2025-02-04 16:27:39 +00:00
|
|
|
# typed: true # rubocop:todo Sorbet/StrictSigil
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class BottleSpecification
|
|
|
|
RELOCATABLE_CELLARS = [:any, :any_skip_relocation].freeze
|
|
|
|
|
|
|
|
attr_accessor :tap
|
|
|
|
attr_reader :collector, :root_url_specs, :repository
|
|
|
|
|
|
|
|
sig { void }
|
|
|
|
def initialize
|
|
|
|
@rebuild = 0
|
|
|
|
@repository = Homebrew::DEFAULT_REPOSITORY
|
|
|
|
@collector = Utils::Bottles::Collector.new
|
|
|
|
@root_url_specs = {}
|
|
|
|
end
|
|
|
|
|
2025-02-23 13:41:23 -08:00
|
|
|
sig { params(val: Integer).returns(T.nilable(Integer)) }
|
|
|
|
def rebuild(val = T.unsafe(nil))
|
2025-02-23 13:18:49 -08:00
|
|
|
val.nil? ? @rebuild : @rebuild = val
|
|
|
|
end
|
|
|
|
|
2025-02-04 16:27:39 +00:00
|
|
|
def root_url(var = nil, specs = {})
|
|
|
|
if var.nil?
|
|
|
|
@root_url ||= if (github_packages_url = GitHubPackages.root_url_if_match(Homebrew::EnvConfig.bottle_domain))
|
|
|
|
github_packages_url
|
|
|
|
else
|
|
|
|
Homebrew::EnvConfig.bottle_domain
|
|
|
|
end
|
|
|
|
else
|
|
|
|
@root_url = if (github_packages_url = GitHubPackages.root_url_if_match(var))
|
|
|
|
github_packages_url
|
|
|
|
else
|
|
|
|
var
|
|
|
|
end
|
|
|
|
@root_url_specs.merge!(specs)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def ==(other)
|
|
|
|
self.class == other.class && rebuild == other.rebuild && collector == other.collector &&
|
|
|
|
root_url == other.root_url && root_url_specs == other.root_url_specs && tap == other.tap
|
|
|
|
end
|
|
|
|
alias eql? ==
|
|
|
|
|
|
|
|
sig { params(tag: Utils::Bottles::Tag).returns(T.any(Symbol, String)) }
|
|
|
|
def tag_to_cellar(tag = Utils::Bottles.tag)
|
|
|
|
spec = collector.specification_for(tag)
|
|
|
|
if spec.present?
|
|
|
|
spec.cellar
|
|
|
|
else
|
|
|
|
tag.default_cellar
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(tag: Utils::Bottles::Tag).returns(T::Boolean) }
|
|
|
|
def compatible_locations?(tag: Utils::Bottles.tag)
|
|
|
|
cellar = tag_to_cellar(tag)
|
|
|
|
|
|
|
|
return true if RELOCATABLE_CELLARS.include?(cellar)
|
|
|
|
|
|
|
|
prefix = Pathname(cellar.to_s).parent.to_s
|
|
|
|
|
|
|
|
cellar_relocatable = cellar.size >= HOMEBREW_CELLAR.to_s.size && ENV["HOMEBREW_RELOCATE_BUILD_PREFIX"].present?
|
|
|
|
prefix_relocatable = prefix.size >= HOMEBREW_PREFIX.to_s.size && ENV["HOMEBREW_RELOCATE_BUILD_PREFIX"].present?
|
|
|
|
|
|
|
|
compatible_cellar = cellar == HOMEBREW_CELLAR.to_s || cellar_relocatable
|
|
|
|
compatible_prefix = prefix == HOMEBREW_PREFIX.to_s || prefix_relocatable
|
|
|
|
|
|
|
|
compatible_cellar && compatible_prefix
|
|
|
|
end
|
|
|
|
|
|
|
|
# Does the {Bottle} this {BottleSpecification} belongs to need to be relocated?
|
|
|
|
sig { params(tag: Utils::Bottles::Tag).returns(T::Boolean) }
|
|
|
|
def skip_relocation?(tag: Utils::Bottles.tag)
|
|
|
|
spec = collector.specification_for(tag)
|
|
|
|
spec&.cellar == :any_skip_relocation
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(tag: T.any(Symbol, Utils::Bottles::Tag), no_older_versions: T::Boolean).returns(T::Boolean) }
|
|
|
|
def tag?(tag, no_older_versions: false)
|
|
|
|
collector.tag?(tag, no_older_versions:)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Checksum methods in the DSL's bottle block take
|
|
|
|
# a Hash, which indicates the platform the checksum applies on.
|
|
|
|
# Example bottle block syntax:
|
|
|
|
# bottle do
|
|
|
|
# sha256 cellar: :any_skip_relocation, big_sur: "69489ae397e4645..."
|
|
|
|
# sha256 cellar: :any, catalina: "449de5ea35d0e94..."
|
|
|
|
# end
|
|
|
|
def sha256(hash)
|
|
|
|
sha256_regex = /^[a-f0-9]{64}$/i
|
|
|
|
|
|
|
|
# find new `sha256 big_sur: "69489ae397e4645..."` format
|
|
|
|
tag, digest = hash.find do |key, value|
|
|
|
|
key.is_a?(Symbol) && value.is_a?(String) && value.match?(sha256_regex)
|
|
|
|
end
|
|
|
|
|
|
|
|
cellar = hash[:cellar] if digest && tag
|
|
|
|
|
|
|
|
tag = Utils::Bottles::Tag.from_symbol(tag)
|
|
|
|
|
|
|
|
cellar ||= tag.default_cellar
|
|
|
|
|
|
|
|
collector.add(tag, checksum: Checksum.new(digest), cellar:)
|
|
|
|
end
|
|
|
|
|
|
|
|
sig {
|
|
|
|
params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean)
|
|
|
|
.returns(T.nilable(Utils::Bottles::TagSpecification))
|
|
|
|
}
|
|
|
|
def tag_specification_for(tag, no_older_versions: false)
|
|
|
|
collector.specification_for(tag, no_older_versions:)
|
|
|
|
end
|
|
|
|
|
|
|
|
def checksums
|
|
|
|
tags = collector.tags.sort_by do |tag|
|
|
|
|
version = tag.to_macos_version
|
|
|
|
# Give `arm64` bottles a higher priority so they are first.
|
2025-03-18 16:10:43 +08:00
|
|
|
priority = (tag.arch == :arm64) ? 3 : 2
|
2025-02-04 16:27:39 +00:00
|
|
|
"#{priority}.#{version}_#{tag}"
|
|
|
|
rescue MacOSVersion::Error
|
2025-03-18 16:10:43 +08:00
|
|
|
# Sort non-macOS tags below macOS tags, and arm64 tags before other tags.
|
|
|
|
priority = (tag.arch == :arm64) ? 1 : 0
|
|
|
|
"#{priority}.#{tag}"
|
2025-02-04 16:27:39 +00:00
|
|
|
end
|
|
|
|
tags.reverse.map do |tag|
|
|
|
|
spec = collector.specification_for(tag)
|
|
|
|
{
|
|
|
|
"tag" => spec.tag.to_sym,
|
|
|
|
"digest" => spec.checksum,
|
|
|
|
"cellar" => spec.cellar,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
require "extend/os/bottle_specification"
|