diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index b6ce4a8ca6..7ef29695ee 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -88,6 +88,7 @@ module Homebrew fetched_bottle = false if fetch_bottle?(f, args: args) begin + f.fetch_bottle_tab fetch_formula(f.bottle, args: args) rescue Interrupt raise diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index bd4d1dd6da..bd49409185 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -2211,6 +2211,20 @@ class Formula patchlist.select(&:external?).each(&:fetch) end + sig { void } + def fetch_bottle_tab + return unless bottled? + + T.must(bottle).fetch_tab + end + + sig { returns(Hash) } + def bottle_tab_attributes + return {} unless bottled? + + T.must(bottle).tab_attributes + end + private def prepare_patches diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index d09970819c..67fd981421 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1100,7 +1100,9 @@ class FormulaInstaller return if only_deps? - unless pour_bottle?(output_warning: true) + if pour_bottle?(output_warning: true) + formula.fetch_bottle_tab + else formula.fetch_patches formula.resources.each(&:fetch) end @@ -1124,14 +1126,17 @@ class FormulaInstaller end keg = Keg.new(formula.prefix) - tab = Tab.for_keg(keg) Tab.clear_cache + tab = if (tab_attributes = formula.bottle_tab_attributes.presence) + Tab.from_file_content(tab_attributes.to_json, keg/Tab::FILENAME) + else + Tab.for_keg(keg) + end + skip_linkage = formula.bottle_specification.skip_relocation? keg.replace_placeholders_with_locations tab.changed_files, skip_linkage: skip_linkage - tab = Tab.for_keg(keg) - unless ignore_deps? CxxStdlib.check_compatibility( formula, formula.recursive_dependencies, diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 6d8c123bfb..1cf353a6f1 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -348,8 +348,62 @@ class Bottle resource.downloader.stage end + def fetch_tab + # a checksum is used later identifying the correct tab but we do not have the checksum for the manifest/tab + github_packages_manifest_resource&.fetch(verify_download_integrity: false) + end + + def tab_attributes + return {} unless github_packages_manifest_resource&.downloaded? + + manifest_json = github_packages_manifest_resource.cached_download.read + + json = begin + JSON.parse(manifest_json) + rescue JSON::ParserError + raise ArgumentError, "Couldn't parse manifest JSON." + end + + manifests = json["manifests"] + raise ArgumentError, "Missing 'manifests' section." if manifests.blank? + + manifests_annotations = manifests.map { |m| m["annotations"] } + raise ArgumentError, "Missing 'annotations' section." if manifests_annotations.blank? + + bottle_checksum = @resource.checksum.hexdigest + manifest_annotations = manifests_annotations.find do |m| + m["sh.brew.bottle.checksum"] == bottle_checksum + end + raise ArgumentError, "Couldn't find manifest matching bottle checksum." if manifest_annotations.blank? + + tab = manifest_annotations["sh.brew.tab"] + raise ArgumentError, "Couldn't find tab from manifest." if tab.blank? + + begin + JSON.parse(tab) + rescue JSON::ParserError + raise ArgumentError, "Couldn't parse tab JSON." + end + end + private + def github_packages_manifest_resource + return if @resource.download_strategy != CurlGitHubPackagesDownloadStrategy + + @github_packages_manifest_resource ||= begin + resource = Resource.new("#{name}_bottle_manifest") + + version_rebuild = GitHubPackages.version_rebuild(@resource.version, rebuild) + resource.version(version_rebuild) + + resource.url("#{@spec.root_url}/#{name}/manifests/#{version_rebuild}", + using: CurlGitHubPackagesDownloadStrategy) + resource.downloader.resolved_basename = "#{name}-#{version_rebuild}.bottle_manifest.json" + resource + end + end + def select_download_strategy(specs) specs[:using] ||= DownloadStrategyDetector.detect(@spec.root_url) specs