Remove Bottle API
This commit is contained in:
		
							parent
							
								
									e53ccbc3cd
								
							
						
					
					
						commit
						89483abda9
					
				@ -2,7 +2,6 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "api/analytics"
 | 
			
		||||
require "api/bottle"
 | 
			
		||||
require "api/cask"
 | 
			
		||||
require "api/cask-source"
 | 
			
		||||
require "api/formula"
 | 
			
		||||
 | 
			
		||||
@ -1,96 +0,0 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "github_packages"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module API
 | 
			
		||||
    # Helper functions for using the bottle JSON API.
 | 
			
		||||
    #
 | 
			
		||||
    # @api private
 | 
			
		||||
    module Bottle
 | 
			
		||||
      class << self
 | 
			
		||||
        extend T::Sig
 | 
			
		||||
 | 
			
		||||
        sig { returns(String) }
 | 
			
		||||
        def bottle_api_path
 | 
			
		||||
          "bottle"
 | 
			
		||||
        end
 | 
			
		||||
        alias generic_bottle_api_path bottle_api_path
 | 
			
		||||
 | 
			
		||||
        GITHUB_PACKAGES_SHA256_REGEX = %r{#{GitHubPackages::URL_REGEX}.*/blobs/sha256:(?<sha256>\h{64})$}.freeze
 | 
			
		||||
 | 
			
		||||
        sig { params(name: String).returns(Hash) }
 | 
			
		||||
        def fetch(name)
 | 
			
		||||
          name = name.sub(%r{^homebrew/core/}, "")
 | 
			
		||||
          Homebrew::API.fetch "#{bottle_api_path}/#{name}.json"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(name: String).returns(T::Boolean) }
 | 
			
		||||
        def available?(name)
 | 
			
		||||
          fetch name
 | 
			
		||||
          true
 | 
			
		||||
        rescue ArgumentError
 | 
			
		||||
          false
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(name: String).void }
 | 
			
		||||
        def fetch_bottles(name)
 | 
			
		||||
          hash = fetch(name)
 | 
			
		||||
          bottle_tag = Utils::Bottles.tag.to_s
 | 
			
		||||
 | 
			
		||||
          if !hash["bottles"].key?(bottle_tag) && !hash["bottles"].key?("all")
 | 
			
		||||
            odie "No bottle available for #{name} on the current OS"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          download_bottle(hash, bottle_tag)
 | 
			
		||||
 | 
			
		||||
          hash["dependencies"].each do |dep_hash|
 | 
			
		||||
            existing_formula = begin
 | 
			
		||||
              Formulary.factory dep_hash["name"]
 | 
			
		||||
            rescue FormulaUnavailableError
 | 
			
		||||
              # The formula might not exist if it's not installed and homebrew/core isn't tapped
 | 
			
		||||
              nil
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            next if existing_formula.present? && existing_formula.latest_version_installed?
 | 
			
		||||
 | 
			
		||||
            download_bottle(dep_hash, bottle_tag)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(url: String).returns(T.nilable(String)) }
 | 
			
		||||
        def checksum_from_url(url)
 | 
			
		||||
          match = url.match GITHUB_PACKAGES_SHA256_REGEX
 | 
			
		||||
          return if match.blank?
 | 
			
		||||
 | 
			
		||||
          match[:sha256]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        sig { params(hash: Hash, tag: String).void }
 | 
			
		||||
        def download_bottle(hash, tag)
 | 
			
		||||
          bottle = hash["bottles"][tag]
 | 
			
		||||
          bottle ||= hash["bottles"]["all"]
 | 
			
		||||
          return if bottle.blank?
 | 
			
		||||
 | 
			
		||||
          sha256 = bottle["sha256"] || checksum_from_url(bottle["url"])
 | 
			
		||||
          bottle_filename = ::Bottle::Filename.new(hash["name"], hash["pkg_version"], tag, hash["rebuild"])
 | 
			
		||||
 | 
			
		||||
          resource = Resource.new hash["name"]
 | 
			
		||||
          resource.url bottle["url"]
 | 
			
		||||
          resource.sha256 sha256
 | 
			
		||||
          resource.version hash["pkg_version"]
 | 
			
		||||
          resource.downloader.resolved_basename = bottle_filename
 | 
			
		||||
 | 
			
		||||
          resource.fetch
 | 
			
		||||
 | 
			
		||||
          # Map the name of this formula to the local bottle path to allow the
 | 
			
		||||
          # formula to be loaded by passing just the name to `Formulary::factory`.
 | 
			
		||||
          [hash["name"], "homebrew/core/#{hash["name"]}"].each do |name|
 | 
			
		||||
            Formulary.map_formula_name_to_local_bottle_path name, resource.downloader.cached_location
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -890,7 +890,7 @@ module Homebrew
 | 
			
		||||
            # Formulae installed with HOMEBREW_INSTALL_FROM_API should not count as deleted formulae
 | 
			
		||||
            # but may not have a tap listed in their tab
 | 
			
		||||
            tap = Tab.for_keg(keg).tap
 | 
			
		||||
            next if (tap.blank? || tap.core_tap?) && Homebrew::API::Bottle.available?(keg.name)
 | 
			
		||||
            next if (tap.blank? || tap.core_tap?) && Homebrew::API::Formula.all_formulae.key?(keg.name)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          keg.name
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "api"
 | 
			
		||||
 | 
			
		||||
