Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bottle: tag specific cellars #10186

Merged
merged 1 commit into from Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Library/Homebrew/dev-cmd/bottle.rb
Expand Up @@ -553,7 +553,7 @@ def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash)
return [mismatches, checksums] if old_keys.exclude? :sha256

old_bottle_spec.collector.each_key do |tag|
old_value = old_bottle_spec.collector[tag].hexdigest
old_value = old_bottle_spec.collector[tag][:checksum].hexdigest
new_value = new_bottle_hash.dig("tags", tag.to_s)
if new_value.present?
mismatches << "sha256 => #{tag}"
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/formula.rb
Expand Up @@ -1831,7 +1831,7 @@ def to_hash
bottle_info["files"] = {}
bottle_spec.collector.each_key do |os|
bottle_url = "#{bottle_spec.root_url}/#{Bottle::Filename.create(self, os, bottle_spec.rebuild).bintray}"
checksum = bottle_spec.collector[os]
checksum = bottle_spec.collector[os][:checksum]
bottle_info["files"][os] = {
"url" => bottle_url,
"sha256" => checksum.hexdigest,
Expand Down
46 changes: 33 additions & 13 deletions Library/Homebrew/software_spec.rb
Expand Up @@ -302,15 +302,15 @@ def initialize(formula, spec)
@resource.specs[:bottle] = true
@spec = spec

checksum, tag = spec.checksum_for(Utils::Bottles.tag)
checksum, tag, cellar = spec.checksum_for(Utils::Bottles.tag)

filename = Filename.create(formula, tag, spec.rebuild)
@resource.url("#{spec.root_url}/#{filename.bintray}",
select_download_strategy(spec.root_url_specs))
@resource.version = formula.pkg_version
@resource.checksum = checksum
@prefix = spec.prefix
@cellar = spec.cellar
@cellar = cellar
@rebuild = spec.rebuild
end

Expand Down Expand Up @@ -338,15 +338,15 @@ def select_download_strategy(specs)
class BottleSpecification
extend T::Sig

attr_rw :prefix, :cellar, :rebuild
attr_rw :prefix, :rebuild
attr_accessor :tap
attr_reader :checksum, :collector, :root_url_specs, :repository
attr_reader :all_tags_cellar, :checksum, :collector, :root_url_specs, :repository

sig { void }
def initialize
@rebuild = 0
@prefix = Homebrew::DEFAULT_PREFIX
@cellar = Homebrew::DEFAULT_CELLAR
@all_tags_cellar = Homebrew::DEFAULT_CELLAR
iMichka marked this conversation as resolved.
Show resolved Hide resolved
@repository = Homebrew::DEFAULT_REPOSITORY
@collector = Utils::Bottles::Collector.new
@root_url_specs = {}
Expand All @@ -370,6 +370,12 @@ def root_url(var = nil, specs = {})
end
end

def cellar(val = nil)
return collector.dig(Utils::Bottles.tag, :cellar) || @all_tags_cellar if val.nil?

@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
Expand Down Expand Up @@ -398,17 +404,30 @@ def skip_relocation?
cellar == :any_skip_relocation
end

sig { params(tag: Symbol).returns(T::Boolean) }
def tag?(tag)
checksum_for(tag) ? true : false
end

# Checksum methods in the DSL's bottle block optionally take
# Checksum methods in the DSL's bottle block take
# a Hash, which indicates the platform the checksum applies on.
def sha256(val)
digest, tag = val.shift
collector[tag] = Checksum.new(digest)
# Example bottle block syntax:
# bottle do
# sha256 "69489ae397e4645..." => :big_sur, :cellar => :any_skip_relocation
# sha256 "449de5ea35d0e94..." => :catalina, :cellar => :any
# end
# Example args:
# {"69489ae397e4645..."=> :big_sur, :cellar=>:any_skip_relocation}
def sha256(hash)
sha256_regex = /^[a-f0-9]{64}$/i
digest, tag = hash.find do |key, value|
key.is_a?(String) && value.is_a?(Symbol) && key.match?(sha256_regex)
end
cellar = hash[:cellar] || all_tags_cellar
collector[tag] = { checksum: Checksum.new(digest), cellar: cellar }
end

sig { params(tag: Symbol).returns(T.nilable([Checksum, Symbol, T.any(Symbol, String)])) }
def checksum_for(tag)
collector.fetch_checksum_for(tag)
end
Expand All @@ -420,10 +439,11 @@ def checksums
# Sort non-MacOS tags below MacOS tags.
"0.#{tag}"
end
sha256s = []
tags.reverse_each do |tag|
checksum = collector[tag]
sha256s << { checksum => tag }
sha256s = tags.reverse.map do |tag|
{
collector[tag][:checksum] => tag,
cellar: collector[tag][:cellar],
}
end
{ sha256: sha256s }
end
Expand Down
44 changes: 31 additions & 13 deletions Library/Homebrew/test/formula_installer_bottle_spec.rb
Expand Up @@ -8,6 +8,7 @@
require "cmd/install"
require "test/support/fixtures/testball"
require "test/support/fixtures/testball_bottle"
require "test/support/fixtures/testball_bottle_cellar"

describe FormulaInstaller do
alias_matcher :pour_bottle, :be_pour_bottle
Expand Down Expand Up @@ -49,26 +50,43 @@ def temporarily_install_bottle(formula)
expect(formula).not_to be_latest_version_installed
end

def test_basic_formula_setup(f)
# Test that things made it into the Keg
expect(f.bin).to be_a_directory

expect(f.libexec).to be_a_directory

expect(f.prefix/"main.c").not_to exist

# Test that things made it into the Cellar
keg = Keg.new f.prefix
keg.link

bin = HOMEBREW_PREFIX/"bin"
expect(bin).to be_a_directory

expect(f.libexec).to be_a_directory
end

specify "basic bottle install" do
allow(DevelopmentTools).to receive(:installed?).and_return(false)
Homebrew.install_args.parse(["testball_bottle"])
temporarily_install_bottle(TestballBottle.new) do |f|
# Copied directly from formula_installer_spec.rb
# as we expect the same behavior.

# Test that things made it into the Keg
expect(f.bin).to be_a_directory

expect(f.libexec).to be_a_directory
test_basic_formula_setup(f)
end
end

expect(f.prefix/"main.c").not_to exist
specify "basic bottle install with cellar information on sha256 line" do
allow(DevelopmentTools).to receive(:installed?).and_return(false)
Homebrew.install_args.parse(["testball_bottle_cellar"])
temporarily_install_bottle(TestballBottleCellar.new) do |f|
test_basic_formula_setup(f)

# Test that things made it into the Cellar
keg = Keg.new f.prefix
keg.link
# skip_relocation is always false on Linux but can be true on macOS.
# see: extend/os/linux/software_spec.rb
skip_relocation = !OS.linux?

bin = HOMEBREW_PREFIX/"bin"
expect(bin).to be_a_directory
expect(f.bottle_specification.skip_relocation?).to eq(skip_relocation)
end
end

Expand Down
44 changes: 32 additions & 12 deletions Library/Homebrew/test/software_spec_spec.rb
Expand Up @@ -183,18 +183,38 @@
end

describe BottleSpecification do
specify "#sha256" do
checksums = {
snow_leopard_32: "deadbeef" * 8,
snow_leopard: "faceb00c" * 8,
lion: "baadf00d" * 8,
mountain_lion: "8badf00d" * 8,
}

checksums.each_pair do |cat, digest|
subject.sha256(digest => cat)
checksum, = subject.checksum_for(cat)
expect(Checksum.new(digest)).to eq(checksum)
describe "#sha256" do
it "works without cellar" do
checksums = {
snow_leopard_32: "deadbeef" * 8,
snow_leopard: "faceb00c" * 8,
lion: "baadf00d" * 8,
mountain_lion: "8badf00d" * 8,
}

checksums.each_pair do |cat, digest|
subject.sha256(digest => cat)
checksum, = subject.checksum_for(cat)
expect(Checksum.new(digest)).to eq(checksum)
end
end

it "works with cellar" do
checksums = [
{ digest: "deadbeef" * 8, tag: :snow_leopard_32, cellar: :any_skip_relocation },
{ digest: "faceb00c" * 8, tag: :snow_leopard, cellar: :any },
{ digest: "baadf00d" * 8, tag: :lion, cellar: "/usr/local/Cellar" },
{ digest: "8badf00d" * 8, tag: :mountain_lion, cellar: Homebrew::DEFAULT_CELLAR },
]

checksums.each do |checksum|
subject.sha256(checksum[:digest] => checksum[:tag], cellar: checksum[:cellar])
digest, tag, cellar = subject.checksum_for(checksum[:tag])
expect(Checksum.new(checksum[:digest])).to eq(digest)
expect(checksum[:tag]).to eq(tag)
checksum[:cellar] ||= Homebrew::DEFAULT_CELLAR
expect(checksum[:cellar]).to eq(cellar)
end
end
end

Expand Down
24 changes: 24 additions & 0 deletions Library/Homebrew/test/support/fixtures/testball_bottle_cellar.rb
@@ -0,0 +1,24 @@
# typed: true
# frozen_string_literal: true

class TestballBottleCellar < Formula
def initialize(name = "testball_bottle", path = Pathname.new(__FILE__).expand_path, spec = :stable,
alias_path: nil, force_bottle: false)
self.class.instance_eval do
stable.url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz"
stable.sha256 TESTBALL_SHA256
hexdigest = "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
stable.bottle do
root_url "file://#{TEST_FIXTURE_DIR}/bottles"
sha256 hexdigest => Utils::Bottles.tag, :cellar => :any_skip_relocation
end
cxxstdlib_check :skip
end
super
end

def install
prefix.install "bin"
prefix.install "libexec"
end
end
6 changes: 3 additions & 3 deletions Library/Homebrew/test/utils/bottles/collector_spec.rb
Expand Up @@ -8,9 +8,9 @@

describe "#fetch_checksum_for" do
it "returns passed tags" do
collector[:mojave] = "foo"
collector[:catalina] = "bar"
expect(collector.fetch_checksum_for(:catalina)).to eq(["bar", :catalina])
collector[:mojave] = { checksum: Checksum.new("foo_checksum"), cellar: "foo_cellar" }
collector[:catalina] = { checksum: Checksum.new("bar_checksum"), cellar: "bar_cellar" }
expect(collector.fetch_checksum_for(:catalina)).to eq(["bar_checksum", :catalina, "bar_cellar"])
end

it "returns nil if empty" do
Expand Down
5 changes: 3 additions & 2 deletions Library/Homebrew/utils/bottles.rb
Expand Up @@ -100,16 +100,17 @@ class Collector

extend Forwardable

def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key
def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key, :dig

sig { void }
def initialize
@checksums = {}
end

sig { params(tag: Symbol).returns(T.nilable([Checksum, Symbol, T.any(Symbol, String)])) }
def fetch_checksum_for(tag)
tag = find_matching_tag(tag)
return self[tag], tag if tag
return self[tag][:checksum], tag, self[tag][:cellar] if tag
end

private
Expand Down