diff --git a/Library/Homebrew/extend/ARGV.rb b/Library/Homebrew/extend/ARGV.rb index 8c3b238a07..b312579b44 100644 --- a/Library/Homebrew/extend/ARGV.rb +++ b/Library/Homebrew/extend/ARGV.rb @@ -42,6 +42,7 @@ module HomebrewArgvExtension def kegs require "keg" require "formula" + require "missing_formula" # TODO: use @instance variable to ||= cache when moving to CLI::Parser downcased_unique_named.map do |name| raise UsageError if name.empty? @@ -50,7 +51,12 @@ module HomebrewArgvExtension dirs = rack.directory? ? rack.subdirs : [] - raise NoSuchKegError, rack.basename if dirs.empty? + if dirs.empty? + if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall")) + $stderr.puts reason + end + raise NoSuchKegError, rack.basename + end linked_keg_ref = HOMEBREW_LINKED_KEGS/rack.basename opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}" diff --git a/Library/Homebrew/extend/os/mac/missing_formula.rb b/Library/Homebrew/extend/os/mac/missing_formula.rb index 58a7906b36..f195895cc2 100644 --- a/Library/Homebrew/extend/os/mac/missing_formula.rb +++ b/Library/Homebrew/extend/os/mac/missing_formula.rb @@ -1,5 +1,10 @@ # frozen_string_literal: true +require "cask/cmd/abstract_command" +require "cask/cmd/info" +require "cask/cask_loader" +require "cask/caskroom" + module Homebrew module MissingFormula class << self @@ -17,14 +22,32 @@ module Homebrew def cask_reason(name, silent: false, show_info: false) return if silent - cask = Cask::CaskLoader.load(name) - reason = +"Found a cask named \"#{name}\" instead.\n" - if show_info - reason << Cask::Cmd::Info.get_info(cask) + suggest_command(name, show_info ? "info" : "install") + end + + def suggest_command(name, command) + suggestion = <<~EOS + Found a cask named "#{name}" instead. Try + brew cask #{command} #{name} + + EOS + case command + when "install" + Cask::CaskLoader.load(name) + when "uninstall" + cask = Cask::Caskroom.casks.find { |installed_cask| installed_cask.to_s == name } + raise Cask::CaskUnavailableError, name if cask.nil? + when "info" + cask = Cask::CaskLoader.load(name) + suggestion = <<~EOS + Found a cask named "#{name}" instead. + + #{Cask::Cmd::Info.get_info(cask)} + EOS else - reason << "Did you mean to type \"brew cask install #{name}\"?\n" + return end - reason.freeze + suggestion rescue Cask::CaskUnavailableError nil end diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb index 27545e7c90..32e5a2a560 100644 --- a/Library/Homebrew/missing_formula.rb +++ b/Library/Homebrew/missing_formula.rb @@ -1,9 +1,6 @@ # frozen_string_literal: true require "formulary" -require "cask/cmd/abstract_command" -require "cask/cmd/info" -require "cask/cask_loader" module Homebrew module MissingFormula @@ -198,6 +195,8 @@ module Homebrew def cask_reason(name, silent: false, show_info: false); end + def suggest_command(name, command); end + require "extend/os/missing_formula" end end diff --git a/Library/Homebrew/test/missing_formula_spec.rb b/Library/Homebrew/test/missing_formula_spec.rb index 30464c7391..40ea55f339 100644 --- a/Library/Homebrew/test/missing_formula_spec.rb +++ b/Library/Homebrew/test/missing_formula_spec.rb @@ -100,14 +100,14 @@ describe Homebrew::MissingFormula do let(:show_info) { false } it { is_expected.to match(/Found a cask named "local-caffeine" instead./) } - it { is_expected.to match(/Did you mean to type "brew cask install local-caffeine"?/) } + it { is_expected.to match(/Try\n brew cask install local-caffeine/) } end context "with a formula name that is a cask and show_info: true" do let(:formula) { "local-caffeine" } let(:show_info) { true } - it { is_expected.to match(/Found a cask named "local-caffeine" instead.\nlocal-caffeine: 1.2.3\n/) } + it { is_expected.to match(/Found a cask named "local-caffeine" instead.\n\nlocal-caffeine: 1.2.3\n/) } end context "with a formula name that is not a cask" do @@ -117,4 +117,40 @@ describe Homebrew::MissingFormula do it { is_expected.to be_nil } end end + + describe "::suggest_command", :cask do + subject { described_class.suggest_command(name, command) } + + context "brew install" do + let(:name) { "local-caffeine" } + let(:command) { "install" } + + it { is_expected.to match(/Found a cask named "local-caffeine" instead./) } + it { is_expected.to match(/Try\n brew cask install local-caffeine/) } + end + + context "brew uninstall" do + let(:name) { "local-caffeine" } + let(:command) { "uninstall" } + + it { is_expected.to be_nil } + + context "with described cask installed" do + before do + allow(Cask::Caskroom).to receive(:casks).and_return(["local-caffeine"]) + end + + it { is_expected.to match(/Found a cask named "local-caffeine" instead./) } + it { is_expected.to match(/Try\n brew cask uninstall local-caffeine/) } + end + end + + context "brew info" do + let(:name) { "local-caffeine" } + let(:command) { "info" } + + it { is_expected.to match(/Found a cask named "local-caffeine" instead./) } + it { is_expected.to match(/local-caffeine: 1.2.3/) } + end + end end