From a481729ade5f3c2be9980a3b4259bdc61d37e275 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Sat, 10 Dec 2022 12:59:06 -0800 Subject: [PATCH 1/6] Show casks in install not found output - Move `search_names` and `print_missing_formula_help` out of `cmd/search.rb` to `search.rb` - Change to using those functions in `cmd/install.rb` when a formula or cask doesn't exist --- Library/Homebrew/cmd/install.rb | 48 ++++++++-------------------- Library/Homebrew/cmd/search.rb | 53 ------------------------------- Library/Homebrew/search.rb | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 88 deletions(-) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index be9fb54dca..dfd248f264 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -278,48 +278,26 @@ module Homebrew # formula was found, but there's a problem with its implementation). $stderr.puts e.backtrace if Homebrew::EnvConfig.developer? ofail e.message - rescue FormulaOrCaskUnavailableError => e - if e.name == "updog" + rescue FormulaOrCaskUnavailableError, Cask::CaskUnavailableError => e + # formula name or cask token + name = e.try(:name) || e.token + + if name == "updog" ofail "What's updog?" return end opoo e - ohai "Searching for similarly named formulae..." - formulae_search_results = search_formulae(e.name) - case formulae_search_results.length - when 0 - ofail "No similarly named formulae found." - when 1 - puts "This similarly named formula was found:" - puts formulae_search_results - puts "To install it, run:\n brew install #{formulae_search_results.first}" - else - puts "These similarly named formulae were found:" - puts Formatter.columns(formulae_search_results) - puts "To install one of them, run (for example):\n brew install #{formulae_search_results.first}" - end + ohai "Searching for similarly named formulae and casks..." - if (reason = MissingFormula.reason(e.name)) - $stderr.puts reason - return - end + # Don't treat formula/cask name as a regex + query = string_or_regex = name + if search_names(query, string_or_regex, args) + puts <<~EOL - # Do not search taps if the formula name is qualified - return if e.name.include?("/") - - taps_search_results = search_taps(e.name)[:formulae] - case taps_search_results.length - when 0 - ofail "No formulae found in taps." - when 1 - puts "This formula was found in a tap:" - puts taps_search_results - puts "To install it, run:\n brew install #{taps_search_results.first}" - else - puts "These formulae were found in taps:" - puts Formatter.columns(taps_search_results) - puts "To install one of them, run (for example):\n brew install #{taps_search_results.first}" + To install one of them, run: + brew install 'package_name' + EOL end end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index 6fa72a11df..d9d9e1e36b 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -128,57 +128,4 @@ module Homebrew GitHub.print_pull_requests_matching(query, only) end - - def search_names(query, string_or_regex, args) - remote_results = search_taps(query, silent: true) - - local_formulae = search_formulae(string_or_regex) - remote_formulae = remote_results[:formulae] - all_formulae = local_formulae + remote_formulae - - local_casks = search_casks(string_or_regex) - remote_casks = remote_results[:casks] - all_casks = local_casks + remote_casks - - print_formulae = args.formula? - print_casks = args.cask? - print_formulae = print_casks = true if !print_formulae && !print_casks - print_formulae &&= all_formulae.any? - print_casks &&= all_casks.any? - - if print_formulae - if $stdout.tty? - ohai "Formulae", Formatter.columns(all_formulae) - else - puts all_formulae - end - end - puts if print_formulae && print_casks - if print_casks - if $stdout.tty? - ohai "Casks", Formatter.columns(all_casks) - else - puts all_casks - end - end - - count = all_formulae.count + all_casks.count - - print_missing_formula_help(query, count.positive?) if local_casks.exclude?(query) - - odie "No formulae or casks found for #{query.inspect}." if count.zero? - end - - def print_missing_formula_help(query, found_matches) - return unless $stdout.tty? - - reason = MissingFormula.reason(query, silent: true) - return if reason.nil? - - if found_matches - puts - puts "If you meant #{query.inspect} specifically:" - end - puts reason - end end diff --git a/Library/Homebrew/search.rb b/Library/Homebrew/search.rb index aa15e894c5..8e8df0dab5 100644 --- a/Library/Homebrew/search.rb +++ b/Library/Homebrew/search.rb @@ -114,6 +114,61 @@ module Homebrew def search_casks(_string_or_regex) [] end + + def search_names(query, string_or_regex, args) + remote_results = search_taps(query, silent: true) + + local_formulae = search_formulae(string_or_regex) + remote_formulae = remote_results[:formulae] + all_formulae = local_formulae + remote_formulae + + local_casks = search_casks(string_or_regex) + remote_casks = remote_results[:casks] + all_casks = local_casks + remote_casks + + print_formulae = args.formula? + print_casks = args.cask? + print_formulae = print_casks = true if !print_formulae && !print_casks + print_formulae &&= all_formulae.any? + print_casks &&= all_casks.any? + + count = 0 + if print_formulae + if $stdout.tty? + ohai "Formulae", Formatter.columns(all_formulae) + else + puts all_formulae + end + count += all_formulae.count + end + puts if print_formulae && print_casks + if print_casks + if $stdout.tty? + ohai "Casks", Formatter.columns(all_casks) + else + puts all_casks + end + count += all_casks.count + end + + print_missing_formula_help(query, count.positive?) if local_casks.exclude?(query) + + odie "No formulae or casks found for #{query.inspect}." if count.zero? + !count.zero? + end + + def print_missing_formula_help(query, found_matches) + return unless $stdout.tty? + + reason = MissingFormula.reason(query, silent: true) + return if reason.nil? + + if found_matches + puts + puts "If you meant #{query.inspect} specifically:" + end + puts reason + end end end From daa87fa10f1c6fda9c4b48509f72fac19b44f878 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Mon, 12 Dec 2022 19:51:18 -0800 Subject: [PATCH 2/6] Add specific examples to install cmd - provide specific install instructions when a cask/formula doesn't exist and we search for similar ones - print and exit early if a named formula that was removed recently has the same name - exit early if the tap is specified because we don't get good search results --- Library/Homebrew/cmd/install.rb | 41 ++++++++++++++++++++++++---- Library/Homebrew/cmd/search.rb | 47 ++++++++++++++++++++++++++++++++- Library/Homebrew/search.rb | 45 ++----------------------------- 3 files changed, 84 insertions(+), 49 deletions(-) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index dfd248f264..28b2bd7d78 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -288,16 +288,47 @@ module Homebrew end opoo e + + reason = MissingFormula.reason(name, silent: true) + if !args.cask? && reason + $stderr.puts reason + return + end + + return if name.include?("/") + ohai "Searching for similarly named formulae and casks..." # Don't treat formula/cask name as a regex query = string_or_regex = name - if search_names(query, string_or_regex, args) - puts <<~EOL + all_formulae, all_casks = search_names(query, string_or_regex) - To install one of them, run: - brew install 'package_name' - EOL + print_formulae = args.formula? + print_casks = args.cask? + print_formulae = print_casks = true if !print_formulae && !print_casks + print_formulae &&= all_formulae.any? + print_casks &&= all_casks.any? + + if print_formulae + ohai "Formulae", Formatter.columns(all_formulae) + first_formula = all_formulae.first.to_s + puts <<~EOS + + To install #{first_formula}, run: + brew install #{first_formula} + EOS end + puts if print_formulae && print_casks + if print_casks + ohai "Casks", Formatter.columns(all_casks) + first_cask = all_casks.first.to_s + puts <<~EOS + + To install #{first_cask}, run: + brew install --cask #{first_cask} + EOS + end + + odie "No formulae or casks found for #{name}." if !print_formulae && !print_casks end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index d9d9e1e36b..d20d4a9089 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -86,7 +86,8 @@ module Homebrew elsif args.pull_request? search_pull_requests(query, args) else - search_names(query, string_or_regex, args) + formulae, casks = search_names(query, string_or_regex) + print_results(formulae, casks, query, args) end puts "Use `brew desc` to list packages with a short description." if args.verbose? @@ -128,4 +129,48 @@ module Homebrew GitHub.print_pull_requests_matching(query, only) end + + def print_results(all_formulae, all_casks, query, args) + print_formulae = args.formula? + print_casks = args.cask? + print_formulae = print_casks = true if !print_formulae && !print_casks + print_formulae &&= all_formulae.any? + print_casks &&= all_casks.any? + + count = 0 + if all_formulae + if $stdout.tty? + ohai "Formulae", Formatter.columns(all_formulae) + else + puts all_formulae + end + count += all_formulae.count + end + puts if print_formulae && print_casks + if print_casks + if $stdout.tty? + ohai "Casks", Formatter.columns(all_casks) + else + puts all_casks + end + count += all_casks.count + end + + print_missing_formula_help(query, count.positive?) if all_casks.exclude?(query) + + odie "No formulae or casks found for #{query.inspect}." if count.zero? + end + + def print_missing_formula_help(query, found_matches) + return unless $stdout.tty? + + reason = MissingFormula.reason(query, silent: true) + return if reason.nil? + + if found_matches + puts + puts "If you meant #{query.inspect} specifically:" + end + puts reason + end end diff --git a/Library/Homebrew/search.rb b/Library/Homebrew/search.rb index 8e8df0dab5..c67cff9a33 100644 --- a/Library/Homebrew/search.rb +++ b/Library/Homebrew/search.rb @@ -115,7 +115,7 @@ module Homebrew [] end - def search_names(query, string_or_regex, args) + def search_names(query, string_or_regex) remote_results = search_taps(query, silent: true) local_formulae = search_formulae(string_or_regex) @@ -126,48 +126,7 @@ module Homebrew remote_casks = remote_results[:casks] all_casks = local_casks + remote_casks - print_formulae = args.formula? - print_casks = args.cask? - print_formulae = print_casks = true if !print_formulae && !print_casks - print_formulae &&= all_formulae.any? - print_casks &&= all_casks.any? - - count = 0 - if print_formulae - if $stdout.tty? - ohai "Formulae", Formatter.columns(all_formulae) - else - puts all_formulae - end - count += all_formulae.count - end - puts if print_formulae && print_casks - if print_casks - if $stdout.tty? - ohai "Casks", Formatter.columns(all_casks) - else - puts all_casks - end - count += all_casks.count - end - - print_missing_formula_help(query, count.positive?) if local_casks.exclude?(query) - - odie "No formulae or casks found for #{query.inspect}." if count.zero? - !count.zero? - end - - def print_missing_formula_help(query, found_matches) - return unless $stdout.tty? - - reason = MissingFormula.reason(query, silent: true) - return if reason.nil? - - if found_matches - puts - puts "If you meant #{query.inspect} specifically:" - end - puts reason + [all_formulae, all_casks] end end end From 0afc41ceefcf2b69443287f12a45bb7d2c2c35e3 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 13 Dec 2022 20:31:33 -0800 Subject: [PATCH 3/6] Explain edge case in install/cmd Co-authored-by: Mike McQuaid --- Library/Homebrew/cmd/install.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 28b2bd7d78..227bedacd0 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -295,6 +295,8 @@ module Homebrew return end + # We don't seem to get good search results when the tap is specified + # so we might as well return early. return if name.include?("/") ohai "Searching for similarly named formulae and casks..." From cb64bc4df38ca845c412dc70d77debe2ac02cb52 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Tue, 13 Dec 2022 20:38:00 -0800 Subject: [PATCH 4/6] Move pkg type logic into search_name Now the search_name method takes the command line args and only returns package types that line up with those args. That means it will only return casks if casks are valid and same with formulae. --- Library/Homebrew/cmd/install.rb | 17 ++++++----------- Library/Homebrew/cmd/search.rb | 21 +++++++-------------- Library/Homebrew/search.rb | 20 +++++++++++++------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 227bedacd0..8dc6251c46 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -303,15 +303,9 @@ module Homebrew # Don't treat formula/cask name as a regex query = string_or_regex = name - all_formulae, all_casks = search_names(query, string_or_regex) + all_formulae, all_casks = search_names(query, string_or_regex, args) - print_formulae = args.formula? - print_casks = args.cask? - print_formulae = print_casks = true if !print_formulae && !print_casks - print_formulae &&= all_formulae.any? - print_casks &&= all_casks.any? - - if print_formulae + if all_formulae.any? ohai "Formulae", Formatter.columns(all_formulae) first_formula = all_formulae.first.to_s puts <<~EOS @@ -320,8 +314,8 @@ module Homebrew brew install #{first_formula} EOS end - puts if print_formulae && print_casks - if print_casks + puts if all_formulae.any? && all_casks.any? + if all_casks.any? ohai "Casks", Formatter.columns(all_casks) first_cask = all_casks.first.to_s puts <<~EOS @@ -330,7 +324,8 @@ module Homebrew brew install --cask #{first_cask} EOS end + return if all_formulae.any? || all_casks.any? - odie "No formulae or casks found for #{name}." if !print_formulae && !print_casks + odie "No formulae or casks found for #{name}." end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index d20d4a9089..bc0e6d01b1 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -86,8 +86,8 @@ module Homebrew elsif args.pull_request? search_pull_requests(query, args) else - formulae, casks = search_names(query, string_or_regex) - print_results(formulae, casks, query, args) + formulae, casks = search_names(query, string_or_regex, args) + print_results(formulae, casks, query) end puts "Use `brew desc` to list packages with a short description." if args.verbose? @@ -130,30 +130,23 @@ module Homebrew GitHub.print_pull_requests_matching(query, only) end - def print_results(all_formulae, all_casks, query, args) - print_formulae = args.formula? - print_casks = args.cask? - print_formulae = print_casks = true if !print_formulae && !print_casks - print_formulae &&= all_formulae.any? - print_casks &&= all_casks.any? + def print_results(all_formulae, all_casks, query) + count = all_formulae.size + all_casks.size - count = 0 - if all_formulae + if all_formulae.any? if $stdout.tty? ohai "Formulae", Formatter.columns(all_formulae) else puts all_formulae end - count += all_formulae.count end - puts if print_formulae && print_casks - if print_casks + puts if all_formulae.any? && all_casks.any? + if all_casks.any? if $stdout.tty? ohai "Casks", Formatter.columns(all_casks) else puts all_casks end - count += all_casks.count end print_missing_formula_help(query, count.positive?) if all_casks.exclude?(query) diff --git a/Library/Homebrew/search.rb b/Library/Homebrew/search.rb index c67cff9a33..674e956b40 100644 --- a/Library/Homebrew/search.rb +++ b/Library/Homebrew/search.rb @@ -115,16 +115,22 @@ module Homebrew [] end - def search_names(query, string_or_regex) + def search_names(query, string_or_regex, args) + both = !args.formula? && !args.cask? + remote_results = search_taps(query, silent: true) - local_formulae = search_formulae(string_or_regex) - remote_formulae = remote_results[:formulae] - all_formulae = local_formulae + remote_formulae + all_formulae = if args.formula? || both + search_formulae(string_or_regex) + remote_results[:formulae] + else + [] + end - local_casks = search_casks(string_or_regex) - remote_casks = remote_results[:casks] - all_casks = local_casks + remote_casks + all_casks = if args.cask? || both + search_casks(string_or_regex) + remote_results[:casks] + else + [] + end [all_formulae, all_casks] end From 363df2a6483890cc8fbd5191a8720f98e6d7a167 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Tue, 13 Dec 2022 23:38:44 -0800 Subject: [PATCH 5/6] Speed up cask search Add new method to get all cask names without using Cask.all which is slow in this case. --- Library/Homebrew/cask/cask.rb | 10 ++++++++++ Library/Homebrew/extend/os/mac/search.rb | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index 9775e80bd8..915beb71b9 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -38,6 +38,16 @@ module Cask end.compact end + def self.full_names + Tap.flat_map do |tap| + next tap.cask_tokens.blank? + next tap.cask_tokens if tap.user == "Homebrew" + + name = tap.name + tap.cask_tokens.map { |tok| "#{name}/#{tok}" } + end.flatten + end + def tap return super if block_given? # Object#tap diff --git a/Library/Homebrew/extend/os/mac/search.rb b/Library/Homebrew/extend/os/mac/search.rb index cbe7a8adff..6a094d30bd 100644 --- a/Library/Homebrew/extend/os/mac/search.rb +++ b/Library/Homebrew/extend/os/mac/search.rb @@ -37,7 +37,7 @@ module Homebrew results = cask_tokens.extend(Searchable) .search(string_or_regex) - cask_names = Cask::Cask.all.map(&:full_name) + cask_names = Cask::Cask.full_names results += DidYouMean::SpellChecker.new(dictionary: cask_names) .correct(string_or_regex) From 3aac0fef7eaeff3cc50b873c921d80dca0ba6810 Mon Sep 17 00:00:00 2001 From: apainintheneck Date: Wed, 14 Dec 2022 00:26:01 -0800 Subject: [PATCH 6/6] Simplify cask search The cask_tokens and cask_names arrays here were almost identical so we'll just use cask_tokens for both. --- Library/Homebrew/cask/cask.rb | 10 ---------- Library/Homebrew/extend/os/mac/search.rb | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index 915beb71b9..9775e80bd8 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -38,16 +38,6 @@ module Cask end.compact end - def self.full_names - Tap.flat_map do |tap| - next tap.cask_tokens.blank? - next tap.cask_tokens if tap.user == "Homebrew" - - name = tap.name - tap.cask_tokens.map { |tok| "#{name}/#{tok}" } - end.flatten - end - def tap return super if block_given? # Object#tap diff --git a/Library/Homebrew/extend/os/mac/search.rb b/Library/Homebrew/extend/os/mac/search.rb index 6a094d30bd..5901ac74ba 100644 --- a/Library/Homebrew/extend/os/mac/search.rb +++ b/Library/Homebrew/extend/os/mac/search.rb @@ -37,8 +37,7 @@ module Homebrew results = cask_tokens.extend(Searchable) .search(string_or_regex) - cask_names = Cask::Cask.full_names - results += DidYouMean::SpellChecker.new(dictionary: cask_names) + results += DidYouMean::SpellChecker.new(dictionary: cask_tokens) .correct(string_or_regex) results.sort.map do |name|