From aea6d79d21b67fb98687a6d1517f9a21754f76cd Mon Sep 17 00:00:00 2001
From: EricFromCanada <enk3@outlook.com>
Date: Fri, 13 Dec 2019 16:50:54 -0500
Subject: [PATCH] option parser: check for extra named args

---
 Library/Homebrew/cli/parser.rb                | 42 +++++++++++++------
 Library/Homebrew/cmd/--version.rb             |  3 +-
 Library/Homebrew/cmd/analytics.rb             |  3 +-
 Library/Homebrew/cmd/cat.rb                   |  2 +-
 Library/Homebrew/cmd/commands.rb              |  1 +
 Library/Homebrew/cmd/config.rb                |  2 +-
 Library/Homebrew/cmd/diy.rb                   |  1 +
 Library/Homebrew/cmd/gist-logs.rb             |  1 +
 Library/Homebrew/cmd/leaves.rb                |  1 +
 Library/Homebrew/cmd/log.rb                   |  1 +
 Library/Homebrew/cmd/sh.rb                    |  1 +
 Library/Homebrew/cmd/switch.rb                |  1 +
 Library/Homebrew/cmd/tap.rb                   |  1 +
 Library/Homebrew/dev-cmd/bump-formula-pr.rb   |  1 +
 Library/Homebrew/dev-cmd/bump-revision.rb     |  2 +-
 Library/Homebrew/dev-cmd/create.rb            |  1 +
 Library/Homebrew/dev-cmd/extract.rb           |  1 +
 .../Homebrew/dev-cmd/install-bundler-gems.rb  |  1 +
 Library/Homebrew/dev-cmd/man.rb               |  3 +-
 Library/Homebrew/dev-cmd/release-notes.rb     |  1 +
 Library/Homebrew/dev-cmd/tap-new.rb           |  1 +
 Library/Homebrew/dev-cmd/tests.rb             |  1 +
 Library/Homebrew/dev-cmd/update-test.rb       |  1 +
 Library/Homebrew/dev-cmd/vendor-gems.rb       |  1 +
 24 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb
index bda488b0c3..e43620a0cf 100644
--- a/Library/Homebrew/cli/parser.rb
+++ b/Library/Homebrew/cli/parser.rb
@@ -34,6 +34,7 @@ module Homebrew
         @conflicts = []
         @switch_sources = {}
         @processed_options = []
+        @max_named_args = nil
         @hide_from_man_page = false
         instance_eval(&block)
         post_initialize
@@ -139,6 +140,7 @@ module Homebrew
           raise e
         end
         check_constraint_violations
+        check_named_args(remaining_args)
         @args[:remaining] = remaining_args
         @args.freeze_processed_options!(@processed_options)
         Homebrew.args = @args
@@ -178,6 +180,10 @@ module Homebrew
         []
       end
 
+      def max_named(count)
+        @max_named_args = count
+      end
+
       def hide_from_man_page!
         @hide_from_man_page = true
       end
@@ -269,6 +275,10 @@ module Homebrew
         check_constraints
       end
 
+      def check_named_args(args)
+        raise NamedArgumentsError, @max_named_args if !@max_named_args.nil? && args.size > @max_named_args
+      end
+
       def process_option(*args)
         option, = @parser.make_switch(args)
         @processed_options << [option.short.first, option.long.first, option.arg, option.desc.first]
@@ -277,14 +287,10 @@ module Homebrew
 
     class OptionConstraintError < RuntimeError
       def initialize(arg1, arg2, missing: false)
-        if !missing
-          message = <<~EOS
-            `#{arg1}` and `#{arg2}` should be passed together.
-          EOS
+        message = if !missing
+          "`#{arg1}` and `#{arg2}` should be passed together."
         else
-          message = <<~EOS
-            `#{arg2}` cannot be passed without `#{arg1}`.
-          EOS
+          "`#{arg2}` cannot be passed without `#{arg1}`."
         end
         super message
       end
