Freeze formula definition once first instance is created
This commit is contained in:
parent
15280ba107
commit
abfbb46678
@ -33,9 +33,17 @@ class BuildEnvironment
|
|||||||
module DSL
|
module DSL
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
|
|
||||||
|
# Initialise @env for each class which may use this DSL (e.g. each formula subclass).
|
||||||
|
# `env` may never be called, and it needs to be initialised before the class is frozen.
|
||||||
|
def inherited(child)
|
||||||
|
super
|
||||||
|
child.instance_eval do
|
||||||
|
@env = BuildEnvironment.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
sig { params(settings: Symbol).returns(BuildEnvironment) }
|
sig { params(settings: Symbol).returns(BuildEnvironment) }
|
||||||
def env(*settings)
|
def env(*settings)
|
||||||
@env ||= BuildEnvironment.new
|
|
||||||
@env.merge(settings)
|
@env.merge(settings)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -26,18 +26,25 @@ class DependencyCollector
|
|||||||
|
|
||||||
sig { void }
|
sig { void }
|
||||||
def initialize
|
def initialize
|
||||||
|
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
|
||||||
@deps = Dependencies.new
|
@deps = Dependencies.new
|
||||||
@requirements = Requirements.new
|
@requirements = Requirements.new
|
||||||
|
|
||||||
init_global_dep_tree_if_needed!
|
init_global_dep_tree_if_needed!
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_copy(other)
|
def initialize_dup(other)
|
||||||
super
|
super
|
||||||
@deps = @deps.dup
|
@deps = @deps.dup
|
||||||
@requirements = @requirements.dup
|
@requirements = @requirements.dup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def freeze
|
||||||
|
@deps.freeze
|
||||||
|
@requirements.freeze
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def add(spec)
|
def add(spec)
|
||||||
case dep = fetch(spec)
|
case dep = fetch(spec)
|
||||||
when Dependency
|
when Dependency
|
||||||
|
@ -5,11 +5,17 @@ class Module
|
|||||||
def attr_rw(*attrs)
|
def attr_rw(*attrs)
|
||||||
attrs.each do |attr|
|
attrs.each do |attr|
|
||||||
module_eval <<-EOS, __FILE__, __LINE__+1
|
module_eval <<-EOS, __FILE__, __LINE__+1
|
||||||
def #{attr}(val=nil) # def prefix(val=nil)
|
def #{attr}(val=nil) # def prefix(val=nil)
|
||||||
@#{attr} ||= nil # @prefix ||= nil
|
if val.nil? # if val.nil?
|
||||||
return @#{attr} if val.nil? # return @prefix if val.nil?
|
if instance_variable_defined?(:@#{attr}) # if instance_variable_defined?(:@prefix)
|
||||||
@#{attr} = val # @prefix = val
|
return @#{attr} # return @prefix
|
||||||
end # end
|
else # else
|
||||||
|
return nil # return nil
|
||||||
|
end # end
|
||||||
|
end # end
|
||||||
|
#
|
||||||
|
@#{attr} = val # @prefix = val
|
||||||
|
end # end
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -184,6 +184,11 @@ class Formula
|
|||||||
# Only allow instances of subclasses. The base class does not hold any spec information (URLs etc).
|
# Only allow instances of subclasses. The base class does not hold any spec information (URLs etc).
|
||||||
raise "Do not call `Formula.new' directly without a subclass." unless self.class < Formula
|
raise "Do not call `Formula.new' directly without a subclass." unless self.class < Formula
|
||||||
|
|
||||||
|
# Stop any subsequent modification of a formula's definition.
|
||||||
|
# Changes do not propagate to existing instances of formulae.
|
||||||
|
# Now that we have an instance, it's too late to make any changes to the class-level definition.
|
||||||
|
self.class.freeze
|
||||||
|
|
||||||
@name = name
|
@name = name
|
||||||
@path = path
|
@path = path
|
||||||
@alias_path = alias_path
|
@alias_path = alias_path
|
||||||
@ -2699,6 +2704,22 @@ class Formula
|
|||||||
include BuildEnvironment::DSL
|
include BuildEnvironment::DSL
|
||||||
include OnSystem::MacOSAndLinux
|
include OnSystem::MacOSAndLinux
|
||||||
|
|
||||||
|
# Initialise instance variables for each subclass. These need to be initialised before the class is frozen,
|
||||||
|
# and some DSL may never be called so it can't be done lazily.
|
||||||
|
def inherited(child)
|
||||||
|
super
|
||||||
|
child.instance_eval do
|
||||||
|
# Ensure this is synced with `freeze`
|
||||||
|
@stable = SoftwareSpec.new(flags: build_flags)
|
||||||
|
@head = HeadSoftwareSpec.new(flags: build_flags)
|
||||||
|
@livecheck = Livecheck.new(self)
|
||||||
|
@conflicts = []
|
||||||
|
@skip_clean_paths = Set.new
|
||||||
|
@link_overwrite_paths = Set.new
|
||||||
|
@allowed_missing_libraries = Set.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def method_added(method)
|
def method_added(method)
|
||||||
super
|
super
|
||||||
|
|
||||||
@ -2710,6 +2731,16 @@ class Formula
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def freeze
|
||||||
|
specs.each(&:freeze)
|
||||||
|
@livecheck.freeze
|
||||||
|
@conflicts.freeze
|
||||||
|
@skip_clean_paths.freeze
|
||||||
|
@link_overwrite_paths.freeze
|
||||||
|
@allowed_missing_libraries.freeze
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
# Whether this formula contains OS/arch-specific blocks
|
# Whether this formula contains OS/arch-specific blocks
|
||||||
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
|
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
|
||||||
# @private
|
# @private
|
||||||
@ -2790,6 +2821,18 @@ class Formula
|
|||||||
# @private
|
# @private
|
||||||
attr_reader :plist_manual
|
attr_reader :plist_manual
|
||||||
|
|
||||||
|
# @private
|
||||||
|
attr_reader :conflicts
|
||||||
|
|
||||||
|
# @private
|
||||||
|
attr_reader :skip_clean_paths
|
||||||
|
|
||||||
|
# @private
|
||||||
|
attr_reader :link_overwrite_paths
|
||||||
|
|
||||||
|
# @private
|
||||||
|
attr_reader :allowed_missing_libraries
|
||||||
|
|
||||||
# If `pour_bottle?` returns `false` the user-visible reason to display for
|
# If `pour_bottle?` returns `false` the user-visible reason to display for
|
||||||
# why they cannot use the bottle.
|
# why they cannot use the bottle.
|
||||||
# @private
|
# @private
|
||||||
@ -2820,7 +2863,7 @@ class Formula
|
|||||||
# A list of the {.stable} and {.head} {SoftwareSpec}s.
|
# A list of the {.stable} and {.head} {SoftwareSpec}s.
|
||||||
# @private
|
# @private
|
||||||
def specs
|
def specs
|
||||||
@specs ||= [stable, head].freeze
|
[stable, head].freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
# @!attribute [w] url
|
# @!attribute [w] url
|
||||||
@ -2937,7 +2980,6 @@ class Formula
|
|||||||
# depends_on "libffi"
|
# depends_on "libffi"
|
||||||
# end</pre>
|
# end</pre>
|
||||||
def stable(&block)
|
def stable(&block)
|
||||||
@stable ||= SoftwareSpec.new(flags: build_flags)
|
|
||||||
return @stable unless block
|
return @stable unless block
|
||||||
|
|
||||||
@stable.instance_eval(&block)
|
@stable.instance_eval(&block)
|
||||||
@ -2956,7 +2998,6 @@ 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(flags: build_flags)
|
|
||||||
if block
|
if block
|
||||||
@head.instance_eval(&block)
|
@head.instance_eval(&block)
|
||||||
elsif val
|
elsif val
|
||||||
@ -3107,11 +3148,6 @@ class Formula
|
|||||||
@plist_manual = options[:manual]
|
@plist_manual = options[:manual]
|
||||||
end
|
end
|
||||||
|
|
||||||
# @private
|
|
||||||
def conflicts
|
|
||||||
@conflicts ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
# One or more formulae that conflict with this one and why.
|
# One or more formulae that conflict with this one and why.
|
||||||
# <pre>conflicts_with "imagemagick", because: "both install `convert` binaries"</pre>
|
# <pre>conflicts_with "imagemagick", because: "both install `convert` binaries"</pre>
|
||||||
def conflicts_with(*names)
|
def conflicts_with(*names)
|
||||||
@ -3132,11 +3168,6 @@ class Formula
|
|||||||
skip_clean_paths.merge(paths)
|
skip_clean_paths.merge(paths)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @private
|
|
||||||
def skip_clean_paths
|
|
||||||
@skip_clean_paths ||= Set.new
|
|
||||||
end
|
|
||||||
|
|
||||||
# Software that will not be symlinked into the `brew --prefix` and will
|
# Software that will not be symlinked into the `brew --prefix` and will
|
||||||
# only live in its Cellar. Other formulae can depend on it and Homebrew
|
# only live in its Cellar. Other formulae can depend on it and Homebrew
|
||||||
# will add the necessary includes, libraries, and other paths while
|
# will add the necessary includes, libraries, and other paths while
|
||||||
@ -3240,7 +3271,6 @@ class Formula
|
|||||||
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
||||||
# end</pre>
|
# end</pre>
|
||||||
def livecheck(&block)
|
def livecheck(&block)
|
||||||
@livecheck ||= Livecheck.new(self)
|
|
||||||
return @livecheck unless block
|
return @livecheck unless block
|
||||||
|
|
||||||
@livecheckable = true
|
@livecheckable = true
|
||||||
@ -3396,11 +3426,6 @@ class Formula
|
|||||||
link_overwrite_paths.merge(paths)
|
link_overwrite_paths.merge(paths)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @private
|
|
||||||
def link_overwrite_paths
|
|
||||||
@link_overwrite_paths ||= Set.new
|
|
||||||
end
|
|
||||||
|
|
||||||
# Permit links to certain libraries that don't exist. Available on Linux only.
|
# Permit links to certain libraries that don't exist. Available on Linux only.
|
||||||
def ignore_missing_libraries(*libs)
|
def ignore_missing_libraries(*libs)
|
||||||
unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
|
unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
|
||||||
@ -3414,11 +3439,6 @@ class Formula
|
|||||||
|
|
||||||
allowed_missing_libraries.merge(libraries)
|
allowed_missing_libraries.merge(libraries)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @private
|
|
||||||
def allowed_missing_libraries
|
|
||||||
@allowed_missing_libraries ||= Set.new
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,9 +82,20 @@ class Options
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
|
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
|
||||||
@options = Set.new(*args)
|
@options = Set.new(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def initialize_dup(other)
|
||||||
|
super
|
||||||
|
@options = @options.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def freeze
|
||||||
|
@options.dup
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def each(*args, &block)
|
def each(*args, &block)
|
||||||
@options.each(*args, &block)
|
@options.each(*args, &block)
|
||||||
end
|
end
|
||||||
|
@ -29,6 +29,7 @@ class Resource
|
|||||||
attr_accessor :name
|
attr_accessor :name
|
||||||
|
|
||||||
def initialize(name = nil, &block)
|
def initialize(name = nil, &block)
|
||||||
|
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
|
||||||
@name = name
|
@name = name
|
||||||
@url = nil
|
@url = nil
|
||||||
@version = nil
|
@version = nil
|
||||||
@ -37,11 +38,35 @@ class Resource
|
|||||||
@checksum = nil
|
@checksum = nil
|
||||||
@using = nil
|
@using = nil
|
||||||
@patches = []
|
@patches = []
|
||||||
@livecheck = nil
|
@livecheck = Livecheck.new(self)
|
||||||
@livecheckable = false
|
@livecheckable = false
|
||||||
instance_eval(&block) if block
|
instance_eval(&block) if block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def initialize_dup(other)
|
||||||
|
super
|
||||||
|
@name = @name.dup
|
||||||
|
@version = @version.dup
|
||||||
|
@mirrors = @mirrors.dup
|
||||||
|
@specs = @specs.dup
|
||||||
|
@checksum = @checksum.dup
|
||||||
|
@using = @using.dup
|
||||||
|
@patches = @patches.dup
|
||||||
|
@livecheck = @livecheck.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def freeze
|
||||||
|
@name.freeze
|
||||||
|
@version.freeze
|
||||||
|
@mirrors.freeze
|
||||||
|
@specs.freeze
|
||||||
|
@checksum.freeze
|
||||||
|
@using.freeze
|
||||||
|
@patches.freeze
|
||||||
|
@livecheck.freeze
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def owner=(owner)
|
def owner=(owner)
|
||||||
@owner = owner
|
@owner = owner
|
||||||
patches.each { |p| p.owner = owner }
|
patches.each { |p| p.owner = owner }
|
||||||
@ -185,7 +210,6 @@ class Resource
|
|||||||
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
||||||
# end</pre>
|
# end</pre>
|
||||||
def livecheck(&block)
|
def livecheck(&block)
|
||||||
@livecheck ||= Livecheck.new(self) if block
|
|
||||||
return @livecheck unless block
|
return @livecheck unless block
|
||||||
|
|
||||||
@livecheckable = true
|
@livecheckable = true
|
||||||
|
@ -36,6 +36,7 @@ class SoftwareSpec
|
|||||||
def_delegators :@resource, :sha256
|
def_delegators :@resource, :sha256
|
||||||
|
|
||||||
def initialize(flags: [])
|
def initialize(flags: [])
|
||||||
|
# Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans)
|
||||||
@resource = Resource.new
|
@resource = Resource.new
|
||||||
@resources = {}
|
@resources = {}
|
||||||
@dependency_collector = DependencyCollector.new
|
@dependency_collector = DependencyCollector.new
|
||||||
@ -50,9 +51,36 @@ class SoftwareSpec
|
|||||||
@uses_from_macos_elements = []
|
@uses_from_macos_elements = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_copy(other)
|
def initialize_dup(other)
|
||||||
super
|
super
|
||||||
|
@resource = @resource.dup
|
||||||
|
@resources = @resources.dup
|
||||||
@dependency_collector = @dependency_collector.dup
|
@dependency_collector = @dependency_collector.dup
|
||||||
|
@bottle_specification = @bottle_specification.dup
|
||||||
|
@patches = @patches.dup
|
||||||
|
@options = @options.dup
|
||||||
|
@flags = @flags.dup
|
||||||
|
@deprecated_flags = @deprecated_flags.dup
|
||||||
|
@deprecated_options = @deprecated_options.dup
|
||||||
|
@build = @build.dup
|
||||||
|
@compiler_failures = @compiler_failures.dup
|
||||||
|
@uses_from_macos_elements = @uses_from_macos_elements.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def freeze
|
||||||
|
@resource.freeze
|
||||||
|
@resources.freeze
|
||||||
|
@dependency_collector.freeze
|
||||||
|
@bottle_specification.freeze
|
||||||
|
@patches.freeze
|
||||||
|
@options.freeze
|
||||||
|
@flags.freeze
|
||||||
|
@deprecated_flags.freeze
|
||||||
|
@deprecated_options.freeze
|
||||||
|
@build.freeze
|
||||||
|
@compiler_failures.freeze
|
||||||
|
@uses_from_macos_elements.freeze
|
||||||
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def owner=(owner)
|
def owner=(owner)
|
||||||
|
@ -66,10 +66,6 @@ describe Resource do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "#livecheck" do
|
describe "#livecheck" do
|
||||||
it "returns nil if livecheck block is not set in resource" do
|
|
||||||
expect(resource.livecheck).to be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "when livecheck block is set" do
|
specify "when livecheck block is set" do
|
||||||
expect(livecheck_resource.livecheck.url).to eq("https://brew.sh/test/releases")
|
expect(livecheck_resource.livecheck.url).to eq("https://brew.sh/test/releases")
|
||||||
expect(livecheck_resource.livecheck.regex).to eq(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
|
expect(livecheck_resource.livecheck.regex).to eq(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user