describe Homebrew::API::Bottle do
 | 
			
		||||
  let(:bottle_json) {
 | 
			
		||||
    <<~EOS
 | 
			
		||||
      {
 | 
			
		||||
        "name": "hello",
 | 
			
		||||
        "pkg_version": "2.10",
 | 
			
		||||
        "rebuild": 0,
 | 
			
		||||
        "bottles": {
 | 
			
		||||
          "arm64_big_sur": {
 | 
			
		||||
            "url": "https://ghcr.io/v2/homebrew/core/hello/blobs/sha256:b3b083db0807ff92c6e289a298f378198354b7727fb9ba9f4d550b8e08f90a60"
 | 
			
		||||
          },
 | 
			
		||||
          "big_sur": {
 | 
			
		||||
            "url": "https://ghcr.io/v2/homebrew/core/hello/blobs/sha256:69489ae397e4645127aa7773211310f81ebb6c99e1f8e3e22c5cdb55333f5408"
 | 
			
		||||
          },
 | 
			
		||||
          "x86_64_linux": {
 | 
			
		||||
            "url": "https://ghcr.io/v2/homebrew/core/hello/blobs/sha256:e6980196298e0a9cfe4fa4e328a71a1869a4d5e1d31c38442150ed784cfc0e29"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "dependencies": []
 | 
			
		||||
      }
 | 
			
		||||
    EOS
 | 
			
		||||
  }
 | 
			
		||||
  let(:bottle_hash) { JSON.parse(bottle_json) }
 | 
			
		||||
 | 
			
		||||
  def mock_curl_output(stdout: "", success: true)
 | 
			
		||||
    curl_output = OpenStruct.new(stdout: stdout, success?: success)
 | 
			
		||||
    allow(Utils::Curl).to receive(:curl_output).and_return curl_output
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::fetch" do
 | 
			
		||||
    it "fetches the bottle JSON for a formula that exists" do
 | 
			
		||||
      mock_curl_output stdout: bottle_json
 | 
			
		||||
      fetched_hash = described_class.fetch("foo")
 | 
			
		||||
      expect(fetched_hash).to eq bottle_hash
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "raises an error if the formula does not exist" do
 | 
			
		||||
      mock_curl_output success: false
 | 
			
		||||
      expect { described_class.fetch("bar") }.to raise_error(ArgumentError, /No file found/)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "raises an error if the bottle JSON is invalid" do
 | 
			
		||||
      mock_curl_output stdout: "foo"
 | 
			
		||||
      expect { described_class.fetch("baz") }.to raise_error(ArgumentError, /Invalid JSON file/)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::available?" do
 | 
			
		||||
    it "returns `true` if `fetch` succeeds" do
 | 
			
		||||
      allow(described_class).to receive(:fetch)
 | 
			
		||||
      expect(described_class.available?("foo")).to be true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns `false` if `fetch` fails" do
 | 
			
		||||
      allow(described_class).to receive(:fetch).and_raise ArgumentError
 | 
			
		||||
      expect(described_class.available?("foo")).to be false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::fetch_bottles" do
 | 
			
		||||
    before do
 | 
			
		||||
      ENV["HOMEBREW_INSTALL_FROM_API"] = "1"
 | 
			
		||||
      allow(described_class).to receive(:fetch).and_return bottle_hash
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "fetches bottles if a bottle is available" do
 | 
			
		||||
      allow(Utils::Bottles).to receive(:tag).and_return :arm64_big_sur
 | 
			
		||||
      expect { described_class.fetch_bottles("hello") }.not_to raise_error
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "raises an error if no bottle is available" do
 | 
			
		||||
      allow(Utils::Bottles).to receive(:tag).and_return :catalina
 | 
			
		||||
      expect { described_class.fetch_bottles("hello") }.to raise_error(SystemExit)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::checksum_from_url" do
 | 
			
		||||
    let(:sha256) { "b3b083db0807ff92c6e289a298f378198354b7727fb9ba9f4d550b8e08f90a60" }
 | 
			
		||||
    let(:url) { "https://ghcr.io/v2/homebrew/core/hello/blobs/sha256:#{sha256}" }
 | 
			
		||||
    let(:non_ghp_url) { "https://formulae.brew.sh/api/formula/hello.json" }
 | 
			
		||||
 | 
			
		||||
    it "returns the `sha256` for a GitHub packages URL" do
 | 
			
		||||
      expect(described_class.checksum_from_url(url)).to eq sha256
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns `nil` for a non-GitHub packages URL" do
 | 
			
		||||
      expect(described_class.checksum_from_url(non_ghp_url)).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user