diff --git a/Library/Homebrew/cli/args.rb b/Library/Homebrew/cli/args.rb index 4032bb9dab7047019696263784d11d067de9e254..a32c50b01c0cbaa44f35f73545907f7ccdf489ba 100644 --- a/Library/Homebrew/cli/args.rb +++ b/Library/Homebrew/cli/args.rb @@ -5,16 +5,23 @@ require "ostruct" module Homebrew module CLI class Args < OpenStruct - attr_accessor :processed_options + attr_reader :processed_options, :args_parsed # undefine tap to allow --tap argument undef tap def initialize(argv:) super @argv = argv + @args_parsed = false @processed_options = [] end + def freeze_processed_options!(processed_options) + @processed_options += processed_options + @processed_options.freeze + @args_parsed = true + end + def option_to_name(option) option.sub(/\A--?/, "") .tr("-", "_") @@ -51,22 +58,36 @@ module Homebrew options_only - CLI::Parser.global_options.values.map(&:first).flatten end - def downcased_unique_named - # Only lowercase names, not paths, bottle filenames or URLs - @downcased_unique_named ||= remaining.map do |arg| - if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg) - arg + def named + remaining + end + + def formulae + require "formula" + @formulae ||= (downcased_unique_named - casks).map do |name| + if name.include?("/") || File.exist?(name) + Formulary.factory(name, spec) else - arg.downcase + Formulary.find_with_priority(name, spec) end - end.uniq + end.uniq(&:name) + end + + def resolved_formulae + require "formula" + @resolved_formulae ||= (downcased_unique_named - casks).map do |name| + Formulary.resolve(name, spec: spec(nil)) + end.uniq(&:name) + end + + def casks + @casks ||= downcased_unique_named.grep HOMEBREW_CASK_TAP_CASK_REGEX end def kegs require "keg" require "formula" require "missing_formula" - @kegs ||= downcased_unique_named.map do |name| raise UsageError if name.empty? @@ -113,6 +134,42 @@ module Homebrew end end end + + private + + def downcased_unique_named + # Only lowercase names, not paths, bottle filenames or URLs + arguments = if args_parsed + remaining + else + cmdline_args.reject { |arg| arg.start_with?("-") } + end + arguments.map do |arg| + if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg) + arg + else + arg.downcase + end + end.uniq + end + + def head + (args_parsed && HEAD?) || cmdline_args.include?("--HEAD") + end + + def devel + (args_parsed && devel?) || cmdline_args.include?("--devel") + end + + def spec(default = :stable) + if head + :head + elsif devel + :devel + else + default + end + end end end end diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 1e767091705582e02543e2ebadb9837e815e4c63..bda488b0c3f248d45ef55de7c7afd29047e87116 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -13,7 +13,7 @@ module Homebrew attr_reader :processed_options, :hide_from_man_page def self.parse(args = ARGV, &block) - new(&block).parse(args) + new(args, &block).parse(args) end def self.global_options @@ -25,9 +25,11 @@ module Homebrew } end - def initialize(&block) + def initialize(args = ARGV, &block) @parser = OptionParser.new @args = Homebrew::CLI::Args.new(argv: ARGV_WITHOUT_MONKEY_PATCHING) + @args[:remaining] = [] + @args[:cmdline_args] = args.dup @constraints = [] @conflicts = [] @switch_sources = {} @@ -138,10 +140,10 @@ module Homebrew end check_constraint_violations @args[:remaining] = remaining_args - @args_parsed = true - @args.processed_options = @processed_options + @args.freeze_processed_options!(@processed_options) Homebrew.args = @args cmdline_args.freeze + @args_parsed = true @parser end @@ -159,7 +161,7 @@ module Homebrew end def formula_options - ARGV.formulae.each do |f| + @args.formulae.each do |f| next if f.options.empty? f.options.each do |o| diff --git a/Library/Homebrew/cmd/--cache.rb b/Library/Homebrew/cmd/--cache.rb index dc253a37ed6996ebd7aa85cbb0b26ed47d564ee9..5e72c776ccfab0e385376a5c6366cfa0a50189ae 100644 --- a/Library/Homebrew/cmd/--cache.rb +++ b/Library/Homebrew/cmd/--cache.rb @@ -29,7 +29,7 @@ module Homebrew if ARGV.named.empty? puts HOMEBREW_CACHE else - ARGV.formulae.each do |f| + Homebrew.args.formulae.each do |f| if Fetch.fetch_bottle?(f) puts f.bottle.cached_download else diff --git a/Library/Homebrew/cmd/--env.rb b/Library/Homebrew/cmd/--env.rb index f1c3e3e94fcfd0a4cc65006d6ecda1f5b37c8621..8da098ea266dae4037f996a43f903abb50f4eb74 100644 --- a/Library/Homebrew/cmd/--env.rb +++ b/Library/Homebrew/cmd/--env.rb @@ -30,7 +30,7 @@ module Homebrew __env_args.parse ENV.activate_extensions! - ENV.deps = ARGV.formulae if superenv? + ENV.deps = Homebrew.args.formulae if superenv? ENV.setup_build_environment ENV.universal_binary if ARGV.build_universal? diff --git a/Library/Homebrew/cmd/cat.rb b/Library/Homebrew/cmd/cat.rb index c7f2f4c790303a2a7eb5bcc583da7cf5167f9fe6..1f2386da673423dce83382b605f4193394b4e64c 100644 --- a/Library/Homebrew/cmd/cat.rb +++ b/Library/Homebrew/cmd/cat.rb @@ -20,7 +20,7 @@ module Homebrew # do not "fix" this to support multiple arguments, the output would be # unparsable, if the user wants to cat multiple formula they can call # brew cat multiple times. - formulae = ARGV.formulae + formulae = Homebrew.args.formulae raise FormulaUnspecifiedError if formulae.empty? raise "`brew cat` doesn't support multiple arguments" if args.remaining.size > 1 diff --git a/Library/Homebrew/cmd/deps.rb b/Library/Homebrew/cmd/deps.rb index fe6484a025eaa8cfe37a8759f021bccf13c53ee7..3031f9d2aa75f0e31766e9b93493177ae08d56cc 100644 --- a/Library/Homebrew/cmd/deps.rb +++ b/Library/Homebrew/cmd/deps.rb @@ -67,16 +67,16 @@ module Homebrew if args.installed? puts_deps_tree Formula.installed.sort, recursive else - raise FormulaUnspecifiedError if args.remaining.empty? + raise FormulaUnspecifiedError if Homebrew.args.remaining.empty? - puts_deps_tree ARGV.formulae, recursive + puts_deps_tree Homebrew.args.formulae, recursive end return elsif args.all? puts_deps Formula.sort, recursive return - elsif !args.remaining.empty? && args.for_each? - puts_deps ARGV.formulae, recursive + elsif !Homebrew.args.remaining.empty? && args.for_each? + puts_deps Homebrew.args.formulae, recursive return end @@ -88,14 +88,14 @@ module Homebrew !args.include_optional? && !args.skip_recommended? - if args.remaining.empty? + if Homebrew.args.remaining.empty? raise FormulaUnspecifiedError unless args.installed? puts_deps Formula.installed.sort, recursive return end - all_deps = deps_for_formulae(ARGV.formulae, recursive, &(args.union? ? :| : :&)) + all_deps = deps_for_formulae(Homebrew.args.formulae, recursive, &(args.union? ? :| : :&)) all_deps = condense_requirements(all_deps) all_deps.select!(&:installed?) if args.installed? all_deps.map!(&method(:dep_display_name)) diff --git a/Library/Homebrew/cmd/desc.rb b/Library/Homebrew/cmd/desc.rb index 3512712047af60707420b8da6e829c1f2bd1cabb..46f50430a60a6988334385497722fc54be2afdfb 100644 --- a/Library/Homebrew/cmd/desc.rb +++ b/Library/Homebrew/cmd/desc.rb @@ -50,7 +50,7 @@ module Homebrew raise FormulaUnspecifiedError if ARGV.named.empty? desc = {} - ARGV.formulae.each { |f| desc[f.full_name] = f.desc } + Homebrew.args.formulae.each { |f| desc[f.full_name] = f.desc } Descriptions.new(desc) else arg = ARGV.named.join(" ") diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index e9159f504d86d98afafe07eb834ab2a8559328a0..ee91163281fe80a1d63c7adc2c26c2242d8420be 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -49,13 +49,13 @@ module Homebrew if args.deps? bucket = [] - ARGV.formulae.each do |f| + Homebrew.args.formulae.each do |f| bucket << f bucket.concat f.recursive_dependencies.map(&:to_formula) end bucket.uniq! else - bucket = ARGV.formulae + bucket = Homebrew.args.formulae end puts "Fetching: #{bucket * ", "}" if bucket.size > 1 diff --git a/Library/Homebrew/cmd/home.rb b/Library/Homebrew/cmd/home.rb index 8746c0feed07a7c5c5934ee99c448207501033e3..98099c090a8e0ee8ee9eda7b9628f952c2bc88a1 100644 --- a/Library/Homebrew/cmd/home.rb +++ b/Library/Homebrew/cmd/home.rb @@ -23,7 +23,7 @@ module Homebrew if args.remaining.empty? exec_browser HOMEBREW_WWW else - exec_browser(*ARGV.formulae.map(&:homepage)) + exec_browser(*Homebrew.args.formulae.map(&:homepage)) end end end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index ad04e74dac8c6c4b8ea6382d41ce09e47d91ebbc..94a82c68b0f4da33436727e91d55803d37a20e87 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -80,7 +80,7 @@ module Homebrew print_json elsif args.github? - exec_browser(*ARGV.formulae.map { |f| github_info(f) }) + exec_browser(*Homebrew.args.formulae.map { |f| github_info(f) }) else print_info end @@ -129,7 +129,7 @@ module Homebrew elsif args.installed? Formula.installed.sort else - ARGV.formulae + Homebrew.args.formulae end json = ff.map(&:to_hash) puts JSON.generate(json) diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 8c61e87d647ab8ad0d4f11f5272cf2c3f12686e3..a3c428c7543a659ae52b5c023ff19b3cab83b70e 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -130,7 +130,7 @@ module Homebrew # developer tools are available, we need to stop them early on FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? - ARGV.formulae.each do |f| + Homebrew.args.formulae.each do |f| # head-only without --HEAD is an error if !Homebrew.args.HEAD? && f.stable.nil? && f.devel.nil? raise <<~EOS diff --git a/Library/Homebrew/cmd/options.rb b/Library/Homebrew/cmd/options.rb index 99948ef6f75bfd771d82890e984491de1bf11aa5..c42f9f06618e7825dd89d182bbadaeb0e33a16b2 100644 --- a/Library/Homebrew/cmd/options.rb +++ b/Library/Homebrew/cmd/options.rb @@ -35,7 +35,7 @@ module Homebrew else raise FormulaUnspecifiedError if args.remaining.empty? - puts_options ARGV.formulae + puts_options Homebrew.args.formulae end end diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index 77c9a0d67f11d920dc702f12916f71d3fe4d4fdb..560329f679e6ae41b0ee9d5720ef845088f64c49 100644 --- a/Library/Homebrew/cmd/style.rb +++ b/Library/Homebrew/cmd/style.rb @@ -45,7 +45,7 @@ module Homebrew elsif ARGV.named.any? { |tap| tap.count("/") == 1 } ARGV.named.map { |tap| Tap.fetch(tap).path } else - ARGV.formulae.map(&:path) + Homebrew.args.formulae.map(&:path) end only_cops = args.only_cops diff --git a/Library/Homebrew/cmd/unpack.rb b/Library/Homebrew/cmd/unpack.rb index 8b49a963bb818dd1814d168c319ef052366e216d..522fc5a891ad579e0bc42620bbe42dded817e376 100644 --- a/Library/Homebrew/cmd/unpack.rb +++ b/Library/Homebrew/cmd/unpack.rb @@ -32,7 +32,7 @@ module Homebrew def unpack unpack_args.parse - formulae = ARGV.formulae + formulae = Homebrew.args.formulae raise FormulaUnspecifiedError if formulae.empty? if dir = args.destdir diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb index ef083c50552d1bff60825a4d1b58dcffe323b398..9f6e235bf27aa0399e7545e06242711c733d12ce 100644 --- a/Library/Homebrew/cmd/uses.rb +++ b/Library/Homebrew/cmd/uses.rb @@ -50,7 +50,7 @@ module Homebrew used_formulae_missing = false used_formulae = begin - ARGV.formulae + Homebrew.args.formulae rescue FormulaUnavailableError => e opoo e used_formulae_missing = true diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index dfd59f3a2385c8fc46d5dcd170807148aa0c5c2c..e984152e78d12e4e455c4edd7cd8a41b5e2fb8da 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -114,7 +114,7 @@ module Homebrew # Use the user's browser, too. ENV["BROWSER"] = ENV["HOMEBREW_BROWSER"] - formula = ARGV.formulae.first + formula = Homebrew.args.formulae.first if formula tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula) diff --git a/Library/Homebrew/dev-cmd/bump-revision.rb b/Library/Homebrew/dev-cmd/bump-revision.rb index af34df763add9dd9e737aac208c9fe4d50d3ceef..ef5f4aee7bab7aec04152a265355b34603489bc6 100644 --- a/Library/Homebrew/dev-cmd/bump-revision.rb +++ b/Library/Homebrew/dev-cmd/bump-revision.rb @@ -32,10 +32,11 @@ module Homebrew # user path, too. ENV["PATH"] = ENV["HOMEBREW_PATH"] - raise FormulaUnspecifiedError if ARGV.formulae.empty? - raise "Multiple formulae given, only one is allowed." if ARGV.formulae.length > 1 + formulae = Homebrew.args.formulae + raise FormulaUnspecifiedError if formulae.empty? + raise "Multiple formulae given, only one is allowed." if formulae.length > 1 - formula = ARGV.formulae.first + formula = formulae.first current_revision = formula.revision if current_revision.zero? diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb index c90c9f98cb9d2a84678530c7fe0f2271f49ed5b1..464d96b5b1cd8213e47c51dda42e21b0e5fc84e7 100644 --- a/Library/Homebrew/dev-cmd/mirror.rb +++ b/Library/Homebrew/dev-cmd/mirror.rb @@ -27,7 +27,7 @@ module Homebrew bintray_key = ENV["HOMEBREW_BINTRAY_KEY"] raise "Missing HOMEBREW_BINTRAY_USER or HOMEBREW_BINTRAY_KEY variables!" if !bintray_user || !bintray_key - ARGV.formulae.each do |f| + Homebrew.args.formulae.each do |f| bintray_package = Utils::Bottles::Bintray.package f.name bintray_repo_url = "https://api.bintray.com/packages/homebrew/mirror" package_url = "#{bintray_repo_url}/#{bintray_package}" diff --git a/Library/Homebrew/test/cli/parser_spec.rb b/Library/Homebrew/test/cli/parser_spec.rb index 8a326d52a772642ffccd9026af78db5b7c75b6d0..3061e484e88dbcfffe7c9667b3f9835958666009 100644 --- a/Library/Homebrew/test/cli/parser_spec.rb +++ b/Library/Homebrew/test/cli/parser_spec.rb @@ -236,6 +236,21 @@ describe Homebrew::CLI::Parser do expect(Homebrew.args.passthrough).to eq %w[--foo --bar=value -s] end + it "#formulae raises an error when a Formula is unavailable" do + parser.parse(["mxcl"]) + expect { Homebrew.args.formulae }.to raise_error FormulaUnavailableError + end + + it "#formulae returns an empty array when there are no Formulae" do + parser.parse([]) + expect(Homebrew.args.formulae).to be_empty + end + + it "#casks returns an empty array when there are no matching casks" do + parser.parse([]) + expect(Homebrew.args.casks).to eq [] + end + context "kegs" do before do keg = HOMEBREW_CELLAR + "mxcl/10.0" @@ -252,5 +267,15 @@ describe Homebrew::CLI::Parser do expect(Homebrew.args.kegs).to be_empty end end + + it "#named returns an array of non-option arguments" do + parser.parse(["foo", "-v", "-s"]) + expect(Homebrew.args.named).to eq ["foo"] + end + + it "#named returns an empty array when there are no named arguments" do + parser.parse([]) + expect(Homebrew.args.named).to be_empty + end end end