Pass args in SoftwareSpec instead of using global args.

This commit is contained in:
Markus Reiter 2020-07-26 07:24:14 +02:00
parent f8934c0255
commit 24eff8f81a
12 changed files with 84 additions and 55 deletions

View File

@ -86,7 +86,7 @@ module Homebrew
require "formula" require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name| @formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.factory(name, spec) Formulary.factory(name, spec, force_bottle: force_bottle?, flags: flags_only)
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
@ -94,7 +94,7 @@ module Homebrew
require "formula" require "formula"
@resolved_formulae ||= (downcased_unique_named - casks).map do |name| @resolved_formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.resolve(name, spec: spec(nil)) Formulary.resolve(name, spec: spec(nil), force_bottle: force_bottle?, flags: flags_only)
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
@ -104,7 +104,8 @@ module Homebrew
casks = [] casks = []
downcased_unique_named.each do |name| downcased_unique_named.each do |name|
resolved_formulae << Formulary.resolve(name, spec: spec(nil)) resolved_formulae << Formulary.resolve(name, spec: spec(nil),
force_bottle: force_bottle?, flags: flags_only)
rescue FormulaUnavailableError rescue FormulaUnavailableError
begin begin
casks << Cask::CaskLoader.load(name) casks << Cask::CaskLoader.load(name)

View File

@ -360,7 +360,7 @@ module Homebrew
named_args.map do |arg| named_args.map do |arg|
next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX) next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX)
Formulary.factory(arg, spec) Formulary.factory(arg, spec, flags: @args.flags_only)
end.compact.uniq(&:name) end.compact.uniq(&:name)
end end
end end

View File

@ -33,13 +33,13 @@ module Homebrew
end end
def __cache def __cache
__cache_args.parse args = __cache_args.parse
if args.no_named? if args.no_named?
puts HOMEBREW_CACHE puts HOMEBREW_CACHE
elsif args.formula? elsif args.formula?
args.named.each do |name| args.named.each do |name|
print_formula_cache name print_formula_cache name, args: args
end end
elsif args.cask? elsif args.cask?
args.named.each do |name| args.named.each do |name|
@ -47,7 +47,7 @@ module Homebrew
end end
else else
args.named.each do |name| args.named.each do |name|
print_formula_cache name print_formula_cache name, args: args
rescue FormulaUnavailableError rescue FormulaUnavailableError
begin begin
print_cask_cache name print_cask_cache name
@ -58,8 +58,8 @@ module Homebrew
end end
end end
def print_formula_cache(name) def print_formula_cache(name, args:)
formula = Formulary.factory name formula = Formulary.factory(name, force_bottle: args.force_bottle?, flags: args.flags_only)
if fetch_bottle?(formula) if fetch_bottle?(formula)
puts formula.bottle.cached_download puts formula.bottle.cached_download
else else

View File

