Merge pull request #7509 from MikeMcQuaid/cli_refactoring

Refactor CLI to remove `unless args_parsed`
This commit is contained in:
Mike McQuaid 2020-05-06 11:04:22 +01:00 committed by GitHub
commit be5bbcd78a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 117 deletions

View File

@ -5,56 +5,44 @@ require "ostruct"
module Homebrew
module CLI
class Args < OpenStruct
attr_reader :processed_options, :args_parsed
# undefine tap to allow --tap argument
undef tap
def initialize
super
def initialize(argv = ARGV.dup.freeze, set_default_args: false)
super()
self[:remaining] = []
self[:argv] = ARGV.dup.freeze
@args_parsed = false
@processed_options = []
# 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")
self[:named_args] = argv.reject { |arg| arg.start_with?("-") }
end
def freeze_named_args!(named_args)
self[:named_args] = named_args
self[:named_args].freeze
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("-", "_")
end
def cli_args
return @cli_args if @cli_args
@cli_args = []
processed_options.each do |short, long|
option = long || short
switch = "#{option_to_name(option)}?".to_sym
flag = option_to_name(option).to_sym
if @table[switch] == true || @table[flag] == true
@cli_args << option
elsif @table[flag].instance_of? String
@cli_args << option + "=" + @table[flag]
elsif @table[flag].instance_of? Array
@cli_args << option + "=" + @table[flag].join(",")
end
end
@cli_args
end
def options_only
@options_only ||= cli_args.select { |arg| arg.start_with?("-") }
.freeze
end
def flags_only
@flags_only ||= cli_args.select { |arg| arg.start_with?("--") }
.freeze
end
def passthrough
@ -62,7 +50,7 @@ module Homebrew
end
def named
remaining
named_args || []
end
def no_named?
@ -74,16 +62,17 @@ module Homebrew
def collect_build_args
build_flags = []
build_flags << "--HEAD" if head
build_flags << "--universal" if build_universal
build_flags << "--build-bottle" if build_bottle
build_flags << "--build-from-source" if build_from_source
build_flags << "--HEAD" if HEAD?
build_flags << "--universal" if build_universal?
build_flags << "--build-bottle" if build_bottle?
build_flags << "--build-from-source" if build_from_source?
build_flags
end
def formulae
require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name|
if name.include?("/") || File.exist?(name)
Formulary.factory(name, spec)
@ -91,29 +80,35 @@ module Homebrew
Formulary.find_with_priority(name, spec)
end
end.uniq(&:name)
.freeze
end
def resolved_formulae
require "formula"
@resolved_formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.resolve(name, spec: spec(nil))
end.uniq(&:name)
.freeze
end
def formulae_paths
@formulae_paths ||= (downcased_unique_named - casks).map do |name|
Formulary.path(name)
end.uniq
.freeze
end
def casks
@casks ||= downcased_unique_named.grep HOMEBREW_CASK_TAP_CASK_REGEX
@casks ||= downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
.freeze
end
def kegs
require "keg"
require "formula"
require "missing_formula"
@kegs ||= downcased_unique_named.map do |name|
raise UsageError if name.empty?
@ -158,7 +153,7 @@ module Homebrew
Please delete (with rm -rf!) all but one and then try again.
EOS
end
end
end.freeze
end
def build_stable?
@ -168,39 +163,40 @@ module Homebrew
# Whether a given formula should be built from source during the current
# installation run.
def build_formula_from_source?(f)
return false if !build_from_source && !build_bottle
return false if !build_from_source? && !build_bottle?
formulae.any? { |args_f| args_f.full_name == f.full_name }
end
def build_from_source
return argv.include?("--build-from-source") || argv.include?("-s") unless args_parsed
build_from_source? || s?
end
def build_bottle
return argv.include?("--build-bottle") unless args_parsed
build_bottle?
end
def force_bottle
return argv.include?("--force-bottle") unless args_parsed
force_bottle?
end
private
def option_to_name(option)
option.sub(/\A--?/, "")
.tr("-", "_")
end
def cli_args
return @cli_args if @cli_args
@cli_args = []
@processed_options.each do |short, long|
option = long || short
switch = "#{option_to_name(option)}?".to_sym
flag = option_to_name(option).to_sym
if @table[switch] == true || @table[flag] == true
@cli_args << option
elsif @table[flag].instance_of? String
@cli_args << option + "=" + @table[flag]
elsif @table[flag].instance_of? Array
@cli_args << option + "=" + @table[flag].join(",")
end
end
@cli_args.freeze
end
def downcased_unique_named
# Only lowercase names, not paths, bottle filenames or URLs
arguments = if args_parsed
named
else
argv.reject { |arg| arg.start_with?("-") }
end
arguments.map do |arg|
named.map do |arg|
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
arg
else
@ -209,28 +205,10 @@ module Homebrew
end.uniq
end
def head
return argv.include?("--HEAD") unless args_parsed
HEAD?
end
def devel
return argv.include?("--devel") unless args_parsed
devel?
end
def build_universal
return argv.include?("--universal") unless args_parsed
universal?
end
def spec(default = :stable)
if head
if HEAD?
:head
elsif devel
elsif devel?
:devel
else
default

