mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
Merge pull request #21495 from Homebrew/load-from-internal-api
Optionally load formulae from the internal API
This commit is contained in:
@@ -284,7 +284,7 @@ module Homebrew
|
||||
sig { returns(T::Array[String]) }
|
||||
def self.formula_names
|
||||
if Homebrew::EnvConfig.use_internal_api?
|
||||
Homebrew::API::Internal.formula_arrays.keys
|
||||
Homebrew::API::Internal.formula_hashes.keys
|
||||
else
|
||||
Homebrew::API::Formula.all_formulae.keys
|
||||
end
|
||||
|
||||
@@ -117,6 +117,16 @@ module Homebrew
|
||||
const :version_scheme, Integer, default: 0
|
||||
const :versioned_formulae, T::Array[String], default: []
|
||||
|
||||
sig { params(other: T.anything).returns(T::Boolean) }
|
||||
def ==(other)
|
||||
case other
|
||||
when FormulaStruct
|
||||
serialize == other.serialize
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(bottle_tag: ::Utils::Bottles::Tag).returns(T.nilable(T::Hash[String, T.untyped])) }
|
||||
def serialize_bottle(bottle_tag: ::Utils::Bottles.tag)
|
||||
bottle_collector = ::Utils::Bottles::Collector.new
|
||||
|
||||
@@ -5,7 +5,6 @@ require "cachable"
|
||||
require "api"
|
||||
require "api/source_download"
|
||||
require "download_queue"
|
||||
require "formula_stub"
|
||||
|
||||
module Homebrew
|
||||
module API
|
||||
@@ -25,35 +24,19 @@ module Homebrew
|
||||
"internal/cask.#{SimulateSystem.current_tag}.jws.json"
|
||||
end
|
||||
|
||||
sig { params(name: String).returns(Homebrew::FormulaStub) }
|
||||
def self.formula_stub(name)
|
||||
return cache["formula_stubs"][name] if cache.key?("formula_stubs") && cache["formula_stubs"].key?(name)
|
||||
sig { params(name: String).returns(Homebrew::API::FormulaStruct) }
|
||||
def self.formula_struct(name)
|
||||
return cache["formula_structs"][name] if cache.key?("formula_structs") && cache["formula_structs"].key?(name)
|
||||
|
||||
stub_array = formula_arrays[name]
|
||||
raise "No formula stub found for #{name}" unless stub_array
|
||||
hash = formula_hashes[name]
|
||||
raise "No formula found for #{name}" unless hash
|
||||
|
||||
aliases = formula_aliases.filter_map do |alias_name, original_name|
|
||||
alias_name if original_name == name
|
||||
end
|
||||
struct = Homebrew::API::FormulaStruct.deserialize(hash, bottle_tag: SimulateSystem.current_tag)
|
||||
|
||||
oldnames = formula_renames.filter_map do |oldname, newname|
|
||||
oldname if newname == name
|
||||
end
|
||||
cache["formula_structs"] ||= {}
|
||||
cache["formula_structs"][name] = struct
|
||||
|
||||
stub = Homebrew::FormulaStub.new(
|
||||
name: name,
|
||||
pkg_version: PkgVersion.parse(stub_array[0]),
|
||||
version_scheme: stub_array[1],
|
||||
rebuild: stub_array[2],
|
||||
sha256: stub_array[3],
|
||||
aliases:,
|
||||
oldnames:,
|
||||
)
|
||||
|
||||
cache["formula_stubs"] ||= {}
|
||||
cache["formula_stubs"][name] = stub
|
||||
|
||||
stub
|
||||
struct
|
||||
end
|
||||
|
||||
sig { returns(Pathname) }
|
||||
@@ -87,11 +70,12 @@ module Homebrew
|
||||
sig { returns(T::Boolean) }
|
||||
def self.download_and_cache_formula_data!
|
||||
json_contents, updated = fetch_formula_api!
|
||||
cache["formula_stubs"] = {}
|
||||
cache["formula_structs"] = {}
|
||||
cache["formula_aliases"] = json_contents["aliases"]
|
||||
cache["formula_renames"] = json_contents["renames"]
|
||||
cache["formula_tap_git_head"] = json_contents["tap_git_head"]
|
||||
cache["formula_tap_migrations"] = json_contents["tap_migrations"]
|
||||
cache["formula_arrays"] = json_contents["formulae"]
|
||||
cache["formula_hashes"] = json_contents["formulae"]
|
||||
|
||||
updated
|
||||
end
|
||||
@@ -111,9 +95,9 @@ module Homebrew
|
||||
|
||||
sig { params(regenerate: T::Boolean).void }
|
||||
def self.write_formula_names_and_aliases(regenerate: false)
|
||||
download_and_cache_formula_data! unless cache.key?("formula_arrays")
|
||||
download_and_cache_formula_data! unless cache.key?("formula_hashes")
|
||||
|
||||
Homebrew::API.write_names_file!(formula_arrays.keys, "formula", regenerate:)
|
||||
Homebrew::API.write_names_file!(formula_hashes.keys, "formula", regenerate:)
|
||||
Homebrew::API.write_aliases_file!(formula_aliases, "formula", regenerate:)
|
||||
end
|
||||
|
||||
@@ -124,14 +108,14 @@ module Homebrew
|
||||
Homebrew::API.write_names_file!(cask_hashes.keys, "cask", regenerate:)
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, [String, Integer, Integer, T.nilable(String)]]) }
|
||||
def self.formula_arrays
|
||||
unless cache.key?("formula_arrays")
|
||||
sig { returns(T::Hash[String, T::Hash[String, T.untyped]]) }
|
||||
def self.formula_hashes
|
||||
unless cache.key?("formula_hashes")
|
||||
updated = download_and_cache_formula_data!
|
||||
write_formula_names_and_aliases(regenerate: updated)
|
||||
end
|
||||
|
||||
cache["formula_arrays"]
|
||||
cache["formula_hashes"]
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
@@ -164,6 +148,16 @@ module Homebrew
|
||||
cache["formula_tap_migrations"]
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def self.formula_tap_git_head
|
||||
unless cache.key?("formula_tap_git_head")
|
||||
updated = download_and_cache_formula_data!
|
||||
write_formula_names_and_aliases(regenerate: updated)
|
||||
end
|
||||
|
||||
cache["formula_tap_git_head"]
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, T::Hash[String, T.untyped]]) }
|
||||
def self.cask_hashes
|
||||
unless cache.key?("cask_hashes")
|
||||
|
||||
@@ -684,6 +684,8 @@ module Homebrew
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def use_internal_api?
|
||||
return true if ENV["HOMEBREW_REALLY_USE_INTERNAL_API"].present?
|
||||
|
||||
# TODO: re-enable this when the internal API is ready again.
|
||||
false
|
||||
end
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "pkg_version"
|
||||
|
||||
module Homebrew
|
||||
# A stub for a formula, with only the information needed to fetch the bottle manifest.
|
||||
class FormulaStub < T::Struct
|
||||
const :name, String
|
||||
const :pkg_version, PkgVersion
|
||||
const :version_scheme, Integer, default: 0
|
||||
const :rebuild, Integer, default: 0
|
||||
const :sha256, T.nilable(String)
|
||||
const :aliases, T::Array[String], default: []
|
||||
const :oldnames, T::Array[String], default: []
|
||||
|
||||
sig { returns(Version) }
|
||||
def version
|
||||
pkg_version.version
|
||||
end
|
||||
|
||||
sig { returns(Integer) }
|
||||
def revision
|
||||
pkg_version.revision
|
||||
end
|
||||
|
||||
sig { params(other: T.anything).returns(T::Boolean) }
|
||||
def ==(other)
|
||||
case other
|
||||
when FormulaStub
|
||||
name == other.name &&
|
||||
pkg_version == other.pkg_version &&
|
||||
version_scheme == other.version_scheme &&
|
||||
rebuild == other.rebuild &&
|
||||
sha256 == other.sha256 &&
|
||||
aliases == other.aliases &&
|
||||
oldnames == other.oldnames
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -203,14 +203,15 @@ module Formulary
|
||||
|
||||
sig {
|
||||
params(
|
||||
name: String,
|
||||
json_formula_with_variations: T::Hash[String, T.untyped],
|
||||
tap_git_head: String,
|
||||
flags: T::Array[String],
|
||||
name: String,
|
||||
formula_struct: Homebrew::API::FormulaStruct,
|
||||
api_source: T::Hash[String, T.untyped],
|
||||
tap_git_head: String,
|
||||
flags: T::Array[String],
|
||||
).returns(T.class_of(Formula))
|
||||
}
|
||||
def self.load_formula_from_json!(name, json_formula_with_variations, tap_git_head:, flags:)
|
||||
namespace = :"FormulaNamespaceAPI#{namespace_key(json_formula_with_variations.to_json)}"
|
||||
def self.load_formula_from_struct!(name, formula_struct, api_source:, tap_git_head:, flags:)
|
||||
namespace = :"FormulaNamespaceAPI#{namespace_key(api_source.to_json)}"
|
||||
|
||||
mod = Module.new
|
||||
remove_const(namespace) if const_defined?(namespace)
|
||||
@@ -220,11 +221,10 @@ module Formulary
|
||||
|
||||
class_name = class_s(name)
|
||||
ruby_source_path = "Formula/#{CoreTap.instance.new_formula_subdirectory(name)}/#{name.downcase}.rb"
|
||||
formula_struct = Homebrew::API::Formula::FormulaStructGenerator.generate_formula_struct_hash(json_formula_with_variations)
|
||||
|
||||
klass = Class.new(::Formula) do
|
||||
@loaded_from_api = T.let(true, T.nilable(T::Boolean))
|
||||
@api_source = T.let(json_formula_with_variations, T.nilable(T::Hash[String, T.untyped]))
|
||||
@api_source = T.let(api_source, T.nilable(T::Hash[String, T.untyped]))
|
||||
|
||||
desc formula_struct.desc
|
||||
homepage formula_struct.homepage
|
||||
@@ -875,16 +875,25 @@ module Formulary
|
||||
|
||||
sig { overridable.params(flags: T::Array[String]).void }
|
||||
def load_from_api(flags:)
|
||||
json_formula = if Homebrew::EnvConfig.use_internal_api?
|
||||
Homebrew::API::Formula.formula_json(name)
|
||||
else
|
||||
Homebrew::API::Formula.all_formulae[name]
|
||||
end
|
||||
return load_from_internal_api(flags:) if Homebrew::EnvConfig.use_internal_api?
|
||||
|
||||
raise FormulaUnavailableError, name if json_formula.nil?
|
||||
api_source = Homebrew::API::Formula.all_formulae[name]
|
||||
raise FormulaUnavailableError, name if api_source.nil?
|
||||
|
||||
tap_git_head = json_formula.fetch("tap_git_head", "")
|
||||
Formulary.load_formula_from_json!(name, json_formula, tap_git_head:, flags:)
|
||||
tap_git_head = api_source.fetch("tap_git_head", "")
|
||||
formula_struct = Homebrew::API::Formula::FormulaStructGenerator.generate_formula_struct_hash(api_source)
|
||||
Formulary.load_formula_from_struct!(name, formula_struct, api_source:, tap_git_head:, flags:)
|
||||
end
|
||||
|
||||
sig { params(flags: T::Array[String]).void }
|
||||
def load_from_internal_api(flags:)
|
||||
formula_struct = Homebrew::API::Internal.formula_struct(name)
|
||||
api_source = Homebrew::API::Internal.formula_hashes[name]
|
||||
tap_git_head = Homebrew::API::Internal.formula_tap_git_head
|
||||
|
||||
raise FormulaUnavailableError, name if api_source.nil?
|
||||
|
||||
Formulary.load_formula_from_struct!(name, formula_struct, api_source:, tap_git_head:, flags:)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -901,7 +910,8 @@ module Formulary
|
||||
sig { override.params(flags: T::Array[String]).void }
|
||||
def load_from_api(flags:)
|
||||
tap_git_head = @contents.fetch("tap_git_head", "")
|
||||
Formulary.load_formula_from_json!(name, @contents, tap_git_head:, flags:)
|
||||
formula_struct = Homebrew::API::Formula::FormulaStructGenerator.generate_formula_struct_hash(@contents)
|
||||
Formulary.load_formula_from_struct!(name, formula_struct, api_source: @contents, tap_git_head:, flags:)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -24,9 +24,31 @@ RSpec.describe Homebrew::API::Internal do
|
||||
<<~JSON
|
||||
{
|
||||
"formulae": {
|
||||
"foo": ["1.0.0", 0, 0, "09f88b61e36045188ddb1b1ba8e402b9f3debee1770cc4ca91355eeccb5f4a38"],
|
||||
"bar": ["0.4.0_5", 1, 0, "bb6e3408f39a404770529cfce548dc2666e861077acd173825cb3138c27c205a"],
|
||||
"baz": ["10.4.5_2", 0, 2, "404c97537d65ca0b75c389e7d439dcefb9b56f34d3b98017669eda0d0501add7"]
|
||||
"foo": {
|
||||
"desc": "Foo formula",
|
||||
"homepage": "https://example.com/foo",
|
||||
"license": "MIT",
|
||||
"ruby_source_checksum": "09f88b61e36045188ddb1b1ba8e402b9f3debee1770cc4ca91355eeccb5f4a38",
|
||||
"stable_version": "1.0.0"
|
||||
},
|
||||
"bar": {
|
||||
"desc": "Bar formula",
|
||||
"homepage": "https://example.com/bar",
|
||||
"license": "Apache-2.0",
|
||||
"ruby_source_checksum": "bb6e3408f39a404770529cfce548dc2666e861077acd173825cb3138c27c205a",
|
||||
"stable_version": "0.4.0",
|
||||
"revision": 5,
|
||||
"version_scheme": 1
|
||||
},
|
||||
"baz": {
|
||||
"desc": "Baz formula",
|
||||
"homepage": "https://example.com/baz",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"ruby_source_checksum": "404c97537d65ca0b75c389e7d439dcefb9b56f34d3b98017669eda0d0501add7",
|
||||
"stable_version": "10.4.5",
|
||||
"revision": 2,
|
||||
"bottle_rebuild": 2
|
||||
}
|
||||
},
|
||||
"aliases": {
|
||||
"foo-alias1": "foo",
|
||||
@@ -38,6 +60,7 @@ RSpec.describe Homebrew::API::Internal do
|
||||
"bar-old": "bar",
|
||||
"baz-old": "baz"
|
||||
},
|
||||
"tap_git_head": "b871900717ccbb3508ca93fa56e128940b9bd371",
|
||||
"tap_migrations": {
|
||||
"abc": "some/tap",
|
||||
"def": "another/tap"
|
||||
@@ -45,25 +68,39 @@ RSpec.describe Homebrew::API::Internal do
|
||||
}
|
||||
JSON
|
||||
end
|
||||
let(:formula_arrays) do
|
||||
let(:formula_hashes) do
|
||||
{
|
||||
"foo" => ["1.0.0", 0, 0, "09f88b61e36045188ddb1b1ba8e402b9f3debee1770cc4ca91355eeccb5f4a38"],
|
||||
"bar" => ["0.4.0_5", 1, 0, "bb6e3408f39a404770529cfce548dc2666e861077acd173825cb3138c27c205a"],
|
||||
"baz" => ["10.4.5_2", 0, 2, "404c97537d65ca0b75c389e7d439dcefb9b56f34d3b98017669eda0d0501add7"],
|
||||
"foo" => {
|
||||
"desc" => "Foo formula",
|
||||
"homepage" => "https://example.com/foo",
|
||||
"license" => "MIT",
|
||||
"ruby_source_checksum" => "09f88b61e36045188ddb1b1ba8e402b9f3debee1770cc4ca91355eeccb5f4a38",
|
||||
"stable_version" => "1.0.0",
|
||||
},
|
||||
"bar" => {
|
||||
"desc" => "Bar formula",
|
||||
"homepage" => "https://example.com/bar",
|
||||
"license" => "Apache-2.0",
|
||||
"ruby_source_checksum" => "bb6e3408f39a404770529cfce548dc2666e861077acd173825cb3138c27c205a",
|
||||
"stable_version" => "0.4.0",
|
||||
"revision" => 5,
|
||||
"version_scheme" => 1,
|
||||
},
|
||||
"baz" => {
|
||||
"desc" => "Baz formula",
|
||||
"homepage" => "https://example.com/baz",
|
||||
"license" => "GPL-3.0-or-later",
|
||||
"ruby_source_checksum" => "404c97537d65ca0b75c389e7d439dcefb9b56f34d3b98017669eda0d0501add7",
|
||||
"stable_version" => "10.4.5",
|
||||
"revision" => 2,
|
||||
"bottle_rebuild" => 2,
|
||||
},
|
||||
}
|
||||
end
|
||||
let(:formula_stubs) do
|
||||
formula_arrays.to_h do |name, (pkg_version, version_scheme, rebuild, sha256)|
|
||||
stub = Homebrew::FormulaStub.new(
|
||||
name: name,
|
||||
pkg_version: PkgVersion.parse(pkg_version),
|
||||
version_scheme: version_scheme,
|
||||
rebuild: rebuild,
|
||||
sha256: sha256,
|
||||
aliases: formulae_aliases.select { |_, new_name| new_name == name }.keys,
|
||||
oldnames: formulae_renames.select { |_, new_name| new_name == name }.keys,
|
||||
)
|
||||
[name, stub]
|
||||
let(:formula_structs) do
|
||||
formula_hashes.to_h do |name, hash|
|
||||
struct = Homebrew::API::FormulaStruct.new(**hash.transform_keys(&:to_sym))
|
||||
[name, struct]
|
||||
end
|
||||
end
|
||||
let(:formulae_aliases) do
|
||||
@@ -80,6 +117,7 @@ RSpec.describe Homebrew::API::Internal do
|
||||
"baz-old" => "baz",
|
||||
}
|
||||
end
|
||||
let(:formula_tap_git_head) { "b871900717ccbb3508ca93fa56e128940b9bd371" }
|
||||
let(:formula_tap_migrations) do
|
||||
{
|
||||
"abc" => "some/tap",
|
||||
@@ -87,17 +125,17 @@ RSpec.describe Homebrew::API::Internal do
|
||||
}
|
||||
end
|
||||
|
||||
it "returns the expected formula stubs" do
|
||||
it "returns the expected formula structs" do
|
||||
mock_curl_download stdout: formula_json
|
||||
formula_stubs.each do |name, stub|
|
||||
expect(described_class.formula_stub(name)).to eq stub
|
||||
formula_structs.each do |name, struct|
|
||||
expect(described_class.formula_struct(name)).to eq struct
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the expected formula arrays" do
|
||||
it "returns the expected formula hashes" do
|
||||
mock_curl_download stdout: formula_json
|
||||
formula_arrays_output = described_class.formula_arrays
|
||||
expect(formula_arrays_output).to eq formula_arrays
|
||||
formula_hashes_output = described_class.formula_hashes
|
||||
expect(formula_hashes_output).to eq formula_hashes
|
||||
end
|
||||
|
||||
it "returns the expected formula alias list" do
|
||||
@@ -112,6 +150,12 @@ RSpec.describe Homebrew::API::Internal do
|
||||
expect(formula_renames_output).to eq formulae_renames
|
||||
end
|
||||
|
||||
it "returns the expected formula tap git head" do
|
||||
mock_curl_download stdout: formula_json
|
||||
formula_tap_git_head_output = described_class.formula_tap_git_head
|
||||
expect(formula_tap_git_head_output).to eq formula_tap_git_head
|
||||
end
|
||||
|
||||
it "returns the expected formula tap migrations list" do
|
||||
mock_curl_download stdout: formula_json
|
||||
formula_tap_migrations_output = described_class.formula_tap_migrations
|
||||
|
||||
Reference in New Issue
Block a user