@@ -294,17 +300,27 @@ module Homebrew
       def initialize(args)
         args_list = args.map(&Formatter.public_method(:option))
                         .join(" and ")
-        super <<~EOS
-          Options #{args_list} are mutually exclusive.
-        EOS
+        super "Options #{args_list} are mutually exclusive."
       end
     end
 
     class InvalidConstraintError < RuntimeError
       def initialize(arg1, arg2)
-        super <<~EOS
-          `#{arg1}` and `#{arg2}` cannot be mutually exclusive and mutually dependent simultaneously.
-        EOS
+        super "`#{arg1}` and `#{arg2}` cannot be mutually exclusive and mutually dependent simultaneously."
+      end
+    end
+
+    class NamedArgumentsError < UsageError
+      def initialize(maximum)
+        message = case maximum
+        when 0
+          "This command does not take named arguments."
+        when 1
+          "This command does not take multiple named arguments."
+        else
+          "This command does not take more than #{maximum} named arguments."
+        end
+        super message
       end
     end
   end
diff --git a/Library/Homebrew/cmd/--version.rb b/Library/Homebrew/cmd/--version.rb
index 45666abbda..037a8cc752 100644
--- a/Library/Homebrew/cmd/--version.rb
+++ b/Library/Homebrew/cmd/--version.rb
@@ -13,14 +13,13 @@ module Homebrew
         Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask
         (if tapped) to standard output.
       EOS
+      max_named 0
     end
   end
 
   def __version
     __version_args.parse
 
-    odie "This command does not take arguments." if ARGV.any?
-
     puts "Homebrew #{HOMEBREW_VERSION}"
     puts "#{CoreTap.instance.full_name} #{CoreTap.instance.version_string}"
     puts "#{Tap.default_cask_tap.full_name} #{Tap.default_cask_tap.version_string}" if Tap.default_cask_tap.installed?
diff --git a/Library/Homebrew/cmd/analytics.rb b/Library/Homebrew/cmd/analytics.rb
index 99d20650ae..6423caa753 100644
--- a/Library/Homebrew/cmd/analytics.rb
+++ b/Library/Homebrew/cmd/analytics.rb
@@ -19,14 +19,13 @@ module Homebrew
       EOS
       switch :verbose
       switch :debug
+      max_named 1
     end
   end
 
   def analytics
     analytics_args.parse
 
-    raise UsageError if args.remaining.size > 1
-
     case args.remaining.first
     when nil, "state"
       if Utils::Analytics.disabled?
diff --git a/Library/Homebrew/cmd/cat.rb b/Library/Homebrew/cmd/cat.rb
index ba1b06da27..92f492e166 100644
--- a/Library/Homebrew/cmd/cat.rb
+++ b/Library/Homebrew/cmd/cat.rb
@@ -12,6 +12,7 @@ module Homebrew
 
         Display the source of <formula>.
       EOS
+      max_named 1
     end
   end
 
@@ -22,7 +23,6 @@ module Homebrew
     # `brew cat` multiple times.
     formulae = Homebrew.args.formulae
     raise FormulaUnspecifiedError if formulae.empty?
-    raise "`brew cat` doesn't support multiple arguments" if args.remaining.size > 1
 
     cd HOMEBREW_REPOSITORY
     pager = if ENV["HOMEBREW_BAT"].nil?
diff --git a/Library/Homebrew/cmd/commands.rb b/Library/Homebrew/cmd/commands.rb
index c18f254e5b..a4c551ab86 100644
--- a/Library/Homebrew/cmd/commands.rb
+++ b/Library/Homebrew/cmd/commands.rb
@@ -19,6 +19,7 @@ module Homebrew
              description: "Include aliases of internal commands."
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/cmd/config.rb b/Library/Homebrew/cmd/config.rb
index 1bbdbdad42..a95ab42f6f 100644
--- a/Library/Homebrew/cmd/config.rb
+++ b/Library/Homebrew/cmd/config.rb
@@ -16,12 +16,12 @@ module Homebrew
       EOS
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
   def config
     config_args.parse
