Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate command usage text #10342

Merged
merged 8 commits into from Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
102 changes: 94 additions & 8 deletions Library/Homebrew/cli/parser.rb
Expand Up @@ -122,13 +122,18 @@ def initialize(&block)

@args = Homebrew::CLI::Args.new

@command_name = caller_locations(2, 1).first.label.chomp("_args").tr("_", "-")

@constraints = []
@conflicts = []
@switch_sources = {}
@processed_options = []
@non_global_processed_options = []
@named_args_type = nil
@max_named_args = nil
@min_named_args = nil
@description = nil
@usage_banner = nil
@hide_from_man_page = false
@formula_options = false

Expand All @@ -137,6 +142,8 @@ def initialize(&block)
end

instance_eval(&block) if block

generate_banner
end

def switch(*names, description: nil, replacement: nil, env: nil, required_for: nil, depends_on: nil,
Expand All @@ -146,7 +153,7 @@ def switch(*names, description: nil, replacement: nil, env: nil, required_for: n

description = option_to_description(*names) if description.nil?
if replacement.nil?
process_option(*names, description)
process_option(*names, description, type: :switch)
else
description += " (disabled#{"; replaced by #{replacement}" if replacement.present?})"
end
Expand Down Expand Up @@ -176,8 +183,12 @@ def env?(env)
Homebrew::EnvConfig.try(:"#{env}?")
end

def description(text)
@description = text.chomp
end

def usage_banner(text)
@parser.banner = "#{text}\n"
@usage_banner, @description = text.chomp.split("\n\n", 2)
end

def usage_banner_text
Expand All @@ -188,22 +199,22 @@ def usage_banner_text
def comma_array(name, description: nil)
name = name.chomp "="
description = option_to_description(name) if description.nil?
process_option(name, description)
process_option(name, description, type: :comma_array)
@parser.on(name, OptionParser::REQUIRED_ARGUMENT, Array, *wrap_option_desc(description)) do |list|
@args[option_to_name(name)] = list
end
end

def flag(*names, description: nil, replacement: nil, required_for: nil, depends_on: nil)
required = if names.any? { |name| name.end_with? "=" }
OptionParser::REQUIRED_ARGUMENT
required, flag_type = if names.any? { |name| name.end_with? "=" }
[OptionParser::REQUIRED_ARGUMENT, :required_flag]
else
OptionParser::OPTIONAL_ARGUMENT
[OptionParser::OPTIONAL_ARGUMENT, :optional_flag]
end
names.map! { |name| name.chomp "=" }
description = option_to_description(*names) if description.nil?
if replacement.nil?
process_option(*names, description)
process_option(*names, description, type: flag_type)
else
description += " (disabled#{"; replaced by #{replacement}" if replacement.present?})"
end
Expand Down Expand Up @@ -432,6 +443,77 @@ def hide_from_man_page!

private

SYMBOL_TO_USAGE_MAPPING = {
text_or_regex: "<text>|`/`<regex>`/`",
url: "<URL>",
}.freeze

def generate_usage_banner
command_names = ["`#{@command_name}`"]
aliases_to_skip = %w[instal uninstal]
command_names += Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.map do |command_alias, command|
next if aliases_to_skip.include? command_alias

"`#{command_alias}`" if command == @command_name
end.compact.sort

options = if @non_global_processed_options.empty?
""
elsif @non_global_processed_options.count > 2
" [<options>]"
else
required_argument_types = [:required_flag, :comma_array]
@non_global_processed_options.map do |option, type|
next " [<#{option}>`=`]" if required_argument_types.include? type

" [<#{option}>]"
end.join
end

named_args = ""
if @named_args_type.present? && @named_args_type != :none
arg_type = if @named_args_type.is_a? Array
types = @named_args_type.map do |type|
next unless type.is_a? Symbol
next SYMBOL_TO_USAGE_MAPPING[type] if SYMBOL_TO_USAGE_MAPPING.key?(type)

"<#{type}>"
end.compact
types << "<subcommand>" if @named_args_type.any? { |type| type.is_a? String }
types.join("|")
elsif SYMBOL_TO_USAGE_MAPPING.key? @named_args_type
SYMBOL_TO_USAGE_MAPPING[@named_args_type]
else
"<#{@named_args_type}>"
end

named_args = if @min_named_args.blank? && @max_named_args == 1
" [#{arg_type}]"
elsif @min_named_args.blank?
" [#{arg_type} ...]"
elsif @min_named_args == 1 && @max_named_args == 1
" #{arg_type}"
elsif @min_named_args == 1
" #{arg_type} [...]"
else
" #{arg_type} ..."
end
end

"#{command_names.join(", ")}#{options}#{named_args}"
end

def generate_banner
@usage_banner ||= generate_usage_banner

@parser.banner = <<~BANNER
#{@usage_banner}

#{@description}

BANNER
end

def set_switch(*names, value:, from:)
names.each do |name|
@switch_sources[option_to_name(name)] = from
Expand Down Expand Up @@ -537,10 +619,14 @@ def check_named_args(args)
raise exception if exception
end

def process_option(*args)
def process_option(*args, type:)
option, = @parser.make_switch(args)
@processed_options.reject! { |existing| existing.second == option.long.first } if option.long.first.present?
@processed_options << [option.short.first, option.long.first, option.arg, option.desc.first]

return if self.class.global_options.include? [option.short.first, option.long.first, option.desc.first]

@non_global_processed_options << [option.long.first || option.short.first, type]
end

def split_non_options(argv)
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--cache.rb
Expand Up @@ -15,9 +15,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __cache_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--cache` [<options>] [<formula>|<cask>] [<formula>|<cask> ...]

description <<~EOS
Display Homebrew's download cache. See also `HOMEBREW_CACHE`.

If <formula> is provided, display the file or directory used to cache <formula>.
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--caskroom.rb
Expand Up @@ -9,9 +9,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __caskroom_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--caskroom` [<cask>] [<cask> ...]

description <<~EOS
Display Homebrew's Caskroom path.

If <cask> is provided, display the location in the Caskroom where <cask>
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--cellar.rb
Expand Up @@ -8,9 +8,7 @@ module Homebrew

def __cellar_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--cellar` [<formula>] [<formula> ...]

description <<~EOS
Display Homebrew's Cellar path. *Default:* `$(brew --prefix)/Cellar`, or if
that directory doesn't exist, `$(brew --repository)/Cellar`.

Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--env.rb
Expand Up @@ -14,9 +14,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __env_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--env` [<options>] [<formula>] [<formula> ...]

description <<~EOS
Summarise Homebrew's build environment as a plain list.

If the command's output is sent through a pipe and no shell is specified,
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--prefix.rb
Expand Up @@ -11,9 +11,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __prefix_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--prefix` [<formula>] [<formula> ...]

description <<~EOS
Display Homebrew's install path. *Default:*

- macOS Intel: `#{HOMEBREW_DEFAULT_PREFIX}`
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--repository.rb
Expand Up @@ -11,9 +11,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __repository_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--repository`, `--repo` [<user>`/`<repo>] [<user>`/`<repo> ...]

description <<~EOS
Display where Homebrew's `.git` directory is located.

If <user>`/`<repo> are provided, display where tap <user>`/`<repo>'s directory is located.
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/--version.rb
Expand Up @@ -11,9 +11,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def __version_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`--version`

description <<~EOS
Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask
(if tapped) to standard output.
EOS
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/analytics.rb
Expand Up @@ -11,9 +11,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def analytics_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`analytics` [<subcommand>]

description <<~EOS
Control Homebrew's anonymous aggregate user behaviour analytics.
Read more at <https://docs.brew.sh/Analytics>.

Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/autoremove.rb
Expand Up @@ -10,9 +10,7 @@ module Homebrew

def autoremove_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`autoremove` [<options>]

description <<~EOS
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed.
EOS
switch "-n", "--dry-run",
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/cleanup.rb
Expand Up @@ -13,9 +13,7 @@ module Homebrew
def cleanup_args
Homebrew::CLI::Parser.new do
days = Homebrew::EnvConfig::ENVS[:HOMEBREW_CLEANUP_MAX_AGE_DAYS][:default]
usage_banner <<~EOS
`cleanup` [<options>] [<formula>|<cask>] [<formula>|<cask> ...]

description <<~EOS
Remove stale lock files and outdated downloads for all formulae and casks,
and remove old versions of installed formulae. If arguments are specified,
only do this for the given formulae and casks. Removes all downloads more than
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/commands.rb
Expand Up @@ -11,9 +11,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def commands_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`commands` [<options>]

description <<~EOS
Show lists of built-in and external commands.
EOS
switch "-q", "--quiet",
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/completions.rb
Expand Up @@ -12,9 +12,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def completions_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`completions` [<subcommand>]

description <<~EOS
Control whether Homebrew automatically links external tap shell completion files.
Read more at <https://docs.brew.sh/Shell-Completion>.

Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/config.rb
Expand Up @@ -12,9 +12,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def config_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`config`

description <<~EOS
Show Homebrew and system configuration info useful for debugging. If you file
a bug report, you will be required to provide this information.
EOS
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/deps.rb
Expand Up @@ -17,9 +17,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def deps_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`deps` [<options>] [<formula>] [<formula> ...]

description <<~EOS
Show dependencies for <formula>. Additional options specific to <formula>
may be appended to the command. When given multiple formula arguments,
show the intersection of dependencies for each formula.
Expand Down
6 changes: 2 additions & 4 deletions Library/Homebrew/cmd/desc.rb
Expand Up @@ -16,9 +16,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def desc_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`desc` [<options>] <text>|`/`<text>`/`|<formula> [<text>|`/`<text>`/`|<formula> ...]

description <<~EOS
Display <formula>'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.
Expand All @@ -35,7 +33,7 @@ def desc_args

conflicts "--search", "--name", "--description"

named_args :formula, min: 1
named_args [:formula, :text_or_regex], min: 1
end
end

Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/doctor.rb
Expand Up @@ -13,9 +13,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def doctor_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`doctor` [<options>]

description <<~EOS
Check your system for potential problems. Will exit with a non-zero status
if any potential problems are found. Please note that these warnings are just
used to help the Homebrew maintainers with debugging if you file an issue. If
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/fetch.rb
Expand Up @@ -16,9 +16,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def fetch_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`fetch` [<options>] <formula>|<cask> [<formula>|<cask> ...]

description <<~EOS
Download a bottle (if available) or source packages for <formula>e
and binaries for <cask>s. For files, also print SHA-256 checksums.
EOS
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/gist-logs.rb
Expand Up @@ -18,9 +18,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def gist_logs_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`gist-logs` [<options>] <formula>

description <<~EOS
Upload logs for a failed build of <formula> to a new Gist. Presents an
error message if no logs are found.
EOS
Expand Down
4 changes: 1 addition & 3 deletions Library/Homebrew/cmd/home.rb
Expand Up @@ -12,9 +12,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def home_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`home` [<formula>|<cask>] [<formula>|<cask> ...]

description <<~EOS
Open a <formula> or <cask>'s homepage in a browser, or open
Homebrew's own homepage if no argument is provided.
EOS
Expand Down