mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
Merge pull request #21176 from Homebrew/use-formula-struct
Use `FormulaStruct` when loading formulae from the API
This commit is contained in:
@@ -5,6 +5,7 @@ require "api/analytics"
|
||||
require "api/cask"
|
||||
require "api/formula"
|
||||
require "api/internal"
|
||||
require "api/formula_struct"
|
||||
require "base64"
|
||||
require "utils/output"
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ require "cachable"
|
||||
require "api"
|
||||
require "api/source_download"
|
||||
require "download_queue"
|
||||
require "autobump_constants"
|
||||
|
||||
module Homebrew
|
||||
module API
|
||||
@@ -157,6 +158,148 @@ module Homebrew
|
||||
Homebrew::API.write_names_file!(all_formulae.keys, "formula", regenerate:)
|
||||
Homebrew::API.write_aliases_file!(all_aliases, "formula", regenerate:)
|
||||
end
|
||||
|
||||
sig { params(hash: T::Hash[String, T.untyped]).returns(FormulaStruct) }
|
||||
def self.generate_formula_struct_hash(hash)
|
||||
hash = Homebrew::API.merge_variations(hash).dup
|
||||
|
||||
if (caveats = hash["caveats"])
|
||||
hash["caveats"] = Formulary.replace_placeholders(caveats)
|
||||
end
|
||||
|
||||
hash["bottle_checksums"] = begin
|
||||
files = hash.dig("bottle", "stable", "files") || {}
|
||||
files.map do |tag, bottle_spec|
|
||||
{
|
||||
cellar: Formulary.convert_to_string_or_symbol(bottle_spec.fetch("cellar")),
|
||||
tag.to_sym => bottle_spec.fetch("sha256"),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
hash["bottle_rebuild"] = hash.dig("bottle", "stable", "rebuild")
|
||||
|
||||
conflicts_with = hash["conflicts_with"] || []
|
||||
conflicts_with_reasons = hash["conflicts_with_reasons"] || []
|
||||
hash["conflicts"] = conflicts_with.zip(conflicts_with_reasons).map do |name, reason|
|
||||
if reason.present?
|
||||
[name, { because: reason }]
|
||||
else
|
||||
[name, {}]
|
||||
end
|
||||
end
|
||||
|
||||
if (deprecation_date = hash["deprecation_date"])
|
||||
hash["deprecate_args"] = {
|
||||
date: deprecation_date,
|
||||
because: DeprecateDisable.to_reason_string_or_symbol(hash["deprecation_reason"],
|
||||
type: :formula),
|
||||
replacement_formula: hash["deprecation_replacement_formula"],
|
||||
replacement_cask: hash["deprecation_replacement_cask"],
|
||||
}
|
||||
end
|
||||
|
||||
if (disable_date = hash["disable_date"])
|
||||
hash["disable_args"] = {
|
||||
date: disable_date,
|
||||
because: DeprecateDisable.to_reason_string_or_symbol(hash["disable_reason"], type: :formula),
|
||||
replacement_formula: hash["disable_replacement_formula"],
|
||||
replacement_cask: hash["disable_replacement_cask"],
|
||||
}
|
||||
end
|
||||
|
||||
hash["head_dependency_hash"] = hash["head_dependencies"]
|
||||
|
||||
hash["head_url_args"] = begin
|
||||
url = hash.dig("urls", "head", "url")
|
||||
specs = {
|
||||
branch: hash.dig("urls", "head", "branch"),
|
||||
using: hash.dig("urls", "head", "using")&.to_sym,
|
||||
}.compact_blank
|
||||
[url, specs]
|
||||
end
|
||||
|
||||
if (keg_only_hash = hash["keg_only_reason"])
|
||||
reason = Formulary.convert_to_string_or_symbol(keg_only_hash.fetch("reason"))
|
||||
explanation = keg_only_hash["explanation"]
|
||||
hash["keg_only_args"] = [reason, explanation].compact
|
||||
end
|
||||
|
||||
hash["license"] = SPDX.string_to_license_expression(hash["license"])
|
||||
|
||||
hash["link_overwrite_paths"] = hash["link_overwrite"]
|
||||
|
||||
if (reason = hash["no_autobump_message"])
|
||||
reason = reason.to_sym if NO_AUTOBUMP_REASONS_LIST.key?(reason.to_sym)
|
||||
hash["no_autobump_args"] = { because: reason }
|
||||
end
|
||||
|
||||
if (condition = hash["pour_bottle_only_if"])
|
||||
hash["pour_bottle_args"] = { only_if: condition.to_sym }
|
||||
end
|
||||
|
||||
hash["requirements_array"] = hash["requirements"]
|
||||
|
||||
hash["ruby_source_checksum"] = hash.dig("ruby_source_checksum", "sha256")
|
||||
|
||||
if (service_hash = hash["service"])
|
||||
service_hash = Homebrew::Service.from_hash(service_hash)
|
||||
|
||||
hash["service_run_args"], hash["service_run_kwargs"] = case (run = service_hash[:run])
|
||||
when Hash
|
||||
[[], run]
|
||||
when Array, String
|
||||
[[run], {}]
|
||||
else
|
||||
[[], {}]
|
||||
end
|
||||
|
||||
hash["service_name_args"] = service_hash[:name]
|
||||
|
||||
hash["service_args"] = service_hash.filter_map do |key, arg|
|
||||
[key.to_sym, arg] if key != :name && key != :run
|
||||
end
|
||||
end
|
||||
|
||||
hash["stable_checksum"] = hash.dig("urls", "stable", "checksum")
|
||||
|
||||
hash["stable_dependency_hash"] = {
|
||||
"dependencies" => hash["dependencies"] || [],
|
||||
"build_dependencies" => hash["build_dependencies"] || [],
|
||||
"test_dependencies" => hash["test_dependencies"] || [],
|
||||
"recommended_dependencies" => hash["recommended_dependencies"] || [],
|
||||
"optional_dependencies" => hash["optional_dependencies"] || [],
|
||||
"uses_from_macos" => hash["uses_from_macos"] || [],
|
||||
"uses_from_macos_bounds" => hash["uses_from_macos_bounds"] || [],
|
||||
}
|
||||
|
||||
hash["stable_url_args"] = begin
|
||||
url = hash.dig("urls", "stable", "url")
|
||||
specs = {
|
||||
tag: hash.dig("urls", "stable", "tag"),
|
||||
revision: hash.dig("urls", "stable", "revision"),
|
||||
using: hash.dig("urls", "stable", "using")&.to_sym,
|
||||
}.compact_blank
|
||||
[url, specs]
|
||||
end
|
||||
|
||||
hash["stable_version"] = hash.dig("versions", "stable")
|
||||
|
||||
# Should match FormulaStruct::PREDICATES
|
||||
hash["bottle_present"] = hash["bottle"].present?
|
||||
hash["deprecated_present"] = hash["deprecation_date"].present?
|
||||
hash["disabled_present"] = hash["disable_date"].present?
|
||||
hash["head_present"] = hash.dig("urls", "head").present?
|
||||
hash["keg_only_present"] = hash["keg_only_reason"].present?
|
||||
hash["no_autobump_message_present"] = hash["no_autobump_message"].present?
|
||||
hash["pour_bottle_present"] = hash["pour_bottle_only_if"].present?
|
||||
hash["service_present"] = hash["service"].present?
|
||||
hash["service_run_present"] = hash.dig("service", "run").present?
|
||||
hash["service_name_present"] = hash.dig("service", "name").present?
|
||||
hash["stable_present"] = hash.dig("urls", "stable").present?
|
||||
|
||||
FormulaStruct.from_hash(hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "service"
|
||||
require "utils/spdx"
|
||||
|
||||
module Homebrew
|
||||
module API
|
||||
class FormulaStruct < T::Struct
|
||||
PREDICATES = [
|
||||
:bottle,
|
||||
:deprecated,
|
||||
:disabled,
|
||||
:head,
|
||||
:keg_only,
|
||||
:no_autobump_message,
|
||||
:pour_bottle,
|
||||
:service,
|
||||
:service_run,
|
||||
:service_name,
|
||||
:stable,
|
||||
].freeze
|
||||
|
||||
# `:codesign` and custom requirement classes are not supported.
|
||||
API_SUPPORTED_REQUIREMENTS = [:arch, :linux, :macos, :maximum_macos, :xcode].freeze
|
||||
private_constant :API_SUPPORTED_REQUIREMENTS
|
||||
|
||||
DependencyArgs = T.type_alias do
|
||||
T.any(
|
||||
# Formula name: "foo"
|
||||
String,
|
||||
# Formula name and dependency type: { "foo" => :build }
|
||||
T::Hash[String, Symbol],
|
||||
)
|
||||
end
|
||||
|
||||
RequirementArgs = T.type_alias do
|
||||
T.any(
|
||||
# Requirement name: :macos
|
||||
Symbol,
|
||||
# Requirement name and other info: { macos: :build }
|
||||
T::Hash[Symbol, T::Array[T.anything]],
|
||||
)
|
||||
end
|
||||
|
||||
UsesFromMacOSArgs = T.type_alias do
|
||||
[
|
||||
T.any(
|
||||
# Formula name: "foo"
|
||||
String,
|
||||
# Formula name and dependency type: { "foo" => :build }
|
||||
# Formula name, dependency type, and version bounds: { "foo" => :build, since: :catalina }
|
||||
T::Hash[T.any(String, Symbol), T.any(Symbol, T::Array[Symbol])],
|
||||
),
|
||||
# If the first argument is only a name, this argument contains the version bounds: { since: :catalina }
|
||||
T::Hash[Symbol, Symbol],
|
||||
]
|
||||
end
|
||||
|
||||
PREDICATES.each do |predicate_name|
|
||||
present_method_name = :"#{predicate_name}_present"
|
||||
predicate_method_name = :"#{predicate_name}?"
|
||||
|
||||
const present_method_name, T::Boolean, default: false
|
||||
|
||||
define_method(predicate_method_name) do
|
||||
send(present_method_name)
|
||||
end
|
||||
end
|
||||
|
||||
# Changes to this struct must be mirrored in Homebrew::API::Formula.generate_formula_struct_hash
|
||||
const :aliases, T::Array[String], default: []
|
||||
const :bottle, T::Hash[String, T.anything], default: {}
|
||||
const :bottle_checksums, T::Array[T::Hash[String, T.anything]], default: []
|
||||
const :bottle_rebuild, Integer, default: 0
|
||||
const :caveats, T.nilable(String)
|
||||
const :conflicts, T::Array[[String, T::Hash[Symbol, String]]], default: []
|
||||
const :deprecate_args, T::Hash[Symbol, T.nilable(T.any(String, Symbol))], default: {}
|
||||
const :desc, String
|
||||
const :disable_args, T::Hash[Symbol, T.nilable(T.any(String, Symbol))], default: {}
|
||||
const :head_url_args, [String, T::Hash[Symbol, T.anything]]
|
||||
const :homepage, String
|
||||
const :keg_only_args, T::Array[T.any(String, Symbol)], default: []
|
||||
const :license, SPDX::LicenseExpression
|
||||
const :link_overwrite_paths, T::Array[String], default: []
|
||||
const :no_autobump_args, T::Hash[Symbol, T.any(String, Symbol)], default: {}
|
||||
const :oldnames, T::Array[String], default: []
|
||||
const :post_install_defined, T::Boolean, default: true
|
||||
const :pour_bottle_args, T::Hash[Symbol, Symbol], default: {}
|
||||
const :revision, Integer, default: 0
|
||||
const :ruby_source_checksum, String
|
||||
const :ruby_source_path, String
|
||||
const :service_args, T::Array[[Symbol, BasicObject]], default: []
|
||||
const :service_name_args, T::Hash[Symbol, String], default: {}
|
||||
const :service_run_args, T::Array[Homebrew::Service::RunParam], default: []
|
||||
const :service_run_kwargs, T::Hash[Symbol, Homebrew::Service::RunParam], default: {}
|
||||
const :stable_checksum, T.nilable(String)
|
||||
const :stable_url_args, [String, T::Hash[Symbol, T.anything]]
|
||||
const :stable_version, String
|
||||
const :tap_git_head, String
|
||||
const :version_scheme, Integer, default: 0
|
||||
const :versioned_formulae, T::Array[String], default: []
|
||||
|
||||
sig { returns(T::Array[T.any(DependencyArgs, RequirementArgs)]) }
|
||||
def head_dependencies
|
||||
spec_dependencies(:head) + spec_requirements(:head)
|
||||
end
|
||||
|
||||
sig { returns(T::Array[T.any(DependencyArgs, RequirementArgs)]) }
|
||||
def stable_dependencies
|
||||
spec_dependencies(:stable) + spec_requirements(:stable)
|
||||
end
|
||||
|
||||
sig { returns(T::Array[UsesFromMacOSArgs]) }
|
||||
def head_uses_from_macos
|
||||
spec_uses_from_macos(:head)
|
||||
end
|
||||
|
||||
sig { returns(T::Array[UsesFromMacOSArgs]) }
|
||||
def stable_uses_from_macos
|
||||
spec_uses_from_macos(:stable)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
const :stable_dependency_hash, T::Hash[String, T::Array[String]], default: {}
|
||||
const :head_dependency_hash, T::Hash[String, T::Array[String]], default: {}
|
||||
const :requirements_array, T::Array[T::Hash[String, T.untyped]], default: []
|
||||
|
||||
sig { params(spec: Symbol).returns(T::Array[DependencyArgs]) }
|
||||
def spec_dependencies(spec)
|
||||
deps_hash = send("#{spec}_dependency_hash")
|
||||
dependencies = deps_hash.fetch("dependencies", [])
|
||||
dependencies + [:build, :test, :recommended, :optional].filter_map do |type|
|
||||
deps_hash["#{type}_dependencies"]&.map do |dep|
|
||||
{ dep => type }
|
||||
end
|
||||
end.flatten(1)
|
||||
end
|
||||
|
||||
sig { params(spec: Symbol).returns(T::Array[UsesFromMacOSArgs]) }
|
||||
def spec_uses_from_macos(spec)
|
||||
deps_hash = send("#{spec}_dependency_hash")
|
||||
zipped_array = deps_hash["uses_from_macos"]&.zip(deps_hash["uses_from_macos_bounds"])
|
||||
return [] unless zipped_array
|
||||
|
||||
zipped_array.map do |entry, bounds|
|
||||
bounds ||= {}
|
||||
bounds = bounds.transform_keys(&:to_sym).transform_values(&:to_sym)
|
||||
|
||||
if entry.is_a?(Hash)
|
||||
# The key is the dependency name, the value is the dep type. Only the type should be a symbol
|
||||
entry = entry.deep_transform_values(&:to_sym)
|
||||
# When passing both a dep type and bounds, uses_from_macos expects them both in the first argument
|
||||
entry = entry.merge(bounds)
|
||||
[entry, {}]
|
||||
else
|
||||
[entry, bounds]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(spec: Symbol).returns(T::Array[RequirementArgs]) }
|
||||
def spec_requirements(spec)
|
||||
requirements_array.filter_map do |req|
|
||||
next unless req["specs"].include?(spec.to_s)
|
||||
|
||||
req_name = req["name"].to_sym
|
||||
next if API_SUPPORTED_REQUIREMENTS.exclude?(req_name)
|
||||
|
||||
req_version = case req_name
|
||||
when :arch
|
||||
req["version"]&.to_sym
|
||||
when :macos, :maximum_macos
|
||||
MacOSVersion::SYMBOLS.key(req["version"])
|
||||
else
|
||||
req["version"]
|
||||
end
|
||||
|
||||
req_tags = []
|
||||
req_tags << req_version if req_version.present?
|
||||
req_tags += req["contexts"]&.map do |tag|
|
||||
case tag
|
||||
when String
|
||||
tag.to_sym
|
||||
when Hash
|
||||
tag.deep_transform_keys(&:to_sym)
|
||||
else
|
||||
tag
|
||||
end
|
||||
end
|
||||
|
||||
if req_tags.empty?
|
||||
req_name
|
||||
else
|
||||
{ req_name => req_tags }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -160,7 +160,7 @@ class DependencyCollector
|
||||
|
||||
def parse_symbol_spec(spec, tags)
|
||||
# When modifying this list of supported requirements, consider
|
||||
# whether `Formulary::API_SUPPORTED_REQUIREMENTS` should also be changed.
|
||||
# whether `FormulaStruct::API_SUPPORTED_REQUIREMENTS` should also be changed.
|
||||
case spec
|
||||
when :arch then ArchRequirement.new(tags)
|
||||
when :codesign then CodesignRequirement.new(tags)
|
||||
|
||||
@@ -3602,14 +3602,14 @@ class Formula
|
||||
# @see https://spdx.github.io/spdx-spec/latest/annexes/spdx-license-expressions/ SPDX license expression guide
|
||||
# @api public
|
||||
sig {
|
||||
params(args: T.nilable(T.any(String, Symbol, T::Hash[T.any(String, Symbol), T.anything])))
|
||||
.returns(T.nilable(T.any(String, Symbol, T::Hash[T.any(String, Symbol), T.anything])))
|
||||
params(args: T.nilable(SPDX::LicenseExpression))
|
||||
.returns(T.nilable(SPDX::LicenseExpression))
|
||||
}
|
||||
def license(args = nil)
|
||||
if args.nil?
|
||||
@licenses
|
||||
else
|
||||
@licenses = T.let(args, T.nilable(T.any(String, Symbol, T::Hash[T.any(String, Symbol), T.anything])))
|
||||
@licenses = T.let(args, T.nilable(SPDX::LicenseExpression))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3936,7 +3936,7 @@ class Formula
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
sig { params(block: T.nilable(T.proc.returns(SoftwareSpec))).returns(T.untyped) }
|
||||
sig { params(block: T.nilable(T.proc.void)).returns(T.untyped) }
|
||||
def stable(&block)
|
||||
return T.must(@stable) unless block
|
||||
|
||||
|
||||
+54
-177
@@ -26,10 +26,6 @@ module Formulary
|
||||
ALLOWED_URL_SCHEMES = %w[file].freeze
|
||||
private_constant :ALLOWED_URL_SCHEMES
|
||||
|
||||
# `:codesign` and custom requirement classes are not supported.
|
||||
API_SUPPORTED_REQUIREMENTS = [:arch, :linux, :macos, :maximum_macos, :xcode].freeze
|
||||
private_constant :API_SUPPORTED_REQUIREMENTS
|
||||
|
||||
# Enable the factory cache.
|
||||
#
|
||||
# @api internal
|
||||
@@ -227,251 +223,132 @@ module Formulary
|
||||
mod.const_set(:BUILD_FLAGS, flags)
|
||||
|
||||
class_name = class_s(name)
|
||||
json_formula = Homebrew::API.merge_variations(json_formula_with_variations)
|
||||
|
||||
caveats_string = (replace_placeholders(json_formula["caveats"]) if json_formula["caveats"])
|
||||
|
||||
uses_from_macos_names = json_formula.fetch("uses_from_macos", []).map do |dep|
|
||||
next dep unless dep.is_a? Hash
|
||||
|
||||
dep.keys.first
|
||||
end
|
||||
|
||||
requirements = {}
|
||||
json_formula["requirements"]&.map do |req|
|
||||
req_name = req["name"].to_sym
|
||||
next if API_SUPPORTED_REQUIREMENTS.exclude?(req_name)
|
||||
|
||||
req_version = case req_name
|
||||
when :arch
|
||||
req["version"]&.to_sym
|
||||
when :macos, :maximum_macos
|
||||
MacOSVersion::SYMBOLS.key(req["version"])
|
||||
else
|
||||
req["version"]
|
||||
end
|
||||
|
||||
req_tags = []
|
||||
req_tags << req_version if req_version.present?
|
||||
req_tags += req["contexts"]&.map do |tag|
|
||||
case tag
|
||||
when String
|
||||
tag.to_sym
|
||||
when Hash
|
||||
tag.deep_transform_keys(&:to_sym)
|
||||
else
|
||||
tag
|
||||
end
|
||||
end
|
||||
|
||||
spec_hash = req_tags.empty? ? req_name : { req_name => req_tags }
|
||||
|
||||
specs = req["specs"]
|
||||
specs ||= ["stable", "head"] # backwards compatibility
|
||||
specs.each do |spec|
|
||||
requirements[spec.to_sym] ||= []
|
||||
requirements[spec.to_sym] << spec_hash
|
||||
end
|
||||
end
|
||||
|
||||
add_deps = lambda do |spec|
|
||||
T.bind(self, SoftwareSpec)
|
||||
|
||||
dep_json = json_formula.fetch("#{spec}_dependencies", json_formula)
|
||||
|
||||
dep_json["dependencies"]&.each do |dep|
|
||||
# Backwards compatibility check - uses_from_macos used to be a part of dependencies on Linux
|
||||
next if !json_formula.key?("uses_from_macos_bounds") && uses_from_macos_names.include?(dep) &&
|
||||
!Homebrew::SimulateSystem.simulating_or_running_on_macos?
|
||||
|
||||
depends_on dep
|
||||
end
|
||||
|
||||
[:build, :test, :recommended, :optional].each do |type|
|
||||
dep_json["#{type}_dependencies"]&.each do |dep|
|
||||
# Backwards compatibility check - uses_from_macos used to be a part of dependencies on Linux
|
||||
next if !json_formula.key?("uses_from_macos_bounds") && uses_from_macos_names.include?(dep) &&
|
||||
!Homebrew::SimulateSystem.simulating_or_running_on_macos?
|
||||
|
||||
depends_on dep => type
|
||||
end
|
||||
end
|
||||
|
||||
dep_json["uses_from_macos"]&.each_with_index do |dep, index|
|
||||
bounds = dep_json.fetch("uses_from_macos_bounds", [])[index].dup || {}
|
||||
bounds.deep_transform_keys!(&:to_sym)
|
||||
bounds.deep_transform_values!(&:to_sym)
|
||||
|
||||
if dep.is_a?(Hash)
|
||||
uses_from_macos dep.deep_transform_values(&:to_sym).merge(bounds)
|
||||
else
|
||||
uses_from_macos dep, bounds
|
||||
end
|
||||
end
|
||||
end
|
||||
formula_struct = Homebrew::API::Formula.generate_formula_struct_hash(json_formula_with_variations)
|
||||
|
||||
klass = Class.new(::Formula) do
|
||||
@loaded_from_api = T.let(true, T.nilable(T::Boolean))
|
||||
@api_source = T.let(json_formula_with_variations, T.nilable(T::Hash[String, T.untyped]))
|
||||
|
||||
desc json_formula["desc"]
|
||||
homepage json_formula["homepage"]
|
||||
license SPDX.string_to_license_expression(json_formula["license"])
|
||||
revision json_formula.fetch("revision", 0)
|
||||
version_scheme json_formula.fetch("version_scheme", 0)
|
||||
desc formula_struct.desc
|
||||
homepage formula_struct.homepage
|
||||
license formula_struct.license
|
||||
revision formula_struct.revision
|
||||
version_scheme formula_struct.version_scheme
|
||||
|
||||
if (urls_stable = json_formula["urls"]["stable"].presence)
|
||||
if formula_struct.stable?
|
||||
stable do
|
||||
url_spec = {
|
||||
tag: urls_stable["tag"],
|
||||
revision: urls_stable["revision"],
|
||||
using: urls_stable["using"]&.to_sym,
|
||||
}.compact
|
||||
url urls_stable["url"], **url_spec
|
||||
version json_formula["versions"]["stable"]
|
||||
sha256 urls_stable["checksum"] if urls_stable["checksum"].present?
|
||||
url(*formula_struct.stable_url_args)
|
||||
version formula_struct.stable_version
|
||||
if (checksum = formula_struct.stable_checksum)
|
||||
sha256 checksum
|
||||
end
|
||||
|
||||
instance_exec(:stable, &add_deps)
|
||||
requirements[:stable]&.each do |req|
|
||||
depends_on req
|
||||
formula_struct.stable_dependencies.each do |dep|
|
||||
depends_on dep
|
||||
end
|
||||
|
||||
formula_struct.stable_uses_from_macos.each do |args|
|
||||
uses_from_macos(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (urls_head = json_formula["urls"]["head"].presence)
|
||||
if formula_struct.head?
|
||||
head do
|
||||
url_spec = {
|
||||
branch: urls_head["branch"],
|
||||
using: urls_head["using"]&.to_sym,
|
||||
}.compact
|
||||
url urls_head["url"], **url_spec
|
||||
url(*formula_struct.head_url_args)
|
||||
|
||||
instance_exec(:head, &add_deps)
|
||||
requirements[:head]&.each do |req|
|
||||
depends_on req
|
||||
formula_struct.head_dependencies.each do |dep|
|
||||
depends_on dep
|
||||
end
|
||||
|
||||
formula_struct.head_uses_from_macos.each do |args|
|
||||
uses_from_macos(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (because = json_formula["no_autobump_msg"])
|
||||
because = because.to_sym if NO_AUTOBUMP_REASONS_LIST.key?(because.to_sym)
|
||||
no_autobump!(because:)
|
||||
end
|
||||
no_autobump!(**formula_struct.no_autobump_args) if formula_struct.no_autobump_message?
|
||||
|
||||
bottles_stable = json_formula["bottle"]["stable"].presence
|
||||
|
||||
if bottles_stable
|
||||
if formula_struct.bottle?
|
||||
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 bottles_stable["rebuild"]
|
||||
bottles_stable["files"].each do |tag, bottle_spec|
|
||||
cellar = Formulary.convert_to_string_or_symbol bottle_spec["cellar"]
|
||||
sha256 cellar:, tag.to_sym => bottle_spec["sha256"]
|
||||
rebuild formula_struct.bottle_rebuild
|
||||
formula_struct.bottle_checksums.each do |args|
|
||||
sha256(**args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (pour_bottle_only_if = json_formula["pour_bottle_only_if"])
|
||||
pour_bottle? only_if: pour_bottle_only_if.to_sym
|
||||
pour_bottle?(**formula_struct.pour_bottle_args) if formula_struct.pour_bottle?
|
||||
|
||||
keg_only(*formula_struct.keg_only_args) if formula_struct.keg_only?
|
||||
|
||||
deprecate!(**formula_struct.deprecate_args) if formula_struct.deprecated?
|
||||
disable!(**formula_struct.disable_args) if formula_struct.disabled?
|
||||
|
||||
formula_struct.conflicts.each do |name, args|
|
||||
conflicts_with(name, **args)
|
||||
end
|
||||
|
||||
if (keg_only_reason = json_formula["keg_only_reason"].presence)
|
||||
reason = Formulary.convert_to_string_or_symbol keg_only_reason["reason"]
|
||||
keg_only reason, keg_only_reason["explanation"]
|
||||
end
|
||||
|
||||
if (deprecation_date = json_formula["deprecation_date"].presence)
|
||||
reason = DeprecateDisable.to_reason_string_or_symbol json_formula["deprecation_reason"], type: :formula
|
||||
replacement_formula = json_formula["deprecation_replacement_formula"]
|
||||
replacement_cask = json_formula["deprecation_replacement_cask"]
|
||||
deprecate! date: deprecation_date, because: reason, replacement_formula:, replacement_cask:
|
||||
end
|
||||
|
||||
if (disable_date = json_formula["disable_date"].presence)
|
||||
reason = DeprecateDisable.to_reason_string_or_symbol json_formula["disable_reason"], type: :formula
|
||||
replacement_formula = json_formula["disable_replacement_formula"]
|
||||
replacement_cask = json_formula["disable_replacement_cask"]
|
||||
disable! date: disable_date, because: reason, replacement_formula:, replacement_cask:
|
||||
end
|
||||
|
||||
json_formula["conflicts_with"]&.each_with_index do |conflict, index|
|
||||
conflicts_with conflict, because: json_formula.dig("conflicts_with_reasons", index)
|
||||
end
|
||||
|
||||
json_formula["link_overwrite"]&.each do |overwrite_path|
|
||||
link_overwrite overwrite_path
|
||||
formula_struct.link_overwrite_paths.each do |path|
|
||||
link_overwrite path
|
||||
end
|
||||
|
||||
define_method(:install) do
|
||||
raise NotImplementedError, "Cannot build from source from abstract formula."
|
||||
end
|
||||
|
||||
@post_install_defined_boolean = T.let(json_formula["post_install_defined"], T.nilable(T::Boolean))
|
||||
@post_install_defined_boolean = true if @post_install_defined_boolean.nil? # Backwards compatibility
|
||||
@post_install_defined_boolean = T.let(formula_struct.post_install_defined, T.nilable(T::Boolean))
|
||||
define_method(:post_install_defined?) do
|
||||
self.class.instance_variable_get(:@post_install_defined_boolean)
|
||||
end
|
||||
|
||||
if (service_hash = json_formula["service"].presence)
|
||||
service_hash = Homebrew::Service.from_hash(service_hash)
|
||||
if formula_struct.service?
|
||||
service do
|
||||
T.bind(self, Homebrew::Service)
|
||||
run(*formula_struct.service_run_args, **formula_struct.service_run_kwargs) if formula_struct.service_run?
|
||||
name(**formula_struct.service_name_args) if formula_struct.service_name?
|
||||
|
||||
if (run_params = service_hash.delete(:run).presence)
|
||||
case run_params
|
||||
when Hash
|
||||
run(**run_params)
|
||||
when Array, String
|
||||
run run_params
|
||||
end
|
||||
end
|
||||
|
||||
if (name_params = service_hash.delete(:name).presence)
|
||||
name(**name_params)
|
||||
end
|
||||
|
||||
service_hash.each do |key, arg|
|
||||
formula_struct.service_args.each do |key, arg|
|
||||
public_send(key, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@caveats_string = T.let(caveats_string, T.nilable(String))
|
||||
@caveats_string = T.let(formula_struct.caveats, T.nilable(String))
|
||||
define_method(:caveats) do
|
||||
self.class.instance_variable_get(:@caveats_string)
|
||||
end
|
||||
|
||||
@tap_git_head_string = T.let(json_formula["tap_git_head"], T.nilable(String))
|
||||
@tap_git_head_string = T.let(formula_struct.tap_git_head, T.nilable(String))
|
||||
define_method(:tap_git_head) do
|
||||
self.class.instance_variable_get(:@tap_git_head_string)
|
||||
end
|
||||
|
||||
@oldnames_array = T.let(json_formula["oldnames"] || [json_formula["oldname"]].compact, T.nilable(T::Array[String]))
|
||||
@oldnames_array = T.let(formula_struct.oldnames, T.nilable(T::Array[String]))
|
||||
define_method(:oldnames) do
|
||||
self.class.instance_variable_get(:@oldnames_array)
|
||||
end
|
||||
|
||||
@aliases_array = T.let(json_formula.fetch("aliases", []), T.nilable(T::Array[String]))
|
||||
@aliases_array = T.let(formula_struct.aliases, T.nilable(T::Array[String]))
|
||||
define_method(:aliases) do
|
||||
self.class.instance_variable_get(:@aliases_array)
|
||||
end
|
||||
|
||||
@versioned_formulae_array = T.let(json_formula.fetch("versioned_formulae", []), T.nilable(T::Array[String]))
|
||||
@versioned_formulae_array = T.let(formula_struct.versioned_formulae, T.nilable(T::Array[String]))
|
||||
define_method(:versioned_formulae_names) do
|
||||
self.class.instance_variable_get(:@versioned_formulae_array)
|
||||
end
|
||||
|
||||
@ruby_source_path_string = T.let(json_formula["ruby_source_path"], T.nilable(String))
|
||||
@ruby_source_path_string = T.let(formula_struct.ruby_source_path, T.nilable(String))
|
||||
define_method(:ruby_source_path) do
|
||||
self.class.instance_variable_get(:@ruby_source_path_string)
|
||||
end
|
||||
|
||||
@ruby_source_checksum_string = T.let(json_formula.dig("ruby_source_checksum", "sha256"), T.nilable(String))
|
||||
@ruby_source_checksum_string ||= json_formula["ruby_source_sha256"]
|
||||
@ruby_source_checksum_string = T.let(formula_struct.ruby_source_checksum, T.nilable(String))
|
||||
define_method(:ruby_source_checksum) do
|
||||
checksum = self.class.instance_variable_get(:@ruby_source_checksum_string)
|
||||
Checksum.new(checksum) if checksum
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Homebrew::API::FormulaStruct`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Homebrew::API::FormulaStruct`.
|
||||
|
||||
|
||||
class Homebrew::API::FormulaStruct
|
||||
sig { returns(T::Boolean) }
|
||||
def bottle?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def deprecated?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def disabled?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def head?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def keg_only?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def no_autobump_message?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def pour_bottle?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def service?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def service_name?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def service_run?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def stable?; end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../../../global"
|
||||
require "api/formula_struct"
|
||||
|
||||
module Tapioca
|
||||
module Compilers
|
||||
class ApiStructs < Tapioca::Dsl::Compiler
|
||||
ConstantType = type_member { { fixed: T.class_of(T::Struct) } }
|
||||
|
||||
sig { override.returns(T::Enumerable[T::Module[T.anything]]) }
|
||||
def self.gather_constants = [::Homebrew::API::FormulaStruct]
|
||||
|
||||
sig { override.void }
|
||||
def decorate
|
||||
root.create_class(T.must(constant.name)) do |klass|
|
||||
::Homebrew::API::FormulaStruct::PREDICATES.each do |predicate_name|
|
||||
klass.create_method("#{predicate_name}?", return_type: "T::Boolean")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -362,6 +362,7 @@ RSpec.describe Formulary do
|
||||
"download" => nil,
|
||||
"version" => "1.0",
|
||||
"contexts" => ["build"],
|
||||
"specs" => ["stable"],
|
||||
},
|
||||
],
|
||||
"conflicts_with" => ["conflicting_formula"],
|
||||
@@ -377,21 +378,28 @@ RSpec.describe Formulary do
|
||||
},
|
||||
"ruby_source_path" => "Formula/#{formula_name}.rb",
|
||||
"ruby_source_checksum" => { "sha256" => "ABCDEFGHIJKLMNOPQRSTUVWXYZ" },
|
||||
"tap_git_head" => "0000000000000000000000000000000000000000",
|
||||
}.merge(extra_items),
|
||||
}
|
||||
end
|
||||
|
||||
let(:deprecate_json) do
|
||||
{
|
||||
"deprecation_date" => "2022-06-15",
|
||||
"deprecation_reason" => "repo_archived",
|
||||
"deprecated" => true,
|
||||
"deprecation_date" => "2022-06-15",
|
||||
"deprecation_reason" => "repo_archived",
|
||||
"deprecation_replacement_formula" => nil,
|
||||
"deprecation_replacement_cask" => nil,
|
||||
}
|
||||
end
|
||||
|
||||
let(:disable_json) do
|
||||
{
|
||||
"disable_date" => "2022-06-15",
|
||||
"disable_reason" => "requires something else",
|
||||
"disabled" => true,
|
||||
"disable_date" => "2022-06-15",
|
||||
"disable_reason" => "requires something else",
|
||||
"disable_replacement_formula" => nil,
|
||||
"disable_replacement_cask" => nil,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -419,7 +427,7 @@ RSpec.describe Formulary do
|
||||
{
|
||||
"variations" => {
|
||||
"x86_64_linux" => {
|
||||
"dependencies" => ["dep", "uses_from_macos_dep"],
|
||||
"dependencies" => ["dep"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -154,19 +154,15 @@ module SPDX
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(
|
||||
string: T.nilable(String),
|
||||
).returns(
|
||||
T.nilable(
|
||||
T.any(
|
||||
String,
|
||||
Symbol,
|
||||
T::Hash[T.any(String, Symbol), T.untyped],
|
||||
),
|
||||
),
|
||||
LicenseExpression = T.type_alias do
|
||||
T.any(
|
||||
String,
|
||||
Symbol,
|
||||
T::Hash[T.any(String, Symbol), T.anything],
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
sig { params(string: T.nilable(String)).returns(T.nilable(LicenseExpression)) }
|
||||
def string_to_license_expression(string)
|
||||
return if string.blank?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user