desc, search: also search cask descriptions

This commit is contained in:
EricFromCanada 2022-03-23 00:03:11 -04:00
parent 663c0a713a
commit 2fdc70c3bf
No known key found for this signature in database
GPG Key ID: 179D9CDDDB814168
17 changed files with 174 additions and 34 deletions

View File

@ -30,10 +30,14 @@ module Homebrew
switch "-d", "--description", switch "-d", "--description",
description: "Search just descriptions for <text>. If <text> is flanked by slashes, "\ description: "Search just descriptions for <text>. If <text> is flanked by slashes, "\
"it is interpreted as a regular expression." "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" conflicts "--search", "--name", "--description"
named_args [:formula, :text_or_regex], min: 1 named_args [:formula, :cask, :text_or_regex], min: 1
end end
end end
@ -48,19 +52,35 @@ module Homebrew
:desc :desc
end end
results = if search_type.nil? if search_type.blank?
desc = {} desc = {}
args.named.to_formulae.each { |f| desc[f.full_name] = f.desc } args.named.to_formulae_and_casks.each do |formula_or_cask|
Descriptions.new(desc) 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 else
query = args.named.join(" ") query = args.named.join(" ")
string_or_regex = query_regexp(query) string_or_regex = query_regexp(query)
CacheStoreDatabase.use(:descriptions) do |db| unless args.cask?
cache_store = DescriptionCacheStore.new(db) ohai "Formulae"
Descriptions.search(string_or_regex, search_type, cache_store) 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
end end
results.print
end end
end end

View File

@ -43,7 +43,7 @@ module Homebrew
description: "Search online and locally for casks." description: "Search online and locally for casks."
switch "--desc", switch "--desc",
description: "Search for formulae with a description matching <text> and casks with "\ description: "Search for formulae with a description matching <text> and casks with "\
"a name matching <text>." "a name or description matching <text>."
switch "--pull-request", switch "--pull-request",
description: "Search for GitHub pull requests containing <text>." description: "Search for GitHub pull requests containing <text>."
switch "--open", switch "--open",

View File

@ -197,6 +197,10 @@ module Homebrew
DescriptionCacheStore.new(db) DescriptionCacheStore.new(db)
.update_from_report!(hub) .update_from_report!(hub)
end end
CacheStoreDatabase.use(:cask_descriptions) do |db|
CaskDescriptionCacheStore.new(db)
.update_from_report!(hub)
end
if !args.preinstall? && !args.quiet? if !args.preinstall? && !args.quiet?
outdated_formulae = Formula.installed.count(&:outdated?) outdated_formulae = Formula.installed.count(&:outdated?)

View File

@ -6,8 +6,8 @@ require "cache_store"
require "searchable" require "searchable"
# #
# {DescriptionCacheStore} provides methods to fetch and mutate linkage-specific data used # {DescriptionCacheStore} provides methods to fetch and mutate formula descriptions used
# by the `brew linkage` command. # by the `brew desc` and `brew search` commands.
# #
class DescriptionCacheStore < CacheStore class DescriptionCacheStore < CacheStore
include Searchable include Searchable
@ -81,6 +81,7 @@ class DescriptionCacheStore < CacheStore
formula_names.each(&method(:delete!)) formula_names.each(&method(:delete!))
end end
alias delete_from_cask_tokens! delete_from_formula_names!
private private
@ -89,3 +90,49 @@ class DescriptionCacheStore < CacheStore
database.select(&block) database.select(&block)
end end
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

View File

@ -45,7 +45,13 @@ class Descriptions
full_name full_name
end end
description = @descriptions[full_name] || blank 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
end end

View File

@ -10,15 +10,13 @@ module Homebrew
def search_descriptions(string_or_regex, args) def search_descriptions(string_or_regex, args)
super super
puts
return if args.formula? return if args.formula?
puts unless args.cask?
ohai "Casks" ohai "Casks"
Cask::Cask.all.extend(Searchable) CacheStoreDatabase.use(:cask_descriptions) do |db|
.search(string_or_regex, &:name) cache_store = CaskDescriptionCacheStore.new(db)
.each do |cask| Descriptions.search(string_or_regex, :desc, cache_store).print
puts "#{Tty.bold}#{cask.token}:#{Tty.reset} #{cask.name.join(", ")}"
end end
end end
@ -42,9 +40,9 @@ module Homebrew
results.sort.map do |name| results.sort.map do |name|
cask = Cask::CaskLoader.load(name) cask = Cask::CaskLoader.load(name)
if cask.installed? if cask.installed?
pretty_installed(cask.token) pretty_installed(cask.full_name)
else else
cask.token cask.full_name
end end
end end
end end

View File

@ -1759,7 +1759,7 @@ class Formula
@aliases ||= (core_aliases + tap_aliases.map { |name| name.split("/").last }).uniq.sort @aliases ||= (core_aliases + tap_aliases.map { |name| name.split("/").last }).uniq.sort
end 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 # @private
def self.alias_full_names def self.alias_full_names
@alias_full_names ||= core_aliases + tap_aliases @alias_full_names ||= core_aliases + tap_aliases

View File

@ -89,7 +89,7 @@ module Homebrew
.search(string_or_regex) .search(string_or_regex)
.sort .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| results.map do |name|
formula, canonical_full_name = begin formula, canonical_full_name = begin