@ -101,6 +101,10 @@ class Formula
# @private # @private
attr_reader :tap attr_reader :tap
# Whether or not to force the use of a bottle.
# @private
attr_reader :force_bottle
# The stable (and default) {SoftwareSpec} for this {Formula} # The stable (and default) {SoftwareSpec} for this {Formula}
# This contains all the attributes (e.g. URL, checksum) that apply to the # This contains all the attributes (e.g. URL, checksum) that apply to the
# stable version of this formula. # stable version of this formula.
@ -181,7 +185,7 @@ class Formula
alias follow_installed_alias? follow_installed_alias alias follow_installed_alias? follow_installed_alias
# @private # @private
def initialize(name, path, spec, alias_path: nil) def initialize(name, path, spec, alias_path: nil, force_bottle: false)
@name = name @name = name
@path = path @path = path
@alias_path = alias_path @alias_path = alias_path
@ -189,6 +193,8 @@ class Formula
@revision = self.class.revision || 0 @revision = self.class.revision || 0
@version_scheme = self.class.version_scheme || 0 @version_scheme = self.class.version_scheme || 0
@force_bottle = force_bottle
@tap = if path == Formulary.core_path(name) @tap = if path == Formulary.core_path(name)
CoreTap.instance CoreTap.instance
else else
@ -273,7 +279,7 @@ class Formula
# and is specified to this instance. # and is specified to this instance.
def installed_alias_path def installed_alias_path
path = build.source["path"] if build.is_a?(Tab) path = build.source["path"] if build.is_a?(Tab)
return unless path&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}) return unless path&.to_s&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases})
return unless File.symlink?(path) return unless File.symlink?(path)
path path
@ -2372,6 +2378,15 @@ class Formula
stable.build stable.build
end end
# @private
def build_flags
mod_name = to_s.split("::")[0..-2].join("::")
return [] if mod_name.empty?
mod = const_get(mod_name)
mod.const_get(:BUILD_FLAGS)
end
# @!attribute [w] stable # @!attribute [w] stable
# Allows adding {.depends_on} and {Patch}es just to the {.stable} {SoftwareSpec}. # Allows adding {.depends_on} and {Patch}es just to the {.stable} {SoftwareSpec}.
# This is required instead of using a conditional. # This is required instead of using a conditional.
@ -2385,7 +2400,7 @@ class Formula
# depends_on "libffi" # depends_on "libffi"
# end</pre> # end</pre>
def stable(&block) def stable(&block)
@stable ||= SoftwareSpec.new @stable ||= SoftwareSpec.new(flags: build_flags)
return @stable unless block_given? return @stable unless block_given?
@stable.instance_eval(&block) @stable.instance_eval(&block)
@ -2405,7 +2420,7 @@ class Formula
# end</pre> # end</pre>
# @private # @private
def devel(&block) def devel(&block)
@devel ||= SoftwareSpec.new @devel ||= SoftwareSpec.new(flags: build_flags)
return @devel unless block_given? return @devel unless block_given?
odeprecated "'devel' blocks in formulae", "'head' blocks or @-versioned formulae" odeprecated "'devel' blocks in formulae", "'head' blocks or @-versioned formulae"
@ -2425,7 +2440,7 @@ class Formula
# or (if autodetect fails): # or (if autodetect fails):
# <pre>head "https://hg.is.awesome.but.git.has.won.example.com/", :using => :hg</pre> # <pre>head "https://hg.is.awesome.but.git.has.won.example.com/", :using => :hg</pre>
def head(val = nil, specs = {}, &block) def head(val = nil, specs = {}, &block)
@head ||= HeadSoftwareSpec.new @head ||= HeadSoftwareSpec.new(flags: build_flags)
if block_given? if block_given?
@head.instance_eval(&block) @head.instance_eval(&block)
elsif val elsif val

View File

