Support head deps & uses_from_macos bounds in API; strip implicit deps

This commit is contained in:
Bo Anderson 2023-06-19 06:07:53 +01:00
parent 71d51faa55
commit c4077aa076
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
2 changed files with 181 additions and 73 deletions

View File

@ -210,8 +210,9 @@ class Formula
@full_name = full_name_with_optional_tap(name)
@full_alias_name = full_name_with_optional_tap(@alias_name)
spec_eval :stable
spec_eval :head
self.class.spec_syms.each do |sym|
spec_eval sym
end
@active_spec = determine_active_spec(spec)
@active_spec_sym = if head?
@ -2114,9 +2115,31 @@ class Formula
Checksum.new(Digest::SHA256.file(path).hexdigest) if path.exist?
end
def merge_spec_dependables(dependables)
# We have a hash of specs names (stable/head) to dependency lists.
# Merge all of the dependency lists together, removing any duplicates.
all_dependables = [].union(*dependables.values.map(&:to_a))
all_dependables.map do |dependable|
{
dependable: dependable,
# Now find the list of specs each dependency was a part of.
specs: dependables.map { |spec, spec_deps| spec if spec_deps&.include?(dependable) }.compact,
}
end
end
private :merge_spec_dependables
# @private
def to_hash
dependencies = deps
# Create a hash of spec names (stable/head) to the list of dependencies under each
dependencies = self.class.spec_syms.to_h do |sym|
[sym, send(sym)&.declared_deps]
end
dependencies.transform_values! { |deps| deps&.reject(&:implicit?) } # Remove all implicit deps from all lists
requirements = self.class.spec_syms.to_h do |sym|
[sym, send(sym)&.requirements]
end
hsh = {
"name" => name,
@ -2141,25 +2164,13 @@ class Formula
"keg_only" => keg_only?,
"keg_only_reason" => keg_only_reason&.to_hash,
"options" => [],
"build_dependencies" => dependencies.select(&:build?)
.map(&:name)
.uniq,
"dependencies" => dependencies.reject(&:optional?)
.reject(&:recommended?)
.reject(&:build?)
.reject(&:test?)
.map(&:name)
.uniq,
"test_dependencies" => dependencies.select(&:test?)
.map(&:name)
.uniq,
"recommended_dependencies" => dependencies.select(&:recommended?)
.map(&:name)
.uniq,
"optional_dependencies" => dependencies.select(&:optional?)
.map(&:name)
.uniq,
"uses_from_macos" => uses_from_macos_elements.uniq,
"build_dependencies" => [],
"dependencies" => [],
"test_dependencies" => [],
"recommended_dependencies" => [],
"optional_dependencies" => [],
"uses_from_macos" => [],
"uses_from_macos_bounds" => [],
"requirements" => [],
"conflicts_with" => conflicts.map(&:name),
"conflicts_with_reasons" => conflicts.map(&:reason),
@ -2204,7 +2215,56 @@ class Formula
{ "option" => opt.flag, "description" => opt.description }
end
hsh["requirements"] = requirements.map do |req|
dependencies.each do |spec_sym, spec_deps|
next if spec_deps.nil?
dep_hash = if spec_sym == :stable
hsh
else
next if spec_deps == dependencies[:stable]
hsh["#{spec_sym}_dependencies"] ||= {}
end
dep_hash["build_dependencies"] = spec_deps.select(&:build?)
.reject(&:uses_from_macos?)
.map(&:name)
.uniq
dep_hash["dependencies"] = spec_deps.reject(&:optional?)
.reject(&:recommended?)
.reject(&:build?)
.reject(&:test?)
.reject(&:uses_from_macos?)
.map(&:name)
.uniq
dep_hash["test_dependencies"] = spec_deps.select(&:test?)
.reject(&:uses_from_macos?)
.map(&:name)
.uniq
dep_hash["recommended_dependencies"] = spec_deps.select(&:recommended?)
.reject(&:uses_from_macos?)
.map(&:name)
.uniq
dep_hash["optional_dependencies"] = spec_deps.select(&:optional?)
.reject(&:uses_from_macos?)
.map(&:name)
.uniq
uses_from_macos_deps = spec_deps.select(&:uses_from_macos?).uniq
dep_hash["uses_from_macos"] = uses_from_macos_deps.map do |dep|
if dep.tags.length >= 2
{ dep.name => dep.tags }
elsif dep.tags.present?
{ dep.name => dep.tags.first }
else
dep.name
end
end
dep_hash["uses_from_macos_bounds"] = uses_from_macos_deps.map(&:bounds)
end
hsh["requirements"] = merge_spec_dependables(requirements).map do |data|
req = data[:dependable]
req_name = req.name.dup
req_name.prepend("maximum_") if req.try(:comparator) == "<="
{
@ -2213,6 +2273,7 @@ class Formula
"download" => req.download,
"version" => req.try(:version) || req.try(:arch),
"contexts" => req.tags,
"specs" => data[:specs],
}
end
@ -2912,10 +2973,17 @@ class Formula
# <pre>version_scheme 1</pre>
attr_rw :version_scheme
# @private
def spec_syms
[:stable, :head].freeze
end
# A list of the {.stable} and {.head} {SoftwareSpec}s.
# @private
def specs
[stable, head].freeze
spec_syms.map do |sym|
send(sym)
end.freeze
end
# @!attribute [w] url

View File

@ -156,6 +156,79 @@ module Formulary
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] || {}
bounds.deep_transform_keys!(&:to_sym)
bounds.deep_transform_values! { |val| val.is_a?(String) ? val.to_sym : val }
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
klass = Class.new(::Formula) do
@loaded_from_api = true
@ -171,11 +244,26 @@ module Formulary
url urls_stable["url"], **url_spec
version json_formula["versions"]["stable"]
sha256 urls_stable["checksum"] if urls_stable["checksum"].present?
instance_exec(:stable, &add_deps)
requirements[:stable]&.each do |req|
depends_on req
end
end
end
if (urls_head = json_formula["urls"]["head"].presence)
head urls_head["url"], branch: urls_head["branch"]
head do
url_spec = { branch: urls_head["branch"] }.compact
url urls_head["url"], **url_spec
instance_exec(:head, &add_deps)
requirements[:head]&.each do |req|
depends_on req
end
end
end
if (bottles_stable = json_formula["bottle"]["stable"].presence)
@ -208,54 +296,6 @@ module Formulary
disable! date: disable_date, because: reason
end
json_formula["dependencies"].each do |dep|
next if uses_from_macos_names.include?(dep) && !Homebrew::SimulateSystem.simulating_or_running_on_macos?
depends_on dep
end
[:build, :test, :recommended, :optional].each do |type|
json_formula["#{type}_dependencies"].each do |dep|
next if uses_from_macos_names.include?(dep) && !Homebrew::SimulateSystem.simulating_or_running_on_macos?
depends_on dep => type
end
end
json_formula["uses_from_macos"].each do |dep|
dep = dep.deep_transform_values(&:to_sym) if dep.is_a?(Hash)
uses_from_macos dep
end
json_formula["requirements"].each 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
depends_on req_name => req_tags
end
json_formula["conflicts_with"].each_with_index do |conflict, index|
conflicts_with conflict, because: json_formula.dig("conflicts_with_reasons", index)
end