View File

@ -32,7 +32,7 @@ module Searchable
simplified_string = simplify_string(string) simplified_string = simplify_string(string)
select do |*args| select do |*args|
args = yield(*args) if block_given? args = yield(*args) if block_given?
args = Array(args).compact args = Array(args).flatten.compact
args.any? { |arg| simplify_string(arg).include?(simplified_string) } args.any? { |arg| simplify_string(arg).include?(simplified_string) }
end end
end end

View File

@ -330,6 +330,10 @@ class Tap
DescriptionCacheStore.new(db) DescriptionCacheStore.new(db)
.update_from_formula_names!(formula_names) .update_from_formula_names!(formula_names)
end end
CacheStoreDatabase.use(:cask_descriptions) do |db|
CaskDescriptionCacheStore.new(db)
.update_from_cask_tokens!(cask_tokens)
end
if official? if official?
untapped = self.class.untapped_official_taps untapped = self.class.untapped_official_taps
@ -411,6 +415,10 @@ class Tap
DescriptionCacheStore.new(db) DescriptionCacheStore.new(db)
.delete_from_formula_names!(formula_names) .delete_from_formula_names!(formula_names)
end 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_manpages(path)
Utils::Link.unlink_completions(path) Utils::Link.unlink_completions(path)
path.rmtree path.rmtree

View File

@ -53,4 +53,34 @@ describe DescriptionCacheStore do
cache_store.delete_from_formula_names!([formula_name]) cache_store.delete_from_formula_names!([formula_name])
end end
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 end

View File

@ -43,4 +43,9 @@ describe Descriptions do
EOS EOS
).to_stdout ).to_stdout
end 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 end

View File

@ -741,8 +741,10 @@ _brew_desc() {
case "${cur}" in case "${cur}" in
-*) -*)
__brewcomp " __brewcomp "
--cask
--debug --debug
--description --description
--formula
--help --help
--name --name
--quiet --quiet
@ -754,6 +756,7 @@ _brew_desc() {
*) *)
esac esac
__brew_complete_formulae __brew_complete_formulae
__brew_complete_casks
} }
_brew_developer() { _brew_developer() {

View File

@ -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 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 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 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 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 fink -d 'Search for text in the given database'
__fish_brew_complete_arg '-S' -l formula -d 'Search online and locally for formulae' __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_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 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 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 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 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 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 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' -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' __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 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 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 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 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 fink -d 'Search for text in the given database'
__fish_brew_complete_arg 'search' -l formula -d 'Search online and locally for formulae' __fish_brew_complete_arg 'search' -l formula -d 'Search online and locally for formulae'

View File

@ -354,7 +354,7 @@ _brew__s() {
'(--open)--closed[Search for only closed GitHub pull requests]' \ '(--open)--closed[Search for only closed GitHub pull requests]' \
'(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \ '(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \
'--debug[Display any debugging information]' \ '--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 --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]' \ '(--repology --macports --opensuse --fedora --archlinux --debian --ubuntu)--fink[Search for text in the given database]' \
'--formula[Search online and locally for formulae]' \ '--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]' \ '(--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]' \ '--verbose[Make some output more verbose]' \
- formula \ - 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 # brew developer
@ -1513,7 +1517,7 @@ _brew_search() {
'(--open)--closed[Search for only closed GitHub pull requests]' \ '(--open)--closed[Search for only closed GitHub pull requests]' \
'(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \ '(--repology --macports --fink --opensuse --fedora --archlinux --ubuntu)--debian[Search for text in the given database]' \
'--debug[Display any debugging information]' \ '--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 --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]' \ '(--repology --macports --opensuse --fedora --archlinux --debian --ubuntu)--fink[Search for text in the given database]' \
'--formula[Search online and locally for formulae]' \ '--formula[Search online and locally for formulae]' \

View File

@ -177,7 +177,7 @@ show the intersection of dependencies for each formula.
* `--cask`: * `--cask`:
Treat all named arguments as casks. 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. Display *`formula`*'s name and one-line description.
Formula descriptions are cached; the cache is created on the 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. Search just names for *`text`*. If *`text`* is flanked by slashes, it is interpreted as a regular expression.
* `-d`, `--description`: * `-d`, `--description`:
Search just descriptions for *`text`*. If *`text`* is flanked by slashes, it is interpreted as a regular expression. 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`*] ### `developer` [*`subcommand`*]
@ -563,7 +567,7 @@ The search for *`text`* is extended online to `homebrew/core` and `homebrew/cask
* `--cask`: * `--cask`:
Search online and locally for casks. Search online and locally for casks.
* `--desc`: * `--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`: * `--pull-request`:
Search for GitHub pull requests containing *`text`*. Search for GitHub pull requests containing *`text`*.
* `--open`: * `--open`:

View File

@ -225,7 +225,7 @@ Treat all named arguments as formulae\.
\fB\-\-cask\fR \fB\-\-cask\fR
Treat all named arguments as casks\. 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\. 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 .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 \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\. 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]" .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\. 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 .TP
\fB\-\-desc\fR \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 .TP
\fB\-\-pull\-request\fR \fB\-\-pull\-request\fR