@ -27,12 +27,14 @@ module Formulary
cache.fetch(path) cache.fetch(path)
end end
def self.load_formula(name, path, contents, namespace) def self.load_formula(name, path, contents, namespace, flags:)
raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" if Homebrew::EnvConfig.disable_load_formula? raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" if Homebrew::EnvConfig.disable_load_formula?
mod = Module.new mod = Module.new
const_set(namespace, mod) const_set(namespace, mod)
begin begin
mod.const_set(:BUILD_FLAGS, flags)
mod.module_eval(contents, path) mod.module_eval(contents, path)
rescue NameError, ArgumentError, ScriptError => e rescue NameError, ArgumentError, ScriptError => e
$stderr.puts e.backtrace if Homebrew::EnvConfig.developer? $stderr.puts e.backtrace if Homebrew::EnvConfig.developer?
@ -51,16 +53,16 @@ module Formulary
end end
end end
def self.load_formula_from_path(name, path) def self.load_formula_from_path(name, path, flags:)
contents = path.open("r") { |f| ensure_utf8_encoding(f).read } contents = path.open("r") { |f| ensure_utf8_encoding(f).read }
namespace = "FormulaNamespace#{Digest::MD5.hexdigest(path.to_s)}" namespace = "FormulaNamespace#{Digest::MD5.hexdigest(path.to_s)}"
klass = load_formula(name, path, contents, namespace) klass = load_formula(name, path, contents, namespace, flags: flags)
cache[path] = klass cache[path] = klass
end end
def self.resolve(name, spec: nil) def self.resolve(name, spec: nil, force_bottle: false, flags: [])
if name.include?("/") || File.exist?(name) if name.include?("/") || File.exist?(name)
f = factory(name, *spec) f = factory(name, *spec, force_bottle: force_bottle, flags: flags)
if f.any_version_installed? if f.any_version_installed?
tab = Tab.for_formula(f) tab = Tab.for_formula(f)
resolved_spec = spec || tab.spec resolved_spec = spec || tab.spec
@ -73,8 +75,8 @@ module Formulary
end end
else else
rack = to_rack(name) rack = to_rack(name)
alias_path = factory(name).alias_path alias_path = factory(name, force_bottle: force_bottle, flags: flags).alias_path
f = from_rack(rack, *spec, alias_path: alias_path) f = from_rack(rack, *spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags)
end end
# If this formula was installed with an alias that has since changed, # If this formula was installed with an alias that has since changed,
@ -121,22 +123,23 @@ module Formulary
# #
# `alias_path` can be overridden here in case an alias was used to refer to # `alias_path` can be overridden here in case an alias was used to refer to
# a formula that was loaded in another way. # a formula that was loaded in another way.
def get_formula(spec, alias_path: nil) def get_formula(spec, alias_path: nil, force_bottle: false, flags: [])
klass.new(name, path, spec, alias_path: alias_path || self.alias_path) klass(flags: flags)
.new(name, path, spec, alias_path: alias_path || self.alias_path, force_bottle: force_bottle)
end end
def klass def klass(flags:)
load_file unless Formulary.formula_class_defined?(path) load_file(flags: flags) unless Formulary.formula_class_defined?(path)
Formulary.formula_class_get(path) Formulary.formula_class_get(path)
end end
private private
def load_file def load_file(flags:)
$stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug? $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug?
raise FormulaUnavailableError, name unless path.file? raise FormulaUnavailableError, name unless path.file?
Formulary.load_formula_from_path(name, path) Formulary.load_formula_from_path(name, path, flags: flags)
end end
end end
@ -161,10 +164,10 @@ module Formulary
super name, Formulary.path(full_name) super name, Formulary.path(full_name)
end end
def get_formula(spec, **) def get_formula(spec, force_bottle: false, flags: [], **)
contents = Utils::Bottles.formula_contents @bottle_filename, name: name contents = Utils::Bottles.formula_contents @bottle_filename, name: name
formula = begin formula = begin
Formulary.from_contents name, @bottle_filename, contents, spec Formulary.from_contents(name, @bottle_filename, contents, spec, force_bottle: force_bottle, flags: flags)
rescue FormulaUnreadableError => e rescue FormulaUnreadableError => e
opoo <<~EOS opoo <<~EOS
Unreadable formula in #{@bottle_filename}: Unreadable formula in #{@bottle_filename}:
@ -205,7 +208,7 @@ module Formulary
super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri.path) super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri.path)
end end
def load_file def load_file(flags:)
if url =~ %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(/Formula)?/([\w+-.@]+).rb} if url =~ %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(/Formula)?/([\w+-.@]+).rb}
formula_name = Regexp.last_match(2) formula_name = Regexp.last_match(2)
odeprecated "Installation of #{formula_name} from a GitHub commit URL", odeprecated "Installation of #{formula_name} from a GitHub commit URL",
@ -270,7 +273,7 @@ module Formulary
[name, path] [name, path]
end end
def get_formula(spec, alias_path: nil) def get_formula(spec, alias_path: nil, force_bottle: false, flags: [])
super super
rescue FormulaUnreadableError => e rescue FormulaUnreadableError => e
raise TapFormulaUnreadableError.new(tap, name, e.formula_error), "", e.backtrace raise TapFormulaUnreadableError.new(tap, name, e.formula_error), "", e.backtrace
@ -280,7 +283,7 @@ module Formulary
raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace
end end
def load_file def load_file(flags:)
super super
rescue MethodDeprecatedError => e rescue MethodDeprecatedError => e
e.issues_url = tap.issues_url || tap.to_s e.issues_url = tap.issues_url || tap.to_s
@ -308,10 +311,10 @@ module Formulary
super name, path super name, path
end end
def klass def klass(flags:)
$stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug? $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug?
namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents)}" namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents.to_s)}"
Formulary.load_formula(name, path, contents, namespace) Formulary.load_formula(name, path, contents, namespace, flags: flags)
end end
end end
@ -322,7 +325,7 @@ module Formulary
# * a formula pathname # * a formula pathname
# * a formula URL # * a formula URL
# * a local bottle reference # * a local bottle reference
def self.factory(ref, spec = :stable, alias_path: nil, from: nil) def self.factory(ref, spec = :stable, alias_path: nil, from: nil, force_bottle: false, flags: [])
raise ArgumentError, "Formulae must have a ref!" unless ref raise ArgumentError, "Formulae must have a ref!" unless ref
cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}" cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}"
@ -331,7 +334,8 @@ module Formulary
return cache[:formulary_factory][cache_key] return cache[:formulary_factory][cache_key]
end end
formula = loader_for(ref, from: from).get_formula(spec, alias_path: alias_path) formula = loader_for(ref, from: from).get_formula(spec, alias_path: alias_path,
force_bottle: force_bottle, flags: flags)
if factory_cached? if factory_cached?
cache[:formulary_factory] ||= {} cache[:formulary_factory] ||= {}
cache[:formulary_factory][cache_key] ||= formula cache[:formulary_factory][cache_key] ||= formula
@ -345,14 +349,15 @@ module Formulary
# The :alias_path option will be used if the formula is found not to be # The :alias_path option will be used if the formula is found not to be
# installed, and discarded if it is installed because the alias_path used # installed, and discarded if it is installed because the alias_path used
# to install the formula will be set instead. # to install the formula will be set instead.
def self.from_rack(rack, spec = nil, alias_path: nil) def self.from_rack(rack, spec = nil, alias_path: nil, force_bottle: false, flags: [])
kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : [] kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
keg = kegs.find(&:linked?) || kegs.find(&:optlinked?) || kegs.max_by(&:version) keg = kegs.find(&:linked?) || kegs.find(&:optlinked?) || kegs.max_by(&:version)
if keg if keg
from_keg(keg, spec, alias_path: alias_path) from_keg(keg, spec, alias_path: alias_path)
else else
factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack) factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack,
force_bottle: force_bottle, flags: flags)
end end
end end
@ -365,19 +370,22 @@ module Formulary
# Return a Formula instance for the given keg. # Return a Formula instance for the given keg.
# It will auto resolve formula's spec when requested spec is nil # It will auto resolve formula's spec when requested spec is nil
def self.from_keg(keg, spec = nil, alias_path: nil) def self.from_keg(keg, spec = nil, alias_path: nil, force_bottle: false, flags: [])
tab = Tab.for_keg(keg) tab = Tab.for_keg(keg)
tap = tab.tap tap = tab.tap
spec ||= tab.spec spec ||= tab.spec
f = if tap.nil? f = if tap.nil?
factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg) factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg,
force_bottle: force_bottle, flags: flags)
else else
begin begin
factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg) factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg,
force_bottle: force_bottle, flags: flags)
rescue FormulaUnavailableError rescue FormulaUnavailableError
# formula may be migrated to different tap. Try to search in core and all taps. # formula may be migrated to different tap. Try to search in core and all taps.
factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg) factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg,
force_bottle: force_bottle, flags: flags)
end end
end end
f.build = tab f.build = tab
@ -387,8 +395,9 @@ module Formulary
end end
# Return a Formula instance directly from contents # Return a Formula instance directly from contents
def self.from_contents(name, path, contents, spec = :stable) def self.from_contents(name, path, contents, spec = :stable, alias_path: nil, force_bottle: false, flags: [])
FormulaContentsLoader.new(name, path, contents).get_formula(spec) FormulaContentsLoader.new(name, path, contents)
.get_formula(spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags)
end end
def self.to_rack(ref) def self.to_rack(ref)