-    raise UsageError unless args.remaining.empty?
 
     SystemConfig.dump_verbose_config
   end
diff --git a/Library/Homebrew/cmd/diy.rb b/Library/Homebrew/cmd/diy.rb
index 42862422d1..51a7ff4c26 100644
--- a/Library/Homebrew/cmd/diy.rb
+++ b/Library/Homebrew/cmd/diy.rb
@@ -21,6 +21,7 @@ module Homebrew
              description: "Explicitly set the <version> of the package being installed."
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb
index cd88d5f4f7..72e867d133 100644
--- a/Library/Homebrew/cmd/gist-logs.rb
+++ b/Library/Homebrew/cmd/gist-logs.rb
@@ -28,6 +28,7 @@ module Homebrew
                           "be accessible with its link."
       switch :verbose
       switch :debug
+      max_named 1
     end
   end
 
diff --git a/Library/Homebrew/cmd/leaves.rb b/Library/Homebrew/cmd/leaves.rb
index 18de100983..be4fcdf559 100644
--- a/Library/Homebrew/cmd/leaves.rb
+++ b/Library/Homebrew/cmd/leaves.rb
@@ -15,6 +15,7 @@ module Homebrew
         List installed formulae that are not dependencies of another installed formula.
       EOS
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb
index 84dab11a10..89b75da874 100644
--- a/Library/Homebrew/cmd/log.rb
+++ b/Library/Homebrew/cmd/log.rb
@@ -22,6 +22,7 @@ module Homebrew
              description: "Print only one line per commit."
       flag   "-1", "--max-count",
              description: "Print only one or a specified number of commits."
+      max_named 1
     end
   end
 
diff --git a/Library/Homebrew/cmd/sh.rb b/Library/Homebrew/cmd/sh.rb
index 25e866b628..00f0860965 100644
--- a/Library/Homebrew/cmd/sh.rb
+++ b/Library/Homebrew/cmd/sh.rb
@@ -22,6 +22,7 @@ module Homebrew
              description: "Use the standard `PATH` instead of superenv's when `std` is passed."
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/cmd/switch.rb b/Library/Homebrew/cmd/switch.rb
index 154ddba4e3..9d458f58b0 100644
--- a/Library/Homebrew/cmd/switch.rb
+++ b/Library/Homebrew/cmd/switch.rb
@@ -16,6 +16,7 @@ module Homebrew
       EOS
       switch :verbose
       switch :debug
+      max_named 2
     end
   end
 
diff --git a/Library/Homebrew/cmd/tap.rb b/Library/Homebrew/cmd/tap.rb
index 09deddb5cf..656dc20768 100644
--- a/Library/Homebrew/cmd/tap.rb
+++ b/Library/Homebrew/cmd/tap.rb
@@ -38,6 +38,7 @@ module Homebrew
       switch "-q", "--quieter",
              description: "Suppress any warnings."
       switch :debug
+      max_named 2
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
index d53c8532b0..2b16fb8c22 100644
--- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb
+++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
@@ -65,6 +65,7 @@ module Homebrew
       switch :debug
       conflicts "--no-audit", "--strict"
       conflicts "--url", "--tag"
+      max_named 1
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/bump-revision.rb b/Library/Homebrew/dev-cmd/bump-revision.rb
index ef5f4aee7b..8c186fe47a 100644
--- a/Library/Homebrew/dev-cmd/bump-revision.rb
+++ b/Library/Homebrew/dev-cmd/bump-revision.rb
@@ -22,6 +22,7 @@ module Homebrew
       switch :quiet
       switch :verbose
       switch :debug
+      max_named 1
     end
   end
 
@@ -34,7 +35,6 @@ module Homebrew
 
     formulae = Homebrew.args.formulae
     raise FormulaUnspecifiedError if formulae.empty?
