From 2cc70549d8365009f69879fd4ac3ee916d2d8dbe Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Thu, 21 Mar 2024 08:18:52 -0700 Subject: [PATCH] Port Homebrew::DevCmd::Edit --- Library/Homebrew/dev-cmd/edit.rb | 232 ++++++++++----------- Library/Homebrew/test/dev-cmd/edit_spec.rb | 3 +- 2 files changed, 118 insertions(+), 117 deletions(-) diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index b8c5f4bf6a..1892d67502 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -1,133 +1,133 @@ # typed: strict # frozen_string_literal: true +require "abstract_command" require "formula" require "cli/parser" module Homebrew - module_function + module DevCmd + class Edit < AbstractCommand + cmd_args do + description <<~EOS + Open a , or in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, + or open the Homebrew repository for editing if no argument is provided. + EOS - sig { returns(CLI::Parser) } - def edit_args - Homebrew::CLI::Parser.new do - description <<~EOS - Open a , or in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, - or open the Homebrew repository for editing if no argument is provided. - EOS + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." + switch "--print-path", + description: "Print the file path to be edited, without opening an editor." - switch "--formula", "--formulae", - description: "Treat all named arguments as formulae." - switch "--cask", "--casks", - description: "Treat all named arguments as casks." - switch "--print-path", - description: "Print the file path to be edited, without opening an editor." + conflicts "--formula", "--cask" - conflicts "--formula", "--cask" - - named_args [:formula, :cask, :tap], without_api: true - end - end - - sig { params(path: Pathname).returns(T::Boolean) } - def core_formula_path?(path) - path.fnmatch?("**/homebrew-core/Formula/**.rb", File::FNM_DOTMATCH) - end - - sig { params(path: Pathname).returns(T::Boolean) } - def core_cask_path?(path) - path.fnmatch?("**/homebrew-cask/Casks/**.rb", File::FNM_DOTMATCH) - end - - sig { params(path: Pathname).returns(T::Boolean) } - def core_formula_tap?(path) - path == CoreTap.instance.path - end - - sig { params(path: Pathname).returns(T::Boolean) } - def core_cask_tap?(path) - path == CoreCaskTap.instance.path - end - - sig { params(path: Pathname, cask: T::Boolean).returns(T.noreturn) } - def raise_with_message!(path, cask) - name = path.basename(".rb").to_s - - if (tap_match = Regexp.new("#{HOMEBREW_TAP_DIR_REGEX.source}$").match(path.to_s)) - raise TapUnavailableError, CoreTap.instance.name if core_formula_tap?(path) - raise TapUnavailableError, CoreCaskTap.instance.name if core_cask_tap?(path) - - raise TapUnavailableError, "#{tap_match[:user]}/#{tap_match[:repo]}" - elsif cask || core_cask_path?(path) - if !CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(name) - command = "brew tap --force #{CoreCaskTap.instance.name}" - action = "tap #{CoreCaskTap.instance.name}" - else - command = "brew create --cask --set-name #{name} $URL" - action = "create a new cask" - end - elsif core_formula_path?(path) && - !CoreTap.instance.installed? && - Homebrew::API::Formula.all_formulae.key?(name) - command = "brew tap --force #{CoreTap.instance.name}" - action = "tap #{CoreTap.instance.name}" - else - command = "brew create --set-name #{name} $URL" - action = "create a new formula" - end - - raise UsageError, <<~EOS - #{name} doesn't exist on disk. - Run #{Formatter.identifier(command)} to #{action}! - EOS - end - - sig { void } - def edit - args = edit_args.parse - - ENV["COLORTERM"] = ENV.fetch("HOMEBREW_COLORTERM", nil) - - unless (HOMEBREW_REPOSITORY/".git").directory? - odie <<~EOS - Changes will be lost! - The first time you `brew update`, all local changes will be lost; you should - thus `brew update` before you `brew edit`! - EOS - end - - paths = if args.named.empty? - # Sublime requires opting into the project editing path, - # as opposed to VS Code which will infer from the .vscode path - if which_editor(silent: true) == "subl" - ["--project", "#{HOMEBREW_REPOSITORY}/.sublime/homebrew.sublime-project"] - else - # If no formulae are listed, open the project root in an editor. - [HOMEBREW_REPOSITORY] - end - else - expanded_paths = args.named.to_paths - expanded_paths.each do |path| - raise_with_message!(path, args.cask?) unless path.exist? + named_args [:formula, :cask, :tap], without_api: true end - if expanded_paths.any? do |path| - (core_formula_path?(path) || core_cask_path?(path) || core_formula_tap?(path) || core_cask_tap?(path)) && - !Homebrew::EnvConfig.no_install_from_api? && - !Homebrew::EnvConfig.no_env_hints? - end - opoo <<~EOS - `brew install` ignores locally edited casks and formulae if - HOMEBREW_NO_INSTALL_FROM_API is not set. + sig { override.void } + def run + ENV["COLORTERM"] = ENV.fetch("HOMEBREW_COLORTERM", nil) + + unless (HOMEBREW_REPOSITORY/".git").directory? + odie <<~EOS + Changes will be lost! + The first time you `brew update`, all local changes will be lost; you should + thus `brew update` before you `brew edit`! + EOS + end + + paths = if args.named.empty? + # Sublime requires opting into the project editing path, + # as opposed to VS Code which will infer from the .vscode path + if which_editor(silent: true) == "subl" + ["--project", "#{HOMEBREW_REPOSITORY}/.sublime/homebrew.sublime-project"] + else + # If no formulae are listed, open the project root in an editor. + [HOMEBREW_REPOSITORY] + end + else + expanded_paths = args.named.to_paths + expanded_paths.each do |path| + raise_with_message!(path, args.cask?) unless path.exist? + end + + if expanded_paths.any? do |path| + !Homebrew::EnvConfig.no_install_from_api? && + !Homebrew::EnvConfig.no_env_hints? && + (core_formula_path?(path) || core_cask_path?(path) || core_formula_tap?(path) || core_cask_tap?(path)) + end + opoo <<~EOS + `brew install` ignores locally edited casks and formulae if + HOMEBREW_NO_INSTALL_FROM_API is not set. + EOS + end + expanded_paths + end + + if args.print_path? + paths.each { puts _1 } + return + end + + exec_editor(*paths) + end + + private + + sig { params(path: Pathname).returns(T::Boolean) } + def core_formula_path?(path) + path.fnmatch?("**/homebrew-core/Formula/**.rb", File::FNM_DOTMATCH) + end + + sig { params(path: Pathname).returns(T::Boolean) } + def core_cask_path?(path) + path.fnmatch?("**/homebrew-cask/Casks/**.rb", File::FNM_DOTMATCH) + end + + sig { params(path: Pathname).returns(T::Boolean) } + def core_formula_tap?(path) + path == CoreTap.instance.path + end + + sig { params(path: Pathname).returns(T::Boolean) } + def core_cask_tap?(path) + path == CoreCaskTap.instance.path + end + + sig { params(path: Pathname, cask: T::Boolean).returns(T.noreturn) } + def raise_with_message!(path, cask) + name = path.basename(".rb").to_s + + if (tap_match = Regexp.new("#{HOMEBREW_TAP_DIR_REGEX.source}$").match(path.to_s)) + raise TapUnavailableError, CoreTap.instance.name if core_formula_tap?(path) + raise TapUnavailableError, CoreCaskTap.instance.name if core_cask_tap?(path) + + raise TapUnavailableError, "#{tap_match[:user]}/#{tap_match[:repo]}" + elsif cask || core_cask_path?(path) + if !CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(name) + command = "brew tap --force #{CoreCaskTap.instance.name}" + action = "tap #{CoreCaskTap.instance.name}" + else + command = "brew create --cask --set-name #{name} $URL" + action = "create a new cask" + end + elsif core_formula_path?(path) && + !CoreTap.instance.installed? && + Homebrew::API::Formula.all_formulae.key?(name) + command = "brew tap --force #{CoreTap.instance.name}" + action = "tap #{CoreTap.instance.name}" + else + command = "brew create --set-name #{name} $URL" + action = "create a new formula" + end + + raise UsageError, <<~EOS + #{name} doesn't exist on disk. + Run #{Formatter.identifier(command)} to #{action}! EOS end - expanded_paths end - - if args.print_path? - paths.each(&method(:puts)) - return - end - - exec_editor(*paths) end end diff --git a/Library/Homebrew/test/dev-cmd/edit_spec.rb b/Library/Homebrew/test/dev-cmd/edit_spec.rb index 09ccfbdc24..265eb73113 100644 --- a/Library/Homebrew/test/dev-cmd/edit_spec.rb +++ b/Library/Homebrew/test/dev-cmd/edit_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true require "cmd/shared_examples/args_parse" +require "dev-cmd/edit" -RSpec.describe "brew edit" do +RSpec.describe Homebrew::DevCmd::Edit do it_behaves_like "parseable arguments" it "opens a given Formula in an editor", :integration_test do