View File

@ -28,14 +28,14 @@ class SoftwareSpec
:cached_download, :clear_cache, :checksum, :mirrors, :specs, :using, :version, :mirror, :cached_download, :clear_cache, :checksum, :mirrors, :specs, :using, :version, :mirror,
:downloader, *Checksum::TYPES :downloader, *Checksum::TYPES
def initialize def initialize(flags: [])
@resource = Resource.new @resource = Resource.new
@resources = {} @resources = {}
@dependency_collector = DependencyCollector.new @dependency_collector = DependencyCollector.new
@bottle_specification = BottleSpecification.new @bottle_specification = BottleSpecification.new
@patches = [] @patches = []
@options = Options.new @options = Options.new
@flags = Homebrew.args.flags_only @flags = flags
@deprecated_flags = [] @deprecated_flags = []
@deprecated_options = [] @deprecated_options = []
@build = BuildOptions.new(Options.create(@flags), options) @build = BuildOptions.new(Options.create(@flags), options)
@ -87,7 +87,7 @@ class SoftwareSpec
def bottled? def bottled?
bottle_specification.tag?(Utils::Bottles.tag) && \ bottle_specification.tag?(Utils::Bottles.tag) && \
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle?) (bottle_specification.compatible_cellar? || owner.force_bottle)
end end
def bottle(disable_type = nil, disable_reason = nil, &block) def bottle(disable_type = nil, disable_reason = nil, &block)
@ -234,7 +234,7 @@ class SoftwareSpec
end end
class HeadSoftwareSpec < SoftwareSpec class HeadSoftwareSpec < SoftwareSpec
def initialize def initialize(flags: [])
super super
@resource.version = Version.create("HEAD") @resource.version = Version.create("HEAD")
end end

