From 2fdc70c3bf098547ce1c2e85a0ec592ceec3b2b2 Mon Sep 17 00:00:00 2001 From: EricFromCanada Date: Wed, 23 Mar 2022 00:03:11 -0400 Subject: [PATCH] desc, search: also search cask descriptions --- Library/Homebrew/cmd/desc.rb | 38 ++++++++++---- Library/Homebrew/cmd/search.rb | 2 +- Library/Homebrew/cmd/update-report.rb | 4 ++ Library/Homebrew/description_cache_store.rb | 51 ++++++++++++++++++- Library/Homebrew/descriptions.rb | 8 ++- Library/Homebrew/extend/os/mac/search.rb | 14 +++-- Library/Homebrew/formula.rb | 2 +- Library/Homebrew/search.rb | 2 +- Library/Homebrew/searchable.rb | 2 +- Library/Homebrew/tap.rb | 8 +++ .../test/description_cache_store_spec.rb | 30 +++++++++++ Library/Homebrew/test/descriptions_spec.rb | 5 ++ completions/bash/brew | 3 ++ completions/fish/brew.fish | 9 ++-- completions/zsh/_brew | 10 ++-- docs/Manpage.md | 8 ++- manpages/brew.1 | 12 ++++- 17 files changed, 174 insertions(+), 34 deletions(-) diff --git a/Library/Homebrew/cmd/desc.rb b/Library/Homebrew/cmd/desc.rb index 666d60b90f..63c91777b9 100644 --- a/Library/Homebrew/cmd/desc.rb +++ b/Library/Homebrew/cmd/desc.rb @@ -30,10 +30,14 @@ module Homebrew switch "-d", "--description", description: "Search just descriptions for . If is flanked by slashes, "\ "it is interpreted as a regular expression." + switch "--formula", "--formulae", + description: "Treat all named arguments as formulae." + switch "--cask", "--casks", + description: "Treat all named arguments as casks." conflicts "--search", "--name", "--description" - named_args [:formula, :text_or_regex], min: 1 + named_args [:formula, :cask, :text_or_regex], min: 1 end end @@ -48,19 +52,35 @@ module Homebrew :desc end - results = if search_type.nil? + if search_type.blank? desc = {} - args.named.to_formulae.each { |f| desc[f.full_name] = f.desc } - Descriptions.new(desc) + args.named.to_formulae_and_casks.each do |formula_or_cask| + if formula_or_cask.is_a? Formula + desc[formula_or_cask.full_name] = formula_or_cask.desc + else + description = formula_or_cask.desc.presence || Formatter.warning("[no description]") + desc[formula_or_cask.full_name] = "(#{formula_or_cask.name.join(", ")}) #{description}" + end + end + Descriptions.new(desc).print else query = args.named.join(" ") string_or_regex = query_regexp(query) - CacheStoreDatabase.use(:descriptions) do |db| - cache_store = DescriptionCacheStore.new(db) - Descriptions.search(string_or_regex, search_type, cache_store) + unless args.cask? + ohai "Formulae" + CacheStoreDatabase.use(:descriptions) do |db| + cache_store = DescriptionCacheStore.new(db) + Descriptions.search(string_or_regex, search_type, cache_store).print + end + end + unless args.formula? + puts unless args.cask? + ohai "Casks" + CacheStoreDatabase.use(:cask_descriptions) do |db| + cache_store = CaskDescriptionCacheStore.new(db) + Descriptions.search(string_or_regex, search_type, cache_store).print + end end end - - results.print end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index e0166404d0..a43cdfc314 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -43,7 +43,7 @@ module Homebrew description: "Search online and locally for casks." switch "--desc", description: "Search for formulae with a description matching and casks with "\ - "a name matching ." + "a name or description matching ." switch "--pull-request", description: "Search for GitHub pull requests containing ." switch "--open", diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index b3d3623f63..ce81fdca3d 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -197,6 +197,10 @@ module Homebrew DescriptionCacheStore.new(db) .update_from_report!(hub) end + CacheStoreDatabase.use(:cask_descriptions) do |db| + CaskDescriptionCacheStore.new(db) + .update_from_report!(hub) + end if !args.preinstall? && !args.quiet? outdated_formulae = Formula.installed.count(&:outdated?) diff --git a/Library/Homebrew/description_cache_store.rb b/Library/Homebrew/description_cache_store.rb index 4eb2a7b162..9cf1ce97d2 100644 --- a/Library/Homebrew/description_cache_store.rb +++ b/Library/Homebrew/description_cache_store.rb @@ -6,8 +6,8 @@ require "cache_store" require "searchable" # -# {DescriptionCacheStore} provides methods to fetch and mutate linkage-specific data used -# by the `brew linkage` command. +# {DescriptionCacheStore} provides methods to fetch and mutate formula descriptions used +# by the `brew desc` and `brew search` commands. # class DescriptionCacheStore < CacheStore include Searchable @@ -81,6 +81,7 @@ class DescriptionCacheStore < CacheStore formula_names.each(&method(:delete!)) end + alias delete_from_cask_tokens! delete_from_formula_names! private @@ -89,3 +90,49 @@ class DescriptionCacheStore < CacheStore database.select(&block) end end + +# +# {CaskDescriptionCacheStore} provides methods to fetch and mutate cask descriptions used +# by the `brew desc` and `brew search` commands. +# +class CaskDescriptionCacheStore < DescriptionCacheStore + # If the database is empty `update!` it with all known casks. + # + # @return [nil] + def populate_if_empty! + return unless database.empty? + + # TODO: 3.6.0: consider if we want to actually read all contents of all casks or odeprecate. + Cask::Cask.all.each { |c| update!(c.full_name, [c.name.join(", "), c.desc.presence]) } + end + + # Use an update report to update the {CaskDescriptionCacheStore}. + # + # @param report [Report] an update report generated by cmd/update.rb + # @return [nil] + def update_from_report!(report) + return populate_if_empty! if database.empty? + return if report.empty? + + alterations = report.select_formula(:AC) + + report.select_formula(:MC) + + update_from_cask_tokens!(alterations) + delete_from_cask_tokens!(report.select_formula(:DC)) + end + + # Use an array of cask tokens to update the {CaskDescriptionCacheStore}. + # + # @param cask_tokens [Array] the casks to update + # @return [nil] + def update_from_cask_tokens!(cask_tokens) + return populate_if_empty! if database.empty? + + cask_tokens.each do |token| + c = Cask::CaskLoader.load(token) + update!(c.full_name, [c.name.join(", "), c.desc.presence]) + rescue Cask::CaskUnavailableError, *FormulaVersions::IGNORED_EXCEPTIONS + delete!(c.full_name) if c.present? + end + end +end diff --git a/Library/Homebrew/descriptions.rb b/Library/Homebrew/descriptions.rb index 3bda061c57..81d451e2f9 100644 --- a/Library/Homebrew/descriptions.rb +++ b/Library/Homebrew/descriptions.rb @@ -45,7 +45,13 @@ class Descriptions full_name end description = @descriptions[full_name] || blank - puts "#{Tty.bold}#{printed_name}:#{Tty.reset} #{description}" + if description.is_a?(Array) + names = description[0] + description = description[1] || blank + puts "#{Tty.bold}#{printed_name}:#{Tty.reset} (#{names}) #{description}" + else + puts "#{Tty.bold}#{printed_name}:#{Tty.reset} #{description}" + end end end diff --git a/Library/Homebrew/extend/os/mac/search.rb b/Library/Homebrew/extend/os/mac/search.rb index 4fee7f8f37..0b2c070acb 100644 --- a/Library/Homebrew/extend/os/mac/search.rb +++ b/Library/Homebrew/extend/os/mac/search.rb @@ -10,15 +10,13 @@ module Homebrew def search_descriptions(string_or_regex, args) super - puts - return if args.formula? + puts unless args.cask? ohai "Casks" - Cask::Cask.all.extend(Searchable) - .search(string_or_regex, &:name) - .each do |cask| - puts "#{Tty.bold}#{cask.token}:#{Tty.reset} #{cask.name.join(", ")}" + CacheStoreDatabase.use(:cask_descriptions) do |db| + cache_store = CaskDescriptionCacheStore.new(db) + Descriptions.search(string_or_regex, :desc, cache_store).print end end @@ -42,9 +40,9 @@ module Homebrew results.sort.map do |name| cask = Cask::CaskLoader.load(name) if cask.installed? - pretty_installed(cask.token) + pretty_installed(cask.full_name) else - cask.token + cask.full_name end end end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 0a157f48bc..b87aa81bce 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1759,7 +1759,7 @@ class Formula @aliases ||= (core_aliases + tap_aliases.map { |name| name.split("/").last }).uniq.sort end - # an array of all aliases, , which the tap formulae have the fully-qualified name + # an array of all aliases as fully-qualified names # @private def self.alias_full_names @alias_full_names ||= core_aliases + tap_aliases diff --git a/Library/Homebrew/search.rb b/Library/Homebrew/search.rb index ba277b3b34..06c04e7497 100644 --- a/Library/Homebrew/search.rb +++ b/Library/Homebrew/search.rb @@ -89,7 +89,7 @@ module Homebrew .search(string_or_regex) .sort - results |= Formula.fuzzy_search(string_or_regex) + results |= Formula.fuzzy_search(string_or_regex).map { |n| Formulary.factory(n).full_name } results.map do |name| formula, canonical_full_name = begin diff --git a/Library/Homebrew/searchable.rb b/Library/Homebrew/searchable.rb index 634b84b561..255db90dc0 100644 --- a/Library/Homebrew/searchable.rb +++ b/Library/Homebrew/searchable.rb @@ -32,7 +32,7 @@ module Searchable simplified_string = simplify_string(string) select do |*args| args = yield(*args) if block_given? - args = Array(args).compact + args = Array(args).flatten.compact args.any? { |arg| simplify_string(arg).include?(simplified_string) } end end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index cd12df1c35..6c241512ad 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -330,6 +330,10 @@ class Tap DescriptionCacheStore.new(db) .update_from_formula_names!(formula_names) end + CacheStoreDatabase.use(:cask_descriptions) do |db| + CaskDescriptionCacheStore.new(db) + .update_from_cask_tokens!(cask_tokens) + end if official? untapped = self.class.untapped_official_taps @@ -411,6 +415,10 @@ class Tap DescriptionCacheStore.new(db) .delete_from_formula_names!(formula_names) end + CacheStoreDatabase.use(:cask_descriptions) do |db| + CaskDescriptionCacheStore.new(db) + .delete_from_cask_tokens!(cask_tokens) + end Utils::Link.unlink_manpages(path) Utils::Link.unlink_completions(path) path.rmtree diff --git a/Library/Homebrew/test/description_cache_store_spec.rb b/Library/Homebrew/test/description_cache_store_spec.rb index 6b16ffb6c4..c0a01cb87c 100644 --- a/Library/Homebrew/test/description_cache_store_spec.rb +++ b/Library/Homebrew/test/description_cache_store_spec.rb @@ -53,4 +53,34 @@ describe DescriptionCacheStore do cache_store.delete_from_formula_names!([formula_name]) end end + + describe CaskDescriptionCacheStore do + subject(:cache_store) { described_class.new(database) } + + let(:database) { double("database") } + + describe "#update_from_report!" do + let(:report) { double(select_formula: [], empty?: false) } + + it "reads from the report" do + expect(database).to receive(:empty?).at_least(:once).and_return(false) + cache_store.update_from_report!(report) + end + end + + describe "#update_from_cask_tokens!" do + it "sets the cask descriptions" do + c = Cask::Cask.new("cask-names-desc") do + url "url-1" + name "Name 1" + name "Name 2" + desc "description" + end + expect(Cask::CaskLoader).to receive(:load).with("cask-names-desc", any_args).and_return(c) + expect(database).to receive(:empty?).and_return(false) + expect(database).to receive(:set).with(c.full_name, [c.name.join(", "), c.desc.presence]) + cache_store.update_from_cask_tokens!([c.token]) + end + end + end end diff --git a/Library/Homebrew/test/descriptions_spec.rb b/Library/Homebrew/test/descriptions_spec.rb index f36dfe2fef..0ea978c455 100644 --- a/Library/Homebrew/test/descriptions_spec.rb +++ b/Library/Homebrew/test/descriptions_spec.rb @@ -43,4 +43,9 @@ describe Descriptions do EOS ).to_stdout end + + it "can print description for a cask" do + descriptions_hash["homebrew/cask/foo"] = ["Foo", "Cask foo"] + expect { descriptions.print }.to output("foo: (Foo) Cask foo\n").to_stdout + end end diff --git a/completions/bash/brew b/completions/bash/brew index d7e79c0750..9c4681d564 100644 --- a/completions/bash/brew +++ b/completions/bash/brew @@ -741,8 +741,10 @@ _brew_desc() { case "${cur}" in -*) __brewcomp " + --cask --debug --description + --formula --help --name --quiet @@ -754,6 +756,7 @@ _brew_desc() { *) esac __brew_complete_formulae + __brew_complete_casks } _brew_developer() { diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish index 5a3841d5d1..737ca43dfe 100644 --- a/completions/fish/brew.fish +++ b/completions/fish/brew.fish @@ -279,7 +279,7 @@ __fish_brew_complete_arg '-S' -l cask -d 'Search online and locally for casks' __fish_brew_complete_arg '-S' -l closed -d 'Search for only closed GitHub pull requests' __fish_brew_complete_arg '-S' -l debian -d 'Search for text in the given database' __fish_brew_complete_arg '-S' -l debug -d 'Display any debugging information' -__fish_brew_complete_arg '-S' -l desc -d 'Search for formulae with a description matching text and casks with a name matching text' +__fish_brew_complete_arg '-S' -l desc -d 'Search for formulae with a description matching text and casks with a name or description matching text' __fish_brew_complete_arg '-S' -l fedora -d 'Search for text in the given database' __fish_brew_complete_arg '-S' -l fink -d 'Search for text in the given database' __fish_brew_complete_arg '-S' -l formula -d 'Search online and locally for formulae' @@ -578,14 +578,17 @@ __fish_brew_complete_arg 'deps; and not __fish_seen_argument -l formula -l formu __fish_brew_complete_cmd 'desc' 'Display formula\'s name and one-line description' +__fish_brew_complete_arg 'desc' -l cask -d 'Treat all named arguments as casks' __fish_brew_complete_arg 'desc' -l debug -d 'Display any debugging information' __fish_brew_complete_arg 'desc' -l description -d 'Search just descriptions for text. If text is flanked by slashes, it is interpreted as a regular expression' +__fish_brew_complete_arg 'desc' -l formula -d 'Treat all named arguments as formulae' __fish_brew_complete_arg 'desc' -l help -d 'Show this message' __fish_brew_complete_arg 'desc' -l name -d 'Search just names for text. If text is flanked by slashes, it is interpreted as a regular expression' __fish_brew_complete_arg 'desc' -l quiet -d 'Make some output more quiet' __fish_brew_complete_arg 'desc' -l search -d 'Search both names and descriptions for text. If text is flanked by slashes, it is interpreted as a regular expression' __fish_brew_complete_arg 'desc' -l verbose -d 'Make some output more verbose' -__fish_brew_complete_arg 'desc' -a '(__fish_brew_suggest_formulae_all)' +__fish_brew_complete_arg 'desc; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)' +__fish_brew_complete_arg 'desc; and not __fish_seen_argument -l formula -l formulae' -a '(__fish_brew_suggest_casks_all)' __fish_brew_complete_cmd 'developer' 'Control Homebrew\'s developer mode' @@ -1240,7 +1243,7 @@ __fish_brew_complete_arg 'search' -l cask -d 'Search online and locally for cask __fish_brew_complete_arg 'search' -l closed -d 'Search for only closed GitHub pull requests' __fish_brew_complete_arg 'search' -l debian -d 'Search for text in the given database' __fish_brew_complete_arg 'search' -l debug -d 'Display any debugging information' -__fish_brew_complete_arg 'search' -l desc -d 'Search for formulae with a description matching text and casks with a name matching text' +__fish_brew_complete_arg 'search' -l desc -d 'Search for formulae with a description matching text and casks with a name or description matching text' __fish_brew_complete_arg 'search' -l fedora -d 'Search for text in the given database' __fish_brew_complete_arg 'search' -l fink -d 'Search for text in the given database' __fish_brew_complete_arg 'search' -l formula -d 'Search online and locally for formulae' diff --git a/completions/zsh/_brew b/completions/zsh/_brew index c67b5f6f62..f59c9e1a8b 100644 --- a/completions/zsh/_brew +++ b/completions/zsh/_brew @@ -354,7 +354,7 @@ _brew__s() { '(--open)--closed[Search for only closed GitHub pull requests]' \ '(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \ '--debug[Display any debugging information]' \ - '(--pull-request)--desc[Search for formulae with a description matching text and casks with a name matching text]' \ + '(--pull-request)--desc[Search for formulae with a description matching text and casks with a name or description matching text]' \ '(--repology --macports --fink --opensuse --archlinux --debian --ubuntu)--fedora[Search for text in the given database]' \ '(--repology --macports --opensuse --fedora --archlinux --debian --ubuntu)--fink[Search for text in the given database]' \ '--formula[Search online and locally for formulae]' \ @@ -717,7 +717,11 @@ _brew_desc() { '(--name --description)--search[Search both names and descriptions for text. If text is flanked by slashes, it is interpreted as a regular expression]' \ '--verbose[Make some output more verbose]' \ - formula \ - '*::formula:__brew_formulae' + '--formula[Treat all named arguments as formulae]' \ + '*::formula:__brew_formulae' \ + - cask \ + '--cask[Treat all named arguments as casks]' \ + '*::cask:__brew_casks' } # brew developer @@ -1513,7 +1517,7 @@ _brew_search() { '(--open)--closed[Search for only closed GitHub pull requests]' \ '(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \ '--debug[Display any debugging information]' \ - '(--pull-request)--desc[Search for formulae with a description matching text and casks with a name matching text]' \ + '(--pull-request)--desc[Search for formulae with a description matching text and casks with a name or description matching text]' \ '(--repology --macports --fink --opensuse --archlinux --debian --ubuntu)--fedora[Search for text in the given database]' \ '(--repology --macports --opensuse --fedora --archlinux --debian --ubuntu)--fink[Search for text in the given database]' \ '--formula[Search online and locally for formulae]' \ diff --git a/docs/Manpage.md b/docs/Manpage.md index 0649ae53e8..0bb49f19dd 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -177,7 +177,7 @@ show the intersection of dependencies for each formula. * `--cask`: Treat all named arguments as casks. -### `desc` [*`options`*] *`formula`*|*`text`*|`/`*`regex`*`/` [...] +### `desc` [*`options`*] *`formula`*|*`cask`*|*`text`*|`/`*`regex`*`/` [...] Display *`formula`*'s name and one-line description. Formula descriptions are cached; the cache is created on the @@ -189,6 +189,10 @@ first search, making that search slower than subsequent ones. Search just names for *`text`*. If *`text`* is flanked by slashes, it is interpreted as a regular expression. * `-d`, `--description`: Search just descriptions for *`text`*. If *`text`* is flanked by slashes, it is interpreted as a regular expression. +* `--formula`: + Treat all named arguments as formulae. +* `--cask`: + Treat all named arguments as casks. ### `developer` [*`subcommand`*] @@ -563,7 +567,7 @@ The search for *`text`* is extended online to `homebrew/core` and `homebrew/cask * `--cask`: Search online and locally for casks. * `--desc`: - Search for formulae with a description matching *`text`* and casks with a name matching *`text`*. + Search for formulae with a description matching *`text`* and casks with a name or description matching *`text`*. * `--pull-request`: Search for GitHub pull requests containing *`text`*. * `--open`: diff --git a/manpages/brew.1 b/manpages/brew.1 index 6aa144e373..85d8163e75 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -225,7 +225,7 @@ Treat all named arguments as formulae\. \fB\-\-cask\fR Treat all named arguments as casks\. . -.SS "\fBdesc\fR [\fIoptions\fR] \fIformula\fR|\fItext\fR|\fB/\fR\fIregex\fR\fB/\fR [\.\.\.]" +.SS "\fBdesc\fR [\fIoptions\fR] \fIformula\fR|\fIcask\fR|\fItext\fR|\fB/\fR\fIregex\fR\fB/\fR [\.\.\.]" Display \fIformula\fR\'s name and one\-line description\. Formula descriptions are cached; the cache is created on the first search, making that search slower than subsequent ones\. . .TP @@ -240,6 +240,14 @@ Search just names for \fItext\fR\. If \fItext\fR is flanked by slashes, it is in \fB\-d\fR, \fB\-\-description\fR Search just descriptions for \fItext\fR\. If \fItext\fR is flanked by slashes, it is interpreted as a regular expression\. . +.TP +\fB\-\-formula\fR +Treat all named arguments as formulae\. +. +.TP +\fB\-\-cask\fR +Treat all named arguments as casks\. +. .SS "\fBdeveloper\fR [\fIsubcommand\fR]" Control Homebrew\'s developer mode\. When developer mode is enabled, \fBbrew update\fR will update Homebrew to the latest commit on the \fBmaster\fR branch instead of the latest stable version along with some other behaviour changes\. . @@ -778,7 +786,7 @@ Search online and locally for casks\. . .TP \fB\-\-desc\fR -Search for formulae with a description matching \fItext\fR and casks with a name matching \fItext\fR\. +Search for formulae with a description matching \fItext\fR and casks with a name or description matching \fItext\fR\. . .TP \fB\-\-pull\-request\fR