-    raise "Multiple formulae given, only one is allowed." if formulae.length > 1
 
     formula = formulae.first
     current_revision = formula.revision
diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb
index 9c56aa8f16..c3e4c660ac 100644
--- a/Library/Homebrew/dev-cmd/create.rb
+++ b/Library/Homebrew/dev-cmd/create.rb
@@ -49,6 +49,7 @@ module Homebrew
       switch :verbose
       switch :debug
       conflicts "--autotools", "--cmake", "--go", "--meson", "--perl", "--python", "--rust"
+      max_named 1
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb
index 3130a8f30b..4a511a8184 100644
--- a/Library/Homebrew/dev-cmd/extract.rb
+++ b/Library/Homebrew/dev-cmd/extract.rb
@@ -91,6 +91,7 @@ module Homebrew
              description: "Extract the specified <version> of <formula> instead of the most recent."
       switch :force
       switch :debug
+      max_named 2
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/install-bundler-gems.rb b/Library/Homebrew/dev-cmd/install-bundler-gems.rb
index 421b942074..66aeb1087d 100644
--- a/Library/Homebrew/dev-cmd/install-bundler-gems.rb
+++ b/Library/Homebrew/dev-cmd/install-bundler-gems.rb
@@ -14,6 +14,7 @@ module Homebrew
         Install Homebrew's Bundler gems.
       EOS
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb
index e453cc2ffb..db541ed9ae 100644
--- a/Library/Homebrew/dev-cmd/man.rb
+++ b/Library/Homebrew/dev-cmd/man.rb
@@ -28,14 +28,13 @@ module Homebrew
                           "comparison without factoring in the date)."
       switch "--link",
              description: "This is now done automatically by `brew update`."
+      max_named 0
     end
   end
 
   def man
     man_args.parse
 
-    raise UsageError unless ARGV.named.empty?
-
     odie "`brew man --link` is now done automatically by `brew update`." if args.link?
 
     regenerate_man_pages
diff --git a/Library/Homebrew/dev-cmd/release-notes.rb b/Library/Homebrew/dev-cmd/release-notes.rb
index 337147d28b..5a806e4906 100644
--- a/Library/Homebrew/dev-cmd/release-notes.rb
+++ b/Library/Homebrew/dev-cmd/release-notes.rb
@@ -16,6 +16,7 @@ module Homebrew
       EOS
       switch "--markdown",
              description: "Print as a Markdown list."
+      max_named 2
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb
index 326830d793..e4e9e268f2 100644
--- a/Library/Homebrew/dev-cmd/tap-new.rb
+++ b/Library/Homebrew/dev-cmd/tap-new.rb
@@ -15,6 +15,7 @@ module Homebrew
       EOS
       switch :verbose
       switch :debug
+      max_named 1
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb
index 96ceaef489..18bff0c88b 100644
--- a/Library/Homebrew/dev-cmd/tests.rb
+++ b/Library/Homebrew/dev-cmd/tests.rb
@@ -29,6 +29,7 @@ module Homebrew
              description: "Randomise tests with the specified <value> instead of a random seed."
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb
index 6327c6d0bf..fdf208dd49 100644
--- a/Library/Homebrew/dev-cmd/update-test.rb
+++ b/Library/Homebrew/dev-cmd/update-test.rb
@@ -23,6 +23,7 @@ module Homebrew
              description: "Use the commit at the specified <date> as the start commit."
       switch :verbose
       switch :debug
+      max_named 0
     end
   end
 
diff --git a/Library/Homebrew/dev-cmd/vendor-gems.rb b/Library/Homebrew/dev-cmd/vendor-gems.rb
index b5f720af92..428223e38a 100644
--- a/Library/Homebrew/dev-cmd/vendor-gems.rb
+++ b/Library/Homebrew/dev-cmd/vendor-gems.rb
@@ -14,6 +14,7 @@ module Homebrew
         Install and commit Homebrew's vendored gems.
       EOS
       switch :debug
+      max_named 0
     end
   end
 
-- 
GitLab