View File

@ -16,7 +16,7 @@ describe Formulary do
bottle do bottle do
cellar :any_skip_relocation cellar :any_skip_relocation
root_url "file://#{bottle_dir}" root_url "file://#{bottle_dir}"
sha256 "d48bbbe583dcfbfa608579724fc6f0328b3cd316935c6ea22f134610aaf2952f" => :#{Utils::Bottles.tag} sha256 "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149" => :#{Utils::Bottles.tag}
end end
def install def install

View File

@ -13,7 +13,8 @@ describe "RuboCop" do
end end
it "loads all Formula cops without errors" do it "loads all Formula cops without errors" do
_, _, status = Open3.capture3("rubocop", TEST_FIXTURE_DIR/"testball.rb") stdout, _, status = Open3.capture3("rubocop", TEST_FIXTURE_DIR/"testball.rb")
expect(stdout).to include("no offenses detected")
expect(status).to be_a_success expect(status).to be_a_success
end end
end end

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class Failball < Formula class Failball < Formula
def initialize(name = "failball", path = Pathname.new(__FILE__).expand_path, spec = :stable, alias_path: nil) def initialize(name = "failball", path = Pathname.new(__FILE__).expand_path, spec = :stable,
alias_path: nil, force_bottle: false)
self.class.instance_eval do self.class.instance_eval do
stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz" stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz"
stable.sha256 TESTBALL_SHA256 stable.sha256 TESTBALL_SHA256

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class Testball < Formula class Testball < Formula
def initialize(name = "testball", path = Pathname.new(__FILE__).expand_path, spec = :stable, alias_path: nil) def initialize(name = "testball", path = Pathname.new(__FILE__).expand_path, spec = :stable,
alias_path: nil, force_bottle: false)
self.class.instance_eval do self.class.instance_eval do
stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz" stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz"
stable.sha256 TESTBALL_SHA256 stable.sha256 TESTBALL_SHA256

View File

@ -1,14 +1,15 @@
# frozen_string_literal: true # frozen_string_literal: true
class TestballBottle < Formula class TestballBottle < Formula
def initialize(name = "testball_bottle", path = Pathname.new(__FILE__).expand_path, spec = :stable, alias_path: nil) def initialize(name = "testball_bottle", path = Pathname.new(__FILE__).expand_path, spec = :stable,
alias_path: nil, force_bottle: false)
self.class.instance_eval do self.class.instance_eval do
stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz" stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz"
stable.sha256 TESTBALL_SHA256 stable.sha256 TESTBALL_SHA256
stable.bottle do stable.bottle do
cellar :any_skip_relocation cellar :any_skip_relocation
root_url "file://#{TEST_FIXTURE_DIR}/bottles" root_url "file://#{TEST_FIXTURE_DIR}/bottles"
sha256 "d48bbbe583dcfbfa608579724fc6f0328b3cd316935c6ea22f134610aaf2952f" => Utils::Bottles.tag sha256 "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149" => Utils::Bottles.tag
end end
cxxstdlib_check :skip cxxstdlib_check :skip
end end