Revamp APIs around bottle specifications

This commit is contained in:
Bo Anderson 2021-09-16 18:56:47 +01:00
parent 109f24fd60
commit b55498269f
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
10 changed files with 166 additions and 123 deletions

View File

@ -350,9 +350,9 @@ module Homebrew
tab_json = Utils::Bottles.file_from_bottle(bottle_path, tab_path) tab_json = Utils::Bottles.file_from_bottle(bottle_path, tab_path)
tab = Tab.from_file_content(tab_json, tab_path) tab = Tab.from_file_content(tab_json, tab_path)
_, _, bottle_cellar = Formula[f.name].bottle_specification.checksum_for(bottle_tag, no_older_versions: true) tag_spec = Formula[f.name].bottle_specification.tag_specification_for(bottle_tag, no_older_versions: true)
relocatable = [:any, :any_skip_relocation].include?(bottle_cellar) relocatable = [:any, :any_skip_relocation].include?(tag_spec.cellar)
skip_relocation = bottle_cellar == :any_skip_relocation skip_relocation = tag_spec.cellar == :any_skip_relocation
prefix = bottle_tag.default_prefix prefix = bottle_tag.default_prefix
cellar = bottle_tag.default_cellar cellar = bottle_tag.default_cellar
@ -506,7 +506,7 @@ module Homebrew
old_spec = f.bottle_specification old_spec = f.bottle_specification
if args.keep_old? && !old_spec.checksums.empty? if args.keep_old? && !old_spec.checksums.empty?
mismatches = [:root_url, :prefix, :rebuild].reject do |key| mismatches = [:root_url, :rebuild].reject do |key|
old_spec.send(key) == bottle.send(key) old_spec.send(key) == bottle.send(key)
end end
unless mismatches.empty? unless mismatches.empty?
@ -551,7 +551,7 @@ module Homebrew
}, },
"bottle" => { "bottle" => {
"root_url" => bottle.root_url, "root_url" => bottle.root_url,
"prefix" => bottle.prefix, "prefix" => prefix.to_s, # TODO: 3.3.0: deprecate this
"cellar" => bottle_cellar.to_s, "cellar" => bottle_cellar.to_s,
"rebuild" => bottle.rebuild, "rebuild" => bottle.rebuild,
"date" => Pathname(filename.to_s).mtime.strftime("%F"), "date" => Pathname(filename.to_s).mtime.strftime("%F"),
@ -640,16 +640,16 @@ module Homebrew
bottle_hash["formula"]["pkg_version"] == formula.pkg_version.to_s && bottle_hash["formula"]["pkg_version"] == formula.pkg_version.to_s &&
bottle.rebuild != old_bottle_spec.rebuild && bottle.rebuild != old_bottle_spec.rebuild &&
bottle.root_url == old_bottle_spec.root_url bottle.root_url == old_bottle_spec.root_url
bottle.collector.keys.all? do |tag| bottle.collector.tags.all? do |tag|
bottle_collector_tag = bottle.collector[tag] tag_spec = bottle.collector.specification_for(tag)
next false if bottle_collector_tag.blank? next false if tag_spec.blank?
old_bottle_spec_collector_tag = old_bottle_spec.collector[tag] old_tag_spec = old_bottle_spec.collector.specification_for(tag)
next false if old_bottle_spec_collector_tag.blank? next false if old_tag_spec.blank?
next false if bottle_collector_tag[:cellar] != old_bottle_spec_collector_tag[:cellar] next false if tag_spec.cellar != old_tag_spec.cellar
bottle_collector_tag[:checksum].hexdigest == old_bottle_spec_collector_tag[:checksum].hexdigest tag_spec.checksum.hexdigest == old_tag_spec.checksum.hexdigest
end end
end end
@ -744,7 +744,6 @@ module Homebrew
new_values = { new_values = {
root_url: new_bottle_hash["root_url"], root_url: new_bottle_hash["root_url"],
prefix: new_bottle_hash["prefix"],
rebuild: new_bottle_hash["rebuild"], rebuild: new_bottle_hash["rebuild"],
} }
@ -762,17 +761,17 @@ module Homebrew
return [mismatches, checksums] if old_keys.exclude? :sha256 return [mismatches, checksums] if old_keys.exclude? :sha256
old_bottle_spec.collector.each_key do |tag| old_bottle_spec.collector.each_tag do |tag|
old_checksum_hash = old_bottle_spec.collector[tag] old_tag_spec = old_bottle_spec.collector.specification_for(tag)
old_hexdigest = old_checksum_hash[:checksum].hexdigest old_hexdigest = old_tag_spec.checksum.hexdigest
old_cellar = old_checksum_hash[:cellar] old_cellar = old_tag_spec.cellar
new_value = new_bottle_hash.dig("tags", tag.to_s) new_value = new_bottle_hash.dig("tags", tag.to_s)
if new_value.present? && new_value["sha256"] != old_hexdigest if new_value.present? && new_value["sha256"] != old_hexdigest
mismatches << "sha256 #{tag}: old: #{old_hexdigest.inspect}, new: #{new_value["sha256"].inspect}" mismatches << "sha256 #{tag}: old: #{old_hexdigest.inspect}, new: #{new_value["sha256"].inspect}"
elsif new_value.present? && new_value["cellar"] != old_cellar.to_s elsif new_value.present? && new_value["cellar"] != old_cellar.to_s
mismatches << "cellar #{tag}: old: #{old_cellar.to_s.inspect}, new: #{new_value["cellar"].inspect}" mismatches << "cellar #{tag}: old: #{old_cellar.to_s.inspect}, new: #{new_value["cellar"].inspect}"
else else
checksums << { cellar: old_cellar, tag => old_hexdigest } checksums << { cellar: old_cellar, tag.to_sym => old_hexdigest }
end end
end end

View File

@ -3,8 +3,9 @@
class BottleSpecification class BottleSpecification
extend T::Sig extend T::Sig
sig { returns(T::Boolean) }
def skip_relocation? sig { params(tag: Utils::Bottles::Tag).returns(T::Boolean) }
def skip_relocation?(tag: Utils::Bottles.tag)
false false
end end
end end

View File

@ -41,11 +41,10 @@ module Utils
return if tag_version.blank? return if tag_version.blank?
keys.find do |key| tags.find do |candidate|
key_tag = Tag.from_symbol(key) next if candidate.arch != tag.arch
next if key_tag.arch != tag.arch
key_tag.to_macos_version <= tag_version candidate.to_macos_version <= tag_version
rescue MacOSVersionError rescue MacOSVersionError
false false
end end

View File

@ -2034,17 +2034,17 @@ class Formula
"root_url" => bottle_spec.root_url, "root_url" => bottle_spec.root_url,
"files" => {}, "files" => {},
} }
bottle_spec.collector.each_key do |os| bottle_spec.collector.each_tag do |tag|
collector_os = bottle_spec.collector[os] tag_spec = bottle_spec.collector.specification_for(tag)
os_cellar = collector_os[:cellar] os_cellar = tag_spec.cellar
os_cellar = os_cellar.inspect if os_cellar.is_a?(Symbol) os_cellar = os_cellar.inspect if os_cellar.is_a?(Symbol)
checksum = collector_os[:checksum].hexdigest checksum = tag_spec.checksum.hexdigest
filename = Bottle::Filename.create(self, os, bottle_spec.rebuild) filename = Bottle::Filename.create(self, tag, bottle_spec.rebuild)
path, = Utils::Bottles.path_resolved_basename(bottle_spec.root_url, name, checksum, filename) path, = Utils::Bottles.path_resolved_basename(bottle_spec.root_url, name, checksum, filename)
url = "#{bottle_spec.root_url}/#{path}" url = "#{bottle_spec.root_url}/#{path}"
hash["files"][os] = { hash["files"][tag.to_sym] = {
"cellar" => os_cellar, "cellar" => os_cellar,
"url" => url, "url" => url,
"sha256" => checksum, "sha256" => checksum,

View File

@ -150,13 +150,14 @@ class FormulaInstaller
return false return false
end end
bottle = formula.bottle_specification bottle = formula.bottle
unless bottle.compatible_locations? if bottle && !bottle.compatible_locations?
if output_warning if output_warning
prefix = Pathname(bottle.cellar).parent
opoo <<~EOS opoo <<~EOS
Building #{formula.full_name} from source as the bottle needs: Building #{formula.full_name} from source as the bottle needs:
- HOMEBREW_CELLAR: #{bottle.cellar} (yours is #{HOMEBREW_CELLAR}) - HOMEBREW_CELLAR: #{bottle.cellar} (yours is #{HOMEBREW_CELLAR})
- HOMEBREW_PREFIX: #{bottle.prefix} (yours is #{HOMEBREW_PREFIX}) - HOMEBREW_PREFIX: #{prefix} (yours is #{HOMEBREW_PREFIX})
EOS EOS
end end
return false return false

View File

@ -91,7 +91,7 @@ class SoftwareSpec
end end
def bottle_defined? def bottle_defined?
!bottle_specification.collector.keys.empty? !bottle_specification.collector.tags.empty?
end end
def bottle_tag?(tag = nil) def bottle_tag?(tag = nil)
@ -302,7 +302,7 @@ class Bottle
extend Forwardable extend Forwardable
attr_reader :name, :resource, :prefix, :cellar, :rebuild attr_reader :name, :resource, :cellar, :rebuild
def_delegators :resource, :url, :verify_download_integrity def_delegators :resource, :url, :verify_download_integrity
def_delegators :resource, :cached_download def_delegators :resource, :cached_download
@ -314,15 +314,14 @@ class Bottle
@resource.specs[:bottle] = true @resource.specs[:bottle] = true
@spec = spec @spec = spec
checksum, tag, cellar = spec.checksum_for(Utils::Bottles.tag(tag)) tag_spec = spec.tag_specification_for(Utils::Bottles.tag(tag))
@prefix = spec.prefix @tag = tag_spec.tag
@tag = tag @cellar = tag_spec.cellar
@cellar = cellar
@rebuild = spec.rebuild @rebuild = spec.rebuild
@resource.version = formula.pkg_version @resource.version = formula.pkg_version
@resource.checksum = checksum @resource.checksum = tag_spec.checksum
root_url(spec.root_url, spec.root_url_specs) root_url(spec.root_url, spec.root_url_specs)
end end
@ -342,12 +341,12 @@ class Bottle
end end
def compatible_locations? def compatible_locations?
@spec.compatible_locations? @spec.compatible_locations?(tag: @tag)
end end
# Does the bottle need to be relocated? # Does the bottle need to be relocated?
def skip_relocation? def skip_relocation?
@spec.skip_relocation? @spec.skip_relocation?(tag: @tag)
end end
def stage def stage
@ -469,12 +468,11 @@ class BottleSpecification
attr_rw :rebuild attr_rw :rebuild
attr_accessor :tap attr_accessor :tap
attr_reader :all_tags_cellar, :collector, :root_url_specs, :repository, :prefix attr_reader :collector, :root_url_specs, :repository
sig { void } sig { void }
def initialize def initialize
@rebuild = 0 @rebuild = 0
@prefix = Homebrew::DEFAULT_PREFIX
@repository = Homebrew::DEFAULT_REPOSITORY @repository = Homebrew::DEFAULT_REPOSITORY
@collector = Utils::Bottles::Collector.new @collector = Utils::Bottles::Collector.new
@root_url_specs = {} @root_url_specs = {}
@ -497,27 +495,26 @@ class BottleSpecification
end end
end end
def cellar(val = nil) def cellar(_val = nil)
if val.present?
odisabled( odisabled(
"`cellar` in a bottle block", "`cellar` in a bottle block",
"`brew style --fix` on the formula to update the style or use `sha256` with a `cellar:` argument", "`brew style --fix` on the formula to update the style or use `sha256` with a `cellar:` argument",
) )
end end
if val.nil? sig { params(tag: Utils::Bottles::Tag).returns(T::Boolean) }
return collector.dig(Utils::Bottles.tag.to_sym, :cellar) || @all_tags_cellar || Homebrew::DEFAULT_CELLAR def compatible_locations?(tag: Utils::Bottles.tag)
spec = collector.specification_for(tag)
cellar = if spec.present?
spec.cellar
else
tag.default_cellar
end end
@all_tags_cellar = val
end
def compatible_locations?
# this looks like it should check prefix and repository too but to be
# `cellar :any` actually requires no references to the cellar, prefix or
# repository.
return true if [:any, :any_skip_relocation].include?(cellar) return true if [:any, :any_skip_relocation].include?(cellar)
prefix = Pathname(cellar).parent.to_s
compatible_cellar = cellar == HOMEBREW_CELLAR.to_s compatible_cellar = cellar == HOMEBREW_CELLAR.to_s
compatible_prefix = prefix == HOMEBREW_PREFIX.to_s compatible_prefix = prefix == HOMEBREW_PREFIX.to_s
@ -525,14 +522,15 @@ class BottleSpecification
end end
# Does the {Bottle} this {BottleSpecification} belongs to need to be relocated? # Does the {Bottle} this {BottleSpecification} belongs to need to be relocated?
sig { returns(T::Boolean) } sig { params(tag: Utils::Bottles::Tag).returns(T::Boolean) }
def skip_relocation? def skip_relocation?(tag: Utils::Bottles.tag)
cellar == :any_skip_relocation spec = collector.specification_for(tag)
spec&.cellar == :any_skip_relocation
end end
sig { params(tag: T.any(Symbol, Utils::Bottles::Tag), no_older_versions: T::Boolean).returns(T::Boolean) } sig { params(tag: T.any(Symbol, Utils::Bottles::Tag), no_older_versions: T::Boolean).returns(T::Boolean) }
def tag?(tag, no_older_versions: false) def tag?(tag, no_older_versions: false)
checksum_for(tag, no_older_versions: no_older_versions) ? true : false collector.tag?(tag, no_older_versions: no_older_versions)
end end
# Checksum methods in the DSL's bottle block take # Checksum methods in the DSL's bottle block take
@ -569,40 +567,35 @@ class BottleSpecification
tag = Utils::Bottles::Tag.from_symbol(tag) tag = Utils::Bottles::Tag.from_symbol(tag)
cellar ||= all_tags_cellar
cellar ||= tag.default_cellar cellar ||= tag.default_cellar
collector[tag.to_sym] = { checksum: Checksum.new(digest), cellar: cellar } collector.add(tag, checksum: Checksum.new(digest), cellar: cellar)
end end
sig { sig {
params( params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean)
tag: T.any(Symbol, Utils::Bottles::Tag), .returns(T.nilable(Utils::Bottles::TagSpecification))
no_older_versions: T::Boolean,
).returns(
T.nilable([Checksum, Symbol, T.any(Symbol, String)]),
)
} }
def checksum_for(tag, no_older_versions: false) def tag_specification_for(tag, no_older_versions: false)
collector.fetch_checksum_for(tag, no_older_versions: no_older_versions) collector.specification_for(tag, no_older_versions: no_older_versions)
end end
def checksums def checksums
tags = collector.keys.sort_by do |sym| tags = collector.tags.sort_by do |tag|
tag = Utils::Bottles::Tag.from_symbol(sym)
version = tag.to_macos_version version = tag.to_macos_version
# Give arm64 bottles a higher priority so they are first # Give arm64 bottles a higher priority so they are first
priority = tag.arch == :arm64 ? "2" : "1" priority = tag.arch == :arm64 ? "2" : "1"
"#{priority}.#{version}_#{sym}" "#{priority}.#{version}_#{tag}"
rescue MacOSVersionError rescue MacOSVersionError
# Sort non-MacOS tags below MacOS tags. # Sort non-MacOS tags below MacOS tags.
"0.#{sym}" "0.#{tag}"
end end
tags.reverse.map do |tag| tags.reverse.map do |tag|
spec = collector.specification_for(tag)
{ {
"tag" => tag, "tag" => spec.tag.to_sym,
"digest" => collector[tag][:checksum], "digest" => spec.checksum,
"cellar" => collector[tag][:cellar], "cellar" => spec.cellar,
} }
end end
end end

View File

@ -386,7 +386,7 @@ describe "brew bottle" do
describe "#merge_bottle_spec" do describe "#merge_bottle_spec" do
it "allows new bottle hash to be empty" do it "allows new bottle hash to be empty" do
valid_keys = [:root_url, :prefix, :cellar, :rebuild, :sha256] valid_keys = [:root_url, :cellar, :rebuild, :sha256]
old_spec = BottleSpecification.new old_spec = BottleSpecification.new
old_spec.sha256(big_sur: "f59bc65c91e4e698f6f050e1efea0040f57372d4dcf0996cbb8f97ced320403b") old_spec.sha256(big_sur: "f59bc65c91e4e698f6f050e1efea0040f57372d4dcf0996cbb8f97ced320403b")
expect { homebrew.merge_bottle_spec(valid_keys, old_spec, {}) }.not_to raise_error expect { homebrew.merge_bottle_spec(valid_keys, old_spec, {}) }.not_to raise_error

View File

@ -17,8 +17,8 @@ describe BottleSpecification do
checksums.each_pair do |cat, digest| checksums.each_pair do |cat, digest|
bottle_spec.sha256(cat => digest) bottle_spec.sha256(cat => digest)
checksum, = bottle_spec.checksum_for(cat) tag_spec = bottle_spec.tag_specification_for(Utils::Bottles::Tag.from_symbol(cat))
expect(Checksum.new(digest)).to eq(checksum) expect(Checksum.new(digest)).to eq(tag_spec.checksum)
end end
end end
@ -32,11 +32,11 @@ describe BottleSpecification do
checksums.each do |checksum| checksums.each do |checksum|
bottle_spec.sha256(cellar: checksum[:cellar], checksum[:tag] => checksum[:digest]) bottle_spec.sha256(cellar: checksum[:cellar], checksum[:tag] => checksum[:digest])
digest, tag, cellar = bottle_spec.checksum_for(checksum[:tag]) tag_spec = bottle_spec.tag_specification_for(Utils::Bottles::Tag.from_symbol(checksum[:tag]))
expect(Checksum.new(checksum[:digest])).to eq(digest) expect(Checksum.new(checksum[:digest])).to eq(tag_spec.checksum)
expect(checksum[:tag]).to eq(tag) expect(checksum[:tag]).to eq(tag_spec.tag.to_sym)
checksum[:cellar] ||= Homebrew::DEFAULT_CELLAR checksum[:cellar] ||= Homebrew::DEFAULT_CELLAR
expect(checksum[:cellar]).to eq(cellar) expect(checksum[:cellar]).to eq(tag_spec.cellar)
end end
end end
end end

View File

@ -6,43 +6,50 @@ require "utils/bottles"
describe Utils::Bottles::Collector do describe Utils::Bottles::Collector do
subject(:collector) { described_class.new } subject(:collector) { described_class.new }
describe "#fetch_checksum_for" do let(:catalina) { Utils::Bottles::Tag.from_symbol(:catalina) }
let(:mojave) { Utils::Bottles::Tag.from_symbol(:mojave) }
describe "#specification_for" do
it "returns passed tags" do it "returns passed tags" do
collector[:mojave] = { checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar" } collector.add(mojave, checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar")
collector[:catalina] = { checksum: Checksum.new("bar_checksum"), cellar: "bar_cellar" } collector.add(catalina, checksum: Checksum.new("bar_checksum"), cellar: "bar_cellar")
expect(collector.fetch_checksum_for(:catalina)).to eq(["bar_checksum", :catalina, "bar_cellar"]) spec = collector.specification_for(catalina)
expect(spec).not_to be_nil
expect(spec.tag).to eq(catalina)
expect(spec.checksum).to eq("bar_checksum")
expect(spec.cellar).to eq("bar_cellar")
end end
it "returns nil if empty" do it "returns nil if empty" do
expect(collector.fetch_checksum_for(:foo)).to be nil expect(collector.specification_for(Utils::Bottles::Tag.from_symbol(:foo))).to be nil
end end
it "returns nil when there is no match" do it "returns nil when there is no match" do
collector[:catalina] = "foo" collector.add(catalina, checksum: Checksum.new("bar_checksum"), cellar: "bar_cellar")
expect(collector.fetch_checksum_for(:foo)).to be nil expect(collector.specification_for(Utils::Bottles::Tag.from_symbol(:foo))).to be nil
end end
it "uses older tags when needed", :needs_macos do it "uses older tags when needed", :needs_macos do
collector[:mojave] = "foo" collector.add(mojave, checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar")
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:mojave))).to eq(:mojave) expect(collector.send(:find_matching_tag, mojave)).to eq(mojave)
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:catalina))).to eq(:mojave) expect(collector.send(:find_matching_tag, catalina)).to eq(mojave)
end end
it "does not use older tags when requested not to", :needs_macos do it "does not use older tags when requested not to", :needs_macos do
allow(Homebrew::EnvConfig).to receive(:developer?).and_return(true) allow(Homebrew::EnvConfig).to receive(:developer?).and_return(true)
allow(Homebrew::EnvConfig).to receive(:skip_or_later_bottles?).and_return(true) allow(Homebrew::EnvConfig).to receive(:skip_or_later_bottles?).and_return(true)
allow(OS::Mac.version).to receive(:prerelease?).and_return(true) allow(OS::Mac.version).to receive(:prerelease?).and_return(true)
collector[:mojave] = "foo" collector.add(mojave, checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar")
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:mojave))).to eq(:mojave) expect(collector.send(:find_matching_tag, mojave)).to eq(mojave)
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:catalina))).to be_nil expect(collector.send(:find_matching_tag, catalina)).to be_nil
end end
it "ignores HOMEBREW_SKIP_OR_LATER_BOTTLES on release versions", :needs_macos do it "ignores HOMEBREW_SKIP_OR_LATER_BOTTLES on release versions", :needs_macos do
allow(Homebrew::EnvConfig).to receive(:skip_or_later_bottles?).and_return(true) allow(Homebrew::EnvConfig).to receive(:skip_or_later_bottles?).and_return(true)
allow(OS::Mac.version).to receive(:prerelease?).and_return(false) allow(OS::Mac.version).to receive(:prerelease?).and_return(false)
collector[:mojave] = "foo" collector.add(mojave, checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar")
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:mojave))).to eq(:mojave) expect(collector.send(:find_matching_tag, mojave)).to eq(mojave)
expect(collector.send(:find_matching_tag, Utils::Bottles::Tag.from_symbol(:catalina))).to eq(:mojave) expect(collector.send(:find_matching_tag, catalina)).to eq(mojave)
end end
end end
end end

