diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 0bf317e76c..1b8279c2dd 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -339,7 +339,7 @@ module Homebrew end end - _, _, bottle_cellar = Formula[f.name].bottle_specification.checksum_for(bottle_tag, exact: true) + _, _, bottle_cellar = Formula[f.name].bottle_specification.checksum_for(bottle_tag, no_older_versions: true) relocatable = [:any, :any_skip_relocation].include?(bottle_cellar) skip_relocation = bottle_cellar == :any_skip_relocation @@ -579,6 +579,12 @@ module Homebrew def merge(args:) bottles_hash = merge_json_files(parse_json_files(args.named)) + # TODO: deduplicate --no-json bottles by: + # 1. throwing away bottles for newer versions of macOS if their SHA256 is + # identical + # 2. generating `all: $SHA256` bottles that can be used on macOS and Linux + # i.e. need to be `any_skip_relocation` and contain no ELF/MachO files. + any_cellars = ["any", "any_skip_relocation"] bottles_hash.each do |formula_name, bottle_hash| ohai formula_name diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index d7bf41554c..9966a748e2 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -158,7 +158,7 @@ module Homebrew formulae.each do |f| name = f.name.downcase - if f.bottle_specification.tag?(@bottle_tag, exact: true) + if f.bottle_specification.tag?(@bottle_tag, no_older_versions: true) puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: already bottled" if any_named_args next end diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 03a302a0ca..b27a934194 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -16,10 +16,10 @@ module Utils alias generic_find_matching_tag find_matching_tag - def find_matching_tag(tag, exact: false) + def find_matching_tag(tag, no_older_versions: false) # Used primarily by developers testing beta macOS releases. - if exact || (OS::Mac.prerelease? && Homebrew::EnvConfig.developer? && - Homebrew::EnvConfig.skip_or_later_bottles?) + if no_older_versions || + (OS::Mac.prerelease? && Homebrew::EnvConfig.developer? && Homebrew::EnvConfig.skip_or_later_bottles?) generic_find_matching_tag(tag) else generic_find_matching_tag(tag) || diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 6c6da77d32..03323328b8 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -485,9 +485,9 @@ class BottleSpecification cellar == :any_skip_relocation end - sig { params(tag: T.any(Symbol, Utils::Bottles::Tag), exact: T::Boolean).returns(T::Boolean) } - def tag?(tag, exact: false) - checksum_for(tag, exact: exact) ? true : false + sig { params(tag: T.any(Symbol, Utils::Bottles::Tag), no_older_versions: T::Boolean).returns(T::Boolean) } + def tag?(tag, no_older_versions: false) + checksum_for(tag, no_older_versions: no_older_versions) ? true : false end # Checksum methods in the DSL's bottle block take @@ -532,14 +532,14 @@ class BottleSpecification sig { params( - tag: T.any(Symbol, Utils::Bottles::Tag), - exact: T::Boolean, + tag: T.any(Symbol, Utils::Bottles::Tag), + no_older_versions: T::Boolean, ).returns( T.nilable([Checksum, Symbol, T.any(Symbol, String)]), ) } - def checksum_for(tag, exact: false) - collector.fetch_checksum_for(tag, exact: exact) + def checksum_for(tag, no_older_versions: false) + collector.fetch_checksum_for(tag, no_older_versions: no_older_versions) end def checksums diff --git a/Library/Homebrew/test/dev-cmd/bottle_spec.rb b/Library/Homebrew/test/dev-cmd/bottle_spec.rb index eed8931c9e..40ef2ed4f7 100644 --- a/Library/Homebrew/test/dev-cmd/bottle_spec.rb +++ b/Library/Homebrew/test/dev-cmd/bottle_spec.rb @@ -493,37 +493,43 @@ describe "brew bottle" do end end - specify "::merge_json_files" do - bottles_hash = homebrew.merge_json_files( - [hello_hash_big_sur, hello_hash_catalina, unzip_hash_big_sur, unzip_hash_catalina], - ) + describe "::merge_json_files" do + it "merges JSON files" do + bottles_hash = homebrew.merge_json_files( + [hello_hash_big_sur, hello_hash_catalina, unzip_hash_big_sur, unzip_hash_catalina], + ) - hello_hash = bottles_hash["hello"] - expect(hello_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation") - expect(hello_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("hello-1.0.big_sur.bottle.tar.gz") - expect(hello_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("hello--1.0.big_sur.bottle.tar.gz") - expect(hello_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq( - "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f", - ) - expect(hello_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any_skip_relocation") - expect(hello_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("hello-1.0.catalina.bottle.tar.gz") - expect(hello_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("hello--1.0.catalina.bottle.tar.gz") - expect(hello_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq( - "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac", - ) - unzip_hash = bottles_hash["unzip"] - expect(unzip_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation") - expect(unzip_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("unzip-2.0.big_sur.bottle.tar.gz") - expect(unzip_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("unzip--2.0.big_sur.bottle.tar.gz") - expect(unzip_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq( - "16cf230afdfcb6306c208d169549cf8773c831c8653d2c852315a048960d7e72", - ) - expect(unzip_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any") - expect(unzip_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("unzip-2.0.catalina.bottle.tar.gz") - expect(unzip_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("unzip--2.0.catalina.bottle.tar.gz") - expect(unzip_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq( - "d9cc50eec8ac243148a121049c236cba06af4a0b1156ab397d0a2850aa79c137", - ) + hello_hash = bottles_hash["hello"] + expect(hello_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation") + expect(hello_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("hello-1.0.big_sur.bottle.tar.gz") + expect(hello_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("hello--1.0.big_sur.bottle.tar.gz") + expect(hello_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq( + "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f", + ) + expect(hello_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any_skip_relocation") + expect(hello_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("hello-1.0.catalina.bottle.tar.gz") + expect(hello_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("hello--1.0.catalina.bottle.tar.gz") + expect(hello_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq( + "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac", + ) + unzip_hash = bottles_hash["unzip"] + expect(unzip_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation") + expect(unzip_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("unzip-2.0.big_sur.bottle.tar.gz") + expect(unzip_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("unzip--2.0.big_sur.bottle.tar.gz") + expect(unzip_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq( + "16cf230afdfcb6306c208d169549cf8773c831c8653d2c852315a048960d7e72", + ) + expect(unzip_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any") + expect(unzip_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("unzip-2.0.catalina.bottle.tar.gz") + expect(unzip_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("unzip--2.0.catalina.bottle.tar.gz") + expect(unzip_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq( + "d9cc50eec8ac243148a121049c236cba06af4a0b1156ab397d0a2850aa79c137", + ) + end + + # TODO: add deduplication tests e.g. + # it "deduplicates JSON files with matching macOS checksums" + # it "deduplicates JSON files with matching OS checksums" do end describe "#merge_bottle_spec" do diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index adcf14a0f3..4b13056151 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -87,6 +87,8 @@ module Utils sig { params(value: Symbol).returns(T.attached_class) } def self.from_symbol(value) + return new(system: :all, arch: :all) if value == :all + @all_archs_regex ||= begin all_archs = Hardware::CPU::ALL_ARCHS.map(&:to_s) / @@ -118,7 +120,9 @@ module Utils sig { returns(Symbol) } def to_sym - if macos? && arch == :x86_64 + if system == :all && arch == :all + :all + elsif macos? && arch == :x86_64 system else "#{arch}_#{system}".to_sym @@ -204,22 +208,26 @@ module Utils sig { params( - tag: T.any(Symbol, Utils::Bottles::Tag), - exact: T::Boolean, + tag: T.any(Symbol, Utils::Bottles::Tag), + no_older_versions: T::Boolean, ).returns( T.nilable([Checksum, Symbol, T.any(Symbol, String)]), ) } - def fetch_checksum_for(tag, exact: false) + def fetch_checksum_for(tag, no_older_versions: false) tag = Utils::Bottles::Tag.from_symbol(tag) if tag.is_a?(Symbol) - tag = find_matching_tag(tag, exact: exact)&.to_sym + tag = find_matching_tag(tag, no_older_versions: no_older_versions)&.to_sym return self[tag][:checksum], tag, self[tag][:cellar] if tag end private - def find_matching_tag(tag, exact: false) - tag if key?(tag.to_sym) + def find_matching_tag(tag, no_older_versions: false) + if key?(tag.to_sym) + tag + elsif key?(:all) + Tag.from_symbol(:all) + end end end end