Enable loading stubbed formulae
This commit is contained in:
parent
99cdd7d8c0
commit
b04b0971a1
@ -271,6 +271,7 @@ class Formula
|
||||
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
||||
@oldname_locks = T.let([], T::Array[FormulaLock])
|
||||
@on_system_blocks_exist = T.let(false, T::Boolean)
|
||||
@fully_loaded_formula = T.let(nil, T.nilable(Formula))
|
||||
end
|
||||
|
||||
sig { params(spec_sym: Symbol).void }
|
||||
@ -557,12 +558,34 @@ class Formula
|
||||
# @see .loaded_from_api?
|
||||
delegate loaded_from_api?: :"self.class"
|
||||
|
||||
# Whether this formula was loaded using the formulae.brew.sh API.
|
||||
# @!method loaded_from_stub?
|
||||
# @see .loaded_from_stub?
|
||||
delegate loaded_from_stub?: :"self.class"
|
||||
|
||||
# The API source data used to load this formula.
|
||||
# Returns `nil` if the formula was not loaded from the API.
|
||||
# @!method api_source
|
||||
# @see .api_source
|
||||
delegate api_source: :"self.class"
|
||||
|
||||
sig { returns(Formula) }
|
||||
def fully_loaded_formula
|
||||
@fully_loaded_formula ||= if loaded_from_stub?
|
||||
json_contents = Homebrew::API::Formula.formula_json(name)
|
||||
Formulary.from_json_contents(name, json_contents)
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(download_queue: T.nilable(Homebrew::DownloadQueue)).void }
|
||||
def fetch_fully_loaded_formula!(download_queue: nil)
|
||||
return unless loaded_from_stub?
|
||||
|
||||
Homebrew::API::Formula.fetch_formula_json!(name, download_queue:)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def update_head_version
|
||||
return unless head?
|
||||
@ -3366,6 +3389,7 @@ class Formula
|
||||
@skip_clean_paths = T.let(Set.new, T.nilable(T::Set[T.any(String, Symbol)]))
|
||||
@link_overwrite_paths = T.let(Set.new, T.nilable(T::Set[String]))
|
||||
@loaded_from_api = T.let(false, T.nilable(T::Boolean))
|
||||
@loaded_from_stub = T.let(false, T.nilable(T::Boolean))
|
||||
@api_source = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
|
||||
@on_system_blocks_exist = T.let(false, T.nilable(T::Boolean))
|
||||
@network_access_allowed = T.let(SUPPORTED_NETWORK_ACCESS_PHASES.to_h do |phase|
|
||||
@ -3391,6 +3415,10 @@ class Formula
|
||||
sig { returns(T::Boolean) }
|
||||
def loaded_from_api? = !!@loaded_from_api
|
||||
|
||||
# Whether this formula was loaded using the internal formulae.brew.sh API.
|
||||
sig { returns(T::Boolean) }
|
||||
def loaded_from_stub? = !!@loaded_from_stub
|
||||
|
||||
# Whether this formula was loaded using the formulae.brew.sh API.
|
||||
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
||||
attr_reader :api_source
|
||||
|
@ -50,6 +50,11 @@ module Formulary
|
||||
platform_cache.key?(:api) && platform_cache[:api].key?(name)
|
||||
end
|
||||
|
||||
sig { params(name: String).returns(T::Boolean) }
|
||||
def self.formula_class_defined_from_stub?(name)
|
||||
platform_cache.key?(:stub) && platform_cache.fetch(:stub).key?(name)
|
||||
end
|
||||
|
||||
def self.formula_class_get_from_path(path)
|
||||
platform_cache[:path].fetch(path)
|
||||
end
|
||||
@ -58,6 +63,11 @@ module Formulary
|
||||
platform_cache[:api].fetch(name)
|
||||
end
|
||||
|
||||
sig { params(name: String).returns(T.class_of(Formula)) }
|
||||
def self.formula_class_get_from_stub(name)
|
||||
platform_cache.fetch(:stub).fetch(name)
|
||||
end
|
||||
|
||||
def self.clear_cache
|
||||
platform_cache.each do |type, cached_objects|
|
||||
next if type == :formulary_factory
|
||||
@ -445,17 +455,59 @@ module Formulary
|
||||
platform_cache[:api][name] = klass
|
||||
end
|
||||
|
||||
sig { params(name: String, formula_stub: Homebrew::FormulaStub, flags: T::Array[String]).returns(T.class_of(Formula)) }
|
||||
def self.load_formula_from_stub!(name, formula_stub, flags:)
|
||||
namespace = :"FormulaNamespaceStub#{namespace_key(formula_stub.to_json)}"
|
||||
|
||||
mod = Module.new
|
||||
remove_const(namespace) if const_defined?(namespace)
|
||||
const_set(namespace, mod)
|
||||
|
||||
mod.const_set(:BUILD_FLAGS, flags)
|
||||
|
||||
class_name = class_s(name)
|
||||
|
||||
klass = Class.new(::Formula) do
|
||||
@loaded_from_api = true
|
||||
@loaded_from_stub = true
|
||||
|
||||
url "formula-stub://#{name}/#{formula_stub.pkg_version}"
|
||||
version formula_stub.version.to_s
|
||||
revision formula_stub.revision
|
||||
|
||||
bottle do
|
||||
if Homebrew::EnvConfig.bottle_domain == HOMEBREW_BOTTLE_DEFAULT_DOMAIN
|
||||
root_url HOMEBREW_BOTTLE_DEFAULT_DOMAIN
|
||||
else
|
||||
root_url Homebrew::EnvConfig.bottle_domain
|
||||
end
|
||||
rebuild formula_stub.rebuild
|
||||
sha256 Utils::Bottles.tag.to_sym => formula_stub.sha256
|
||||
end
|
||||
|
||||
define_method :install do
|
||||
raise NotImplementedError, "Cannot build from source from abstract stubbed formula."
|
||||
end
|
||||
end
|
||||
|
||||
mod.const_set(class_name, klass)
|
||||
|
||||
platform_cache[:stub] ||= {}
|
||||
platform_cache[:stub][name] = klass
|
||||
end
|
||||
|
||||
sig {
|
||||
params(name: String, spec: T.nilable(Symbol), force_bottle: T::Boolean, flags: T::Array[String]).returns(Formula)
|
||||
params(name: String, spec: T.nilable(Symbol), force_bottle: T::Boolean, flags: T::Array[String], prefer_stub: T::Boolean).returns(Formula)
|
||||
}
|
||||
def self.resolve(
|
||||
name,
|
||||
spec: nil,
|
||||
force_bottle: false,
|
||||
flags: []
|
||||
flags: [],
|
||||
prefer_stub: false
|
||||
)
|
||||
if name.include?("/") || File.exist?(name)
|
||||
f = factory(name, *spec, force_bottle:, flags:)
|
||||
f = factory(name, *spec, force_bottle:, flags:, prefer_stub:)
|
||||
if f.any_version_installed?
|
||||
tab = Tab.for_formula(f)
|
||||
resolved_spec = spec || tab.spec
|
||||
@ -468,7 +520,7 @@ module Formulary
|
||||
end
|
||||
else
|
||||
rack = to_rack(name)
|
||||
alias_path = factory(name, force_bottle:, flags:).alias_path
|
||||
alias_path = factory(name, force_bottle:, flags:, prefer_stub:).alias_path
|
||||
f = from_rack(rack, *spec, alias_path:, force_bottle:, flags:)
|
||||
end
|
||||
|
||||
@ -936,6 +988,46 @@ module Formulary
|
||||
end
|
||||
end
|
||||
|
||||
# Load formulae directly from their JSON contents.
|
||||
class FormulaJSONContentsLoader < FromAPILoader
|
||||
def initialize(name, contents, tap: nil, alias_name: nil)
|
||||
@contents = contents
|
||||
super(name, tap: tap, alias_name: alias_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_from_api(flags:)
|
||||
Formulary.load_formula_from_json!(name, @contents, flags:)
|
||||
end
|
||||
end
|
||||
|
||||
# Load a formula stub from the internal API.
|
||||
class FormulaStubLoader < FromAPILoader
|
||||
sig {
|
||||
params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean)
|
||||
.returns(T.nilable(T.attached_class))
|
||||
}
|
||||
def self.try_new(ref, from: nil, warn: false)
|
||||
return unless Homebrew::EnvConfig.use_internal_api?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def klass(flags:, ignore_errors:)
|
||||
load_from_api(flags:) unless Formulary.formula_class_defined_from_stub?(name)
|
||||
Formulary.formula_class_get_from_stub(name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_from_api(flags:)
|
||||
formula_stub = Homebrew::API::Internal.formula_stub(name)
|
||||
|
||||
Formulary.load_formula_from_stub!(name, formula_stub, flags:)
|
||||
end
|
||||
end
|
||||
|
||||
# Return a {Formula} instance for the given reference.
|
||||
# `ref` is a string containing:
|
||||
#
|
||||
@ -955,6 +1047,7 @@ module Formulary
|
||||
force_bottle: T::Boolean,
|
||||
flags: T::Array[String],
|
||||
ignore_errors: T::Boolean,
|
||||
prefer_stub: T::Boolean,
|
||||
).returns(Formula)
|
||||
}
|
||||
def self.factory(
|
||||
@ -965,15 +1058,17 @@ module Formulary
|
||||
warn: false,
|
||||
force_bottle: false,
|
||||
flags: [],
|
||||
ignore_errors: false
|
||||
ignore_errors: false,
|
||||
prefer_stub: false
|
||||
)
|
||||
cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}"
|
||||
cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}-#{prefer_stub}"
|
||||
if factory_cached? && platform_cache[:formulary_factory]&.key?(cache_key)
|
||||
return platform_cache[:formulary_factory][cache_key]
|
||||
end
|
||||
|
||||
formula = loader_for(ref, from:, warn:)
|
||||
.get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:)
|
||||
loader = FormulaStubLoader.try_new(ref, from:, warn:) if prefer_stub
|
||||
loader ||= loader_for(ref, from:, warn:)
|
||||
formula = loader.get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:)
|
||||
|
||||
if factory_cached?
|
||||
platform_cache[:formulary_factory] ||= {}
|
||||
@ -1098,6 +1193,31 @@ module Formulary
|
||||
.get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:)
|
||||
end
|
||||
|
||||
# Return a {Formula} instance directly from JSON contents.
|
||||
sig {
|
||||
params(
|
||||
name: String,
|
||||
contents: T::Hash[String, T.untyped],
|
||||
spec: Symbol,
|
||||
alias_path: T.nilable(Pathname),
|
||||
force_bottle: T::Boolean,
|
||||
flags: T::Array[String],
|
||||
ignore_errors: T::Boolean,
|
||||
).returns(Formula)
|
||||
}
|
||||
def self.from_json_contents(
|
||||
name,
|
||||
contents,
|
||||
spec = :stable,
|
||||
alias_path: nil,
|
||||
force_bottle: false,
|
||||
flags: [],
|
||||
ignore_errors: false
|
||||
)
|
||||
FormulaJSONContentsLoader.new(name, contents)
|
||||
.get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:)
|
||||
end
|
||||
|
||||
def self.to_rack(ref)
|
||||
# If using a fully-scoped reference, check if the formula can be resolved.
|
||||
factory(ref) if ref.include? "/"
|
||||
|
3
Library/Homebrew/sorbet/rbi/dsl/formula.rbi
generated
3
Library/Homebrew/sorbet/rbi/dsl/formula.rbi
generated
@ -111,6 +111,9 @@ class Formula
|
||||
sig { params(args: T.untyped, block: T.untyped).returns(T::Boolean) }
|
||||
def loaded_from_api?(*args, &block); end
|
||||
|
||||
sig { params(args: T.untyped, block: T.untyped).returns(T::Boolean) }
|
||||
def loaded_from_stub?(*args, &block); end
|
||||
|
||||
sig { params(args: T.untyped, block: T.untyped).returns(T::Boolean) }
|
||||
def network_access_allowed?(*args, &block); end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user