View File

@ -11,6 +11,7 @@ module Utils
class << self class << self
extend T::Sig extend T::Sig
# Gets the tag for the running OS.
def tag(symbol = nil) def tag(symbol = nil)
return Tag.from_symbol(symbol) if symbol.present? return Tag.from_symbol(symbol) if symbol.present?
@ -160,6 +161,14 @@ module Utils
end end
end end
def eql?(other)
self.class == other.class && self == other
end
def hash
[system, arch].hash
end
sig { returns(Symbol) } sig { returns(Symbol) }
def to_sym def to_sym
if system == :all && arch == :all if system == :all && arch == :all
@ -217,40 +226,74 @@ module Utils
end end
end end
# The specification for a specific tag
class TagSpecification
extend T::Sig
sig { returns(Utils::Bottles::Tag) }
attr_reader :tag
sig { returns(Checksum) }
attr_reader :checksum
sig { returns(T.any(Symbol, String)) }
attr_reader :cellar
def initialize(tag:, checksum:, cellar:)
@tag = tag
@checksum = checksum
@cellar = cellar
end
end
# Collector for bottle specifications. # Collector for bottle specifications.
class Collector class Collector
extend T::Sig extend T::Sig
extend Forwardable
def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key, :dig
sig { void } sig { void }
def initialize def initialize
@checksums = {} @tag_specs = T.let({}, T::Hash[Utils::Bottles::Tag, Utils::Bottles::TagSpecification])
end
sig { returns(T::Array[Utils::Bottles::Tag]) }
def tags
@tag_specs.keys
end
sig { params(tag: Utils::Bottles::Tag, checksum: Checksum, cellar: T.any(Symbol, String)).void }
def add(tag, checksum:, cellar:)
spec = Utils::Bottles::TagSpecification.new(tag: tag, checksum: checksum, cellar: cellar)
@tag_specs[tag] = spec
end
sig { params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean).returns(T::Boolean) }
def tag?(tag, no_older_versions: false)
tag = find_matching_tag(tag, no_older_versions: no_older_versions)
tag.present?
end
sig { params(block: T.proc.params(tag: Utils::Bottles::Tag).void).void }
def each_tag(&block)
@tag_specs.each_key(&block)
end end
sig { sig {
params( params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean)
tag: T.any(Symbol, Utils::Bottles::Tag), .returns(T.nilable(Utils::Bottles::TagSpecification))
no_older_versions: T::Boolean,
).returns(
T.nilable([Checksum, Symbol, T.any(Symbol, String)]),
)
} }
def fetch_checksum_for(tag, no_older_versions: false) def specification_for(tag, no_older_versions: false)
tag = Utils::Bottles::Tag.from_symbol(tag) if tag.is_a?(Symbol) tag = find_matching_tag(tag, no_older_versions: no_older_versions)
tag = find_matching_tag(tag, no_older_versions: no_older_versions)&.to_sym @tag_specs[tag] if tag
return self[tag][:checksum], tag, self[tag][:cellar] if tag
end end
private private
def find_matching_tag(tag, no_older_versions: false) def find_matching_tag(tag, no_older_versions: false)
if key?(tag.to_sym) if @tag_specs.key?(tag)
tag tag
elsif key?(:all) else
Tag.from_symbol(:all) all = Tag.from_symbol(:all)
all if @tag_specs.key?(all)
end end
end end
end end