View File

@ -12,8 +12,8 @@ module Homebrew
class Parser
attr_reader :processed_options, :hide_from_man_page
def self.parse(args = ARGV, allow_no_named_args: false, &block)
new(args, &block).parse(args, allow_no_named_args: allow_no_named_args)
def self.parse(argv = ARGV.dup.freeze, allow_no_named_args: false, &block)
new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
end
def self.from_cmd_path(cmd_path)
@ -37,9 +37,10 @@ module Homebrew
}
end
def initialize(&block)
def initialize(argv = ARGV.dup.freeze, &block)
@parser = OptionParser.new
@args = Homebrew::CLI::Args.new
@argv = argv
@args = Homebrew::CLI::Args.new(@argv)
@constraints = []
@conflicts = []
@ -152,7 +153,7 @@ module Homebrew
@parser.to_s
end
def parse(argv = ARGV, allow_no_named_args: false)
def parse(argv = @argv, allow_no_named_args: false)
raise "Arguments were already parsed!" if @args_parsed
begin
@ -161,12 +162,14 @@ module Homebrew
$stderr.puts generate_help_text
raise e
end
check_constraint_violations
check_named_args(named_args, allow_no_named_args: allow_no_named_args)
@args[:remaining] = named_args
@args.freeze_named_args!(named_args)
parse_formula_options
@args.freeze_processed_options!(@processed_options)
Homebrew.args = @args
argv.freeze
@args_parsed = true
@parser
end
@ -186,21 +189,7 @@ module Homebrew
end
def formula_options
@args.formulae.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
[]
@parse_formula_options = true
end
def max_named(count)
@ -239,6 +228,26 @@ module Homebrew
private
def parse_formula_options
return unless @parse_formula_options
@args.formulae.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
[]
end
def enable_switch(*names, from:)
names.each do |name|
@switch_sources[option_to_name(name)] = from

View File

@ -152,7 +152,7 @@ module Homebrew
end
# --HEAD, fail with no head defined
raise "No head is defined for #{f.full_name}" if args.head? && f.head.nil?
raise "No head is defined for #{f.full_name}" if args.HEAD? && f.head.nil?
# --devel, fail with no devel defined
raise "No devel block is defined for #{f.full_name}" if args.devel? && f.devel.nil?

View File

@ -18,7 +18,8 @@ module Homebrew
module_function
def irb_args
Homebrew::CLI::Parser.new do
# work around IRB modifying ARGV.
Homebrew::CLI::Parser.new(ARGV.dup) do
usage_banner <<~EOS
`irb` [<options>]
@ -33,8 +34,7 @@ module Homebrew
end
def irb
# work around IRB modifying ARGV.
irb_args.parse(ARGV.dup)
irb_args.parse
if args.examples?
puts "'v8'.f # => instance of the v8 formula"

View File

@ -268,7 +268,7 @@ module SharedEnvExtension
# @private
def effective_arch
if Homebrew.args.build_bottle && ARGV.bottle_arch
if Homebrew.args.build_bottle? && ARGV.bottle_arch
ARGV.bottle_arch
else
Hardware.oldest_cpu

View File

@ -5,7 +5,7 @@ module Homebrew
module_function
def fetch_bottle?(f)
return true if Homebrew.args.force_bottle && f.bottle
return true if Homebrew.args.force_bottle? && f.bottle
return false unless f.bottle && f.pour_bottle?
return false if Homebrew.args.build_formula_from_source?(f)
return false unless f.bottle.compatible_cellar?

View File

@ -49,9 +49,9 @@ class FormulaInstaller
@show_header = false
@ignore_deps = false
@only_deps = false
@build_from_source = Homebrew.args.build_from_source
@build_from_source = Homebrew.args.build_from_source?
@build_bottle = false
@force_bottle = Homebrew.args.force_bottle
@force_bottle = Homebrew.args.force_bottle?
@include_test = ARGV.include?("--include-test")
@interactive = false
@git = false

View File

@ -85,7 +85,7 @@ module Homebrew
end
def args
@args ||= CLI::Args.new
@args ||= CLI::Args.new(set_default_args: true)
end
def messages

View File

@ -25,7 +25,7 @@ module Homebrew
fi = FormulaInstaller.new(f)
fi.options = options
fi.build_bottle = Homebrew.args.build_bottle
fi.build_bottle = Homebrew.args.build_bottle?
fi.interactive = Homebrew.args.interactive?
fi.git = Homebrew.args.git?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt

View File

@ -95,7 +95,7 @@ class SoftwareSpec
def bottled?
bottle_specification.tag?(Utils::Bottles.tag) && \
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle)
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle?)
end
def bottle(disable_type = nil, disable_reason = nil, &block)