From be2d19fe07633a35e5022ccf5152a47d180fd388 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 31 Jul 2020 17:37:36 +0200 Subject: [PATCH] Refactor handling of formula options in `CLI::Parser`. --- Library/Homebrew/brew.rb | 6 +++- Library/Homebrew/cli/args.rb | 38 +++++--------------- Library/Homebrew/cli/parser.rb | 62 ++++++++++++++++++++------------- Library/Homebrew/dev-cmd/irb.rb | 2 +- Library/Homebrew/global.rb | 2 +- Library/Homebrew/help.rb | 2 ++ 6 files changed, 54 insertions(+), 58 deletions(-) diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index d63f2d05f7..ca89004014 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -41,6 +41,7 @@ begin empty_argv = ARGV.empty? help_flag_list = %w[-h --help --usage -?] help_flag = !ENV["HOMEBREW_HELP"].nil? + help_cmd_index = nil cmd = nil ARGV.each_with_index do |arg, i| @@ -49,13 +50,16 @@ begin if arg == "help" && !cmd # Command-style help: `help ` is fine, but ` help` is not. help_flag = true + help_cmd_index = i elsif !cmd && !help_flag_list.include?(arg) cmd = ARGV.delete_at(i) cmd = Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd) end end - Homebrew.args = Homebrew::CLI::Parser.new.parse(ignore_invalid_options: true) + ARGV.delete_at(help_cmd_index) if help_cmd_index + + Homebrew.args = Homebrew::CLI::Parser.new.parse(ARGV.dup.freeze, ignore_invalid_options: true) path = PATH.new(ENV["PATH"]) homebrew_path = PATH.new(ENV["HOMEBREW_PATH"]) diff --git a/Library/Homebrew/cli/args.rb b/Library/Homebrew/cli/args.rb index 21231160bb..1253c71b0c 100644 --- a/Library/Homebrew/cli/args.rb +++ b/Library/Homebrew/cli/args.rb @@ -10,32 +10,21 @@ module Homebrew # undefine tap to allow --tap argument undef tap - def initialize(argv = ARGV.dup.freeze, set_default_args: false) + def initialize super() @processed_options = [] - @options_only = args_options_only(argv) - @flags_only = args_flags_only(argv) + @options_only = [] + @flags_only = [] # Can set these because they will be overwritten by freeze_named_args! # (whereas other values below will only be overwritten if passed). - self[:named_args] = argv.reject { |arg| arg.start_with?("-") } + self[:named_args] = [] self[:remaining] = [] - - # Set values needed before Parser#parse has been run. - return unless set_default_args - - self[:build_from_source?] = argv.include?("--build-from-source") || argv.include?("-s") - self[:build_bottle?] = argv.include?("--build-bottle") - self[:force_bottle?] = argv.include?("--force-bottle") - self[:HEAD?] = argv.include?("--HEAD") - self[:devel?] = argv.include?("--devel") - self[:universal?] = argv.include?("--universal") end def freeze_remaining_args!(remaining_args) - self[:remaining] = remaining_args - self[:remaining].freeze + self[:remaining] = remaining_args.freeze end def freeze_named_args!(named_args) @@ -49,8 +38,7 @@ module Homebrew @kegs = nil @kegs_casks = nil - self[:named_args] = named_args - self[:named_args].freeze + self[:named_args] = named_args.freeze end def freeze_processed_options!(processed_options) @@ -60,8 +48,8 @@ module Homebrew @processed_options += processed_options @processed_options.freeze - @options_only = args_options_only(cli_args) - @flags_only = args_flags_only(cli_args) + @options_only = cli_args.select { |a| a.start_with?("-") }.freeze + @flags_only = cli_args.select { |a| a.start_with?("--") }.freeze end def named @@ -221,16 +209,6 @@ module Homebrew @cli_args.freeze end - def args_options_only(args) - args.select { |arg| arg.start_with?("-") } - .freeze - end - - def args_flags_only(args) - args.select { |arg| arg.start_with?("--") } - .freeze - end - def downcased_unique_named # Only lowercase names, not paths, bottle filenames or URLs named.map do |arg| diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 2e07925421..25d9cd00fc 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -33,11 +33,10 @@ module Homebrew ] end - def initialize(argv = ARGV.dup.freeze, &block) + def initialize(&block) @parser = OptionParser.new - @argv = argv - @args = Homebrew::CLI::Args.new(@argv) + @args = Homebrew::CLI::Args.new @constraints = [] @conflicts = [] @@ -47,6 +46,7 @@ module Homebrew @min_named_args = nil @min_named_type = nil @hide_from_man_page = false + @formula_options = false self.class.global_options.each do |short, long, desc| switch short, long, description: desc @@ -63,7 +63,7 @@ module Homebrew # Disable default handling of `--help` switch. @parser.on_tail("-h", "--help", "Show this message.") do - raise OptionParser::InvalidOption + # Handled in `brew.rb`. end end @@ -190,9 +190,31 @@ module Homebrew [remaining, non_options] end - def parse(argv = @argv, ignore_invalid_options: false) + def parse(argv = ARGV.freeze, ignore_invalid_options: false) raise "Arguments were already parsed!" if @args_parsed + # If we accept formula options, parse once allowing invalid options + # so we can get the remaining list containing formula names. + if @formula_options + remaining, non_options = parse_remaining(argv, ignore_invalid_options: true) + + argv = [*remaining, "--", *non_options] + + formulae(argv).each do |f| + next if f.options.empty? + + f.options.each do |o| + name = o.flag + description = "`#{f.name}`: #{o.description}" + if name.end_with? "=" + flag name, description: description + else + switch name, description: description + end + end + end + end + remaining, non_options = parse_remaining(argv, ignore_invalid_options: ignore_invalid_options) named_args = if ignore_invalid_options @@ -201,8 +223,8 @@ module Homebrew remaining + non_options end - check_constraint_violations - check_named_args(named_args) + check_constraint_violations unless ignore_invalid_options + check_named_args(named_args) unless ignore_invalid_options @args.freeze_named_args!(named_args) @args.freeze_remaining_args!(non_options.empty? ? remaining : [*remaining, "--", non_options]) @args.freeze_processed_options!(@processed_options) @@ -221,21 +243,7 @@ module Homebrew end def formula_options - formulae(@argv).each do |f| - next if f.options.empty? - - f.options.each do |o| - name = o.flag - description = "`#{f.name}`: #{o.description}" - if name.end_with? "=" - flag name, description: description - else - switch name, description: description - end - end - end - rescue FormulaUnavailableError - [] + @formula_options = true end def max_named(count) @@ -385,9 +393,9 @@ module Homebrew end def formulae(argv) - argv, named_argv = split_double_dash(argv) + argv, non_options = split_double_dash(argv) - named_args = argv.reject { |arg| arg.start_with?("-") } + named_argv + named_args = argv.reject { |arg| arg.start_with?("-") } + non_options spec = if argv.include?("--HEAD") :head elsif argv.include?("--devel") @@ -400,7 +408,11 @@ module Homebrew named_args.map do |arg| next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX) - Formulary.factory(arg, spec, flags: @args.flags_only) + begin + Formulary.factory(arg, spec, flags: argv.select { |a| a.start_with?("--") }) + rescue FormulaUnavailableError + nil + end end.compact.uniq(&:name) end end diff --git a/Library/Homebrew/dev-cmd/irb.rb b/Library/Homebrew/dev-cmd/irb.rb index 2f1976e61d..94d31a967a 100644 --- a/Library/Homebrew/dev-cmd/irb.rb +++ b/Library/Homebrew/dev-cmd/irb.rb @@ -34,7 +34,7 @@ module Homebrew end def irb - args = irb_args.parse + args = irb_args.parse(ARGV.dup.freeze) if args.examples? puts "'v8'.f # => instance of the v8 formula" diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index dbdca9a57c..b100822fc0 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -82,7 +82,7 @@ module Homebrew end def args - @args ||= CLI::Args.new(set_default_args: true) + @args ||= CLI::Args.new end def messages diff --git a/Library/Homebrew/help.rb b/Library/Homebrew/help.rb index d868c9c828..53c3e46d56 100644 --- a/Library/Homebrew/help.rb +++ b/Library/Homebrew/help.rb @@ -95,6 +95,8 @@ module Homebrew cmd_parser = CLI::Parser.from_cmd_path(path) return unless cmd_parser + # Try parsing arguments here in order to show formula options in help output. + cmd_parser.parse(Homebrew.args.remaining, ignore_invalid_options: true) cmd_parser.generate_help_text end