diff --git a/Library/Homebrew/api.rb b/Library/Homebrew/api.rb index ef06312bff..4b154f4432 100644 --- a/Library/Homebrew/api.rb +++ b/Library/Homebrew/api.rb @@ -116,11 +116,13 @@ module Homebrew end end - sig { params(name: String, git_head: T.nilable(String), sha256: T.nilable(String)).returns(String) } - def self.fetch_homebrew_cask_source(name, git_head: nil, sha256: nil) + sig { + params(name: String, path: T.any(Pathname, String), git_head: String, + sha256: T.nilable(String)).returns(String) + } + def self.fetch_homebrew_cask_source(name, path:, git_head:, sha256: nil) # TODO: unify with formula logic (https://github.com/Homebrew/brew/issues/14746) - git_head = "master" if git_head.blank? - raw_endpoint = "#{git_head}/Casks/#{name}.rb" + raw_endpoint = "#{git_head}/#{path}" return cache[raw_endpoint] if cache.present? && cache.key?(raw_endpoint) # This API sometimes returns random 404s so needs a fallback at formulae.brew.sh. diff --git a/Library/Homebrew/api/cask.rb b/Library/Homebrew/api/cask.rb index ccec8f083e..32be78af09 100644 --- a/Library/Homebrew/api/cask.rb +++ b/Library/Homebrew/api/cask.rb @@ -20,9 +20,12 @@ module Homebrew Homebrew::API.fetch "cask/#{token}.json" end - sig { params(token: String, git_head: T.nilable(String), sha256: T.nilable(String)).returns(String) } - def fetch_source(token, git_head: nil, sha256: nil) - Homebrew::API.fetch_homebrew_cask_source token, git_head: git_head, sha256: sha256 + sig { + params(token: String, path: T.any(String, Pathname), git_head: String, + sha256: T.nilable(String)).returns(String) + } + def fetch_source(token, path:, git_head:, sha256: nil) + Homebrew::API.fetch_homebrew_cask_source token, path: path, git_head: git_head, sha256: sha256 end sig { returns(T::Boolean) } diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index e2597c98b5..c2924025a3 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -241,6 +241,15 @@ module Cask end end + def ruby_source_path + return @ruby_source_path if defined?(@ruby_source_path) + + return unless sourcefile_path + return unless tap + + @ruby_source_path = sourcefile_path.relative_path_from(tap.path) + end + def ruby_source_checksum @ruby_source_checksum ||= { "sha256" => Digest::SHA256.file(sourcefile_path).hexdigest, @@ -259,7 +268,9 @@ module Cask raise ArgumentError, "Expected cask to be loaded from the API" unless loaded_from_api? @languages = json_cask[:languages] - @tap_git_head = json_cask[:tap_git_head] + @tap_git_head = json_cask.fetch(:tap_git_head, "HEAD") + + @ruby_source_path = json_cask[:ruby_source_path] @ruby_source_checksum = json_cask[:ruby_source_checksum].freeze end @@ -308,6 +319,7 @@ module Cask "auto_updates" => auto_updates, "tap_git_head" => tap_git_head, "languages" => languages, + "ruby_source_path" => ruby_source_path, "ruby_source_checksum" => ruby_source_checksum, } end diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index e5d7ea2559..1321e8b32e 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -564,8 +564,12 @@ on_request: true) end def load_cask_from_source_api! - options = { git_head: @cask.tap_git_head, sha256: @cask.ruby_source_checksum["sha256"] } - cask_source = Homebrew::API::Cask.fetch_source(@cask.token, **options) + cask_source = Homebrew::API::Cask.fetch_source( + @cask.token, + path: @cask.ruby_source_path || "Casks/#{@cask.token}.rb", + git_head: @cask.tap_git_head, + sha256: @cask.ruby_source_checksum["sha256"], + ) @cask = CaskLoader::FromContentLoader.new(cask_source, tap: @cask.tap).load(config: @cask.config) end end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 6b73e7127c..0e4feeb1c6 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -2199,6 +2199,7 @@ class Formula "sha256" => resource("ruby-source").checksum.hexdigest, } elsif !self.class.loaded_from_api && path.exist? + hsh["ruby_source_path"] = path.relative_path_from(tap.path).to_s hsh["ruby_source_checksum"] = { "sha256" => Digest::SHA256.file(path).hexdigest, } diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 6724e6db7e..349b5b5041 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -255,10 +255,12 @@ module Formulary end resource "ruby-source" do - url "https://raw.githubusercontent.com/Homebrew/homebrew-core/#{json_formula["tap_git_head"]}/Formula/#{name}.rb" - if (ruby_source_sha256 = json_formula.dig("ruby_source_checksum", "sha256")).present? - sha256 ruby_source_sha256 - end + tap_git_head = json_formula.fetch("tap_git_head", "HEAD") + ruby_source_path = json_formula.fetch("ruby_source_path", "Formula/#{name}.rb") + ruby_source_sha256 = json_formula.dig("ruby_source_checksum", "sha256") + + url "https://raw.githubusercontent.com/Homebrew/homebrew-core/#{tap_git_head}/#{ruby_source_path}" + sha256 ruby_source_sha256 if ruby_source_sha256 end def install diff --git a/Library/Homebrew/test/api/cask_spec.rb b/Library/Homebrew/test/api/cask_spec.rb index c5a555d0e6..3d476483a4 100644 --- a/Library/Homebrew/test/api/cask_spec.rb +++ b/Library/Homebrew/test/api/cask_spec.rb @@ -51,9 +51,9 @@ describe Homebrew::API::Cask do it "fetches the source of a cask (defaulting to master when no `git_head` is passed)" do curl_output = instance_double(SystemCommand::Result, stdout: "foo", success?: true) expect(Utils::Curl).to receive(:curl_output) - .with("--fail", "https://raw.githubusercontent.com/Homebrew/homebrew-cask/master/Casks/foo.rb") + .with("--fail", "https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/foo.rb") .and_return(curl_output) - described_class.fetch_source("foo", git_head: nil) + described_class.fetch_source("foo", path: "Casks/foo.rb", git_head: "HEAD") end end end diff --git a/Library/Homebrew/test/api_spec.rb b/Library/Homebrew/test/api_spec.rb index d1c02111f0..2ff4ff5c32 100644 --- a/Library/Homebrew/test/api_spec.rb +++ b/Library/Homebrew/test/api_spec.rb @@ -72,14 +72,14 @@ describe Homebrew::API do describe "::fetch_file_source" do it "fetches a file" do mock_curl_output stdout: json - fetched_json = described_class.fetch_homebrew_cask_source("foo", git_head: "master") + fetched_json = described_class.fetch_homebrew_cask_source("foo", path: "Casks/foo.rb", git_head: "HEAD") expect(fetched_json).to eq json end it "raises an error if the file does not exist" do mock_curl_output success: false expect do - described_class.fetch_homebrew_cask_source("bar", git_head: "master") + described_class.fetch_homebrew_cask_source("bar", path: "Casks/bar.rb", git_head: "HEAD") end.to raise_error(ArgumentError, /No valid file found/) end end diff --git a/Library/Homebrew/test/support/fixtures/cask/everything-systemsettings-caveats.json b/Library/Homebrew/test/support/fixtures/cask/everything-systemsettings-caveats.json index 4accb46a89..e7291d2cc3 100644 --- a/Library/Homebrew/test/support/fixtures/cask/everything-systemsettings-caveats.json +++ b/Library/Homebrew/test/support/fixtures/cask/everything-systemsettings-caveats.json @@ -93,6 +93,7 @@ "en", "eo" ], + "ruby_source_path": "Formula/everything.rb", "ruby_source_checksum": { "sha256": "b2707d1952f02c3fa566b7ad2a707a847a959d36f51d3dee642dbe5deec12f27" } diff --git a/Library/Homebrew/test/support/fixtures/cask/everything.json b/Library/Homebrew/test/support/fixtures/cask/everything.json index 9ac6b3d522..f69b490717 100644 --- a/Library/Homebrew/test/support/fixtures/cask/everything.json +++ b/Library/Homebrew/test/support/fixtures/cask/everything.json @@ -93,6 +93,7 @@ "en", "eo" ], + "ruby_source_path": "Casks/everything.rb", "ruby_source_checksum": { "sha256": "b2707d1952f02c3fa566b7ad2a707a847a959d36f51d3dee642dbe5deec12f27" }