diff --git a/Library/Homebrew/dev-cmd/generate-formula-api.rb b/Library/Homebrew/dev-cmd/generate-formula-api.rb index a9afe47ee7..747f838e17 100644 --- a/Library/Homebrew/dev-cmd/generate-formula-api.rb +++ b/Library/Homebrew/dev-cmd/generate-formula-api.rb @@ -75,8 +75,7 @@ module Homebrew version = Version.new(formula.dig("versions", "stable")) pkg_version = PkgVersion.new(version, formula["revision"]) rebuild = formula.dig("bottle", "stable", "rebuild") || 0 - sha256 = formula.dig("bottle", "stable", "files", :all, "sha256") - sha256 ||= formula.dig("bottle", "stable", "files", bottle_tag.to_sym, "sha256") + sha256 = newest_bottle_sha256(formula, bottle_tag) [name, [pkg_version.to_s, rebuild, sha256]] end @@ -88,6 +87,35 @@ module Homebrew end end + sig { + params(formula_json: T::Hash[String, T.untyped], bottle_tag: Utils::Bottles::Tag).returns(T.nilable(String)) + } + def newest_bottle_sha256(formula_json, bottle_tag) + available_tags = formula_json.dig("bottle", "stable", "files")&.keys&.map(&:to_sym) + return unless available_tags + + return formula_json.dig("bottle", "stable", "files", :all, "sha256") if available_tags.include? :all + + if available_tags.include? bottle_tag.to_sym + return formula_json.dig("bottle", "stable", "files", bottle_tag.to_sym, "sha256") + end + + return unless bottle_tag.macos? + + # If the actual tag is not available, find the newest tag with matching arch that's older than the actual tag + newest_viable_macos_tag = available_tags.filter_map do |tag_sym| + tag = Utils::Bottles::Tag.from_symbol(tag_sym) + next unless tag.macos? + next if tag.arch != bottle_tag.arch + next if tag.to_macos_version > bottle_tag.to_macos_version + + tag + end.max_by(&:to_macos_version) + return unless newest_viable_macos_tag + + formula_json.dig("bottle", "stable", "files", newest_viable_macos_tag.to_sym, "sha256") + end + private sig { params(title: String).returns(String) } diff --git a/Library/Homebrew/test/dev-cmd/generate-formula-api_spec.rb b/Library/Homebrew/test/dev-cmd/generate-formula-api_spec.rb index 74136d6645..675d937ed7 100644 --- a/Library/Homebrew/test/dev-cmd/generate-formula-api_spec.rb +++ b/Library/Homebrew/test/dev-cmd/generate-formula-api_spec.rb @@ -5,4 +5,58 @@ require "dev-cmd/generate-formula-api" RSpec.describe Homebrew::DevCmd::GenerateFormulaApi do it_behaves_like "parseable arguments" + + describe "#newest_bottle_sha256" do + subject(:generate_formula_api) { described_class.new [] } + + def make_json(bottles) + json = { + "bottle" => { + "stable" => { + "files" => {}, + }, + }, + } + bottles.each do |tag, sha256| + json["bottle"]["stable"]["files"][tag] = { "sha256" => sha256 } + end + json + end + + expected_sha256s = { + arm64_sequoia: "abc123", + arm64_sonoma: "abc123", + arm64_ventura: "ghi789", + arm64_monterey: nil, + sequoia: "jkl012", + sonoma: "jkl012", + ventura: "mno345", + monterey: "mno345", + x86_64_linux: "pqr678", + arm64_linux: nil, + }.transform_keys do |tag| + Utils::Bottles::Tag.from_symbol(tag) + end + + let(:all_json) { make_json all: "abc123" } + let(:standard_json) do + make_json arm64_sonoma: "abc123", + arm64_ventura: "ghi789", + sonoma: "jkl012", + big_sur: "mno345", + x86_64_linux: "pqr678" + end + + it "returns the sha256 for the :all tag on all systems" do + expected_sha256s.each_key do |tag| + expect(generate_formula_api.newest_bottle_sha256(all_json, tag)).to eq("abc123") + end + end + + expected_sha256s.each_key do |tag| + it "returns the corrent sha256 for #{tag}" do + expect(generate_formula_api.newest_bottle_sha256(standard_json, tag)).to eq(expected_sha256s[tag]) + end + end + end end