diff --git a/Library/Homebrew/api.rb b/Library/Homebrew/api.rb index 8417784fa0..1221d42d78 100644 --- a/Library/Homebrew/api.rb +++ b/Library/Homebrew/api.rb @@ -4,6 +4,7 @@ require "api/analytics" require "api/cask" require "api/formula" +require "api/internal" require "base64" module Homebrew @@ -151,6 +152,30 @@ module Homebrew json.except("variations") end + sig { params(download_queue: T.nilable(DownloadQueue), stale_seconds: Integer).void } + def self.fetch_api_files!(download_queue: nil, stale_seconds: Homebrew::EnvConfig.api_auto_update_secs.to_i) + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.fetch_formula_api!(download_queue:, stale_seconds:) + Homebrew::API::Internal.fetch_cask_api!(download_queue:, stale_seconds:) + else + Homebrew::API::Formula.fetch_api!(download_queue:, stale_seconds:) + Homebrew::API::Formula.fetch_tap_migrations!(download_queue:, stale_seconds:) + Homebrew::API::Cask.fetch_api!(download_queue:, stale_seconds:) + Homebrew::API::Cask.fetch_tap_migrations!(download_queue:, stale_seconds:) + end + end + + sig { void } + def self.write_names_and_aliases + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.write_formula_names_and_aliases + Homebrew::API::Internal.write_cask_names + else + Homebrew::API::Formula.write_names_and_aliases + Homebrew::API::Cask.write_names + end + end + sig { params(names: T::Array[String], type: String, regenerate: T::Boolean).returns(T::Boolean) } def self.write_names_file!(names, type, regenerate:) names_path = HOMEBREW_CACHE_API/"#{type}_names.txt" @@ -216,6 +241,69 @@ module Homebrew Tap.fetch(org, repo) end + + sig { returns(T::Array[String]) } + def self.formula_names + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.formula_arrays.keys + else + Homebrew::API::Formula.all_formulae.keys + end + end + + sig { returns(T::Hash[String, String]) } + def self.formula_aliases + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.formula_aliases + else + Homebrew::API::Formula.all_aliases + end + end + + sig { returns(T::Hash[String, String]) } + def self.formula_renames + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.formula_renames + else + Homebrew::API::Formula.all_renames + end + end + + sig { returns(T::Hash[String, String]) } + def self.formula_tap_migrations + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.formula_tap_migrations + else + Homebrew::API::Formula.tap_migrations + end + end + + sig { returns(T::Array[String]) } + def self.cask_tokens + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.cask_hashes.keys + else + Homebrew::API::Cask.all_casks.keys + end + end + + sig { returns(T::Hash[String, String]) } + def self.cask_renames + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.cask_renames + else + Homebrew::API::Cask.all_renames + end + end + + sig { returns(T::Hash[String, String]) } + def self.cask_tap_migrations + if Homebrew::EnvConfig.use_internal_api? + Homebrew::API::Internal.cask_tap_migrations + else + Homebrew::API::Cask.tap_migrations + end + end end sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) } diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index aced177b90..f38ef7ec7e 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -95,10 +95,7 @@ begin require "api/cask" download_queue = Homebrew::DownloadQueue.new stale_seconds = 86400 # 1 day - Homebrew::API::Formula.fetch_api!(download_queue:, stale_seconds:) - Homebrew::API::Formula.fetch_tap_migrations!(download_queue:, stale_seconds:) - Homebrew::API::Cask.fetch_api!(download_queue:, stale_seconds:) - Homebrew::API::Cask.fetch_tap_migrations!(download_queue:, stale_seconds:) + Homebrew::API.fetch_api_files!(download_queue:, stale_seconds:) begin download_queue.fetch ensure diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index 18666f40c4..905ec292a6 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -306,8 +306,8 @@ module Cask return if Homebrew::EnvConfig.no_install_from_api? return unless ref.is_a?(String) return unless (token = ref[HOMEBREW_DEFAULT_TAP_CASK_REGEX, :token]) - if !Homebrew::API::Cask.all_casks.key?(token) && - !Homebrew::API::Cask.all_renames.key?(token) + if Homebrew::API.cask_tokens.exclude?(token) && + !Homebrew::API.cask_renames.key?(token) return end diff --git a/Library/Homebrew/cli/named_args.rb b/Library/Homebrew/cli/named_args.rb index 1047b10265..4500547035 100644 --- a/Library/Homebrew/cli/named_args.rb +++ b/Library/Homebrew/cli/named_args.rb @@ -207,13 +207,13 @@ module Homebrew if formula_path.exist? || (!Homebrew::EnvConfig.no_install_from_api? && !CoreTap.instance.installed? && - Homebrew::API::Formula.all_formulae.key?(path.basename.to_s)) + Homebrew::API.formula_names.include?(path.basename.to_s)) paths << formula_path end if cask_path.exist? || (!Homebrew::EnvConfig.no_install_from_api? && !CoreCaskTap.instance.installed? && - Homebrew::API::Cask.all_casks.key?(path.basename.to_s)) + Homebrew::API.cask_tokens.include?(path.basename.to_s)) paths << cask_path end diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 38c84d2e02..a7d9ce6b60 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -134,10 +134,7 @@ module Homebrew end # Check if we can parse the JSON and do any Ruby-side follow-up. - unless Homebrew::EnvConfig.no_install_from_api? - Homebrew::API::Formula.write_names_and_aliases - Homebrew::API::Cask.write_names - end + Homebrew::API.write_names_and_aliases unless Homebrew::EnvConfig.no_install_from_api? Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"] return if Homebrew::EnvConfig.disable_load_formula? diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index bee0caf795..d3e8072657 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -110,7 +110,7 @@ module Homebrew raise TapUnavailableError, "#{tap_match[:user]}/#{tap_match[:repo]}" elsif cask || core_cask_path?(path) - if !CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(name) + if !CoreCaskTap.instance.installed? && Homebrew::API.cask_tokens.include?(name) command = "brew tap --force #{CoreCaskTap.instance.name}" action = "tap #{CoreCaskTap.instance.name}" else @@ -119,7 +119,7 @@ module Homebrew end elsif core_formula_path?(path) && !CoreTap.instance.installed? && - Homebrew::API::Formula.all_formulae.key?(name) + Homebrew::API.formula_names.include?(name) command = "brew tap --force #{CoreTap.instance.name}" action = "tap #{CoreTap.instance.name}" else diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 47a11688a5..74679b02fd 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -662,5 +662,10 @@ module Homebrew [concurrency, 1].max end + + sig { returns(T::Boolean) } + def use_internal_api? + ENV["HOMEBREW_USE_INTERNAL_API"].present? + end end end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index b436f80030..e325ecbdca 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -875,9 +875,9 @@ module Formulary return if Homebrew::EnvConfig.no_install_from_api? return unless ref.is_a?(String) return unless (name = ref[HOMEBREW_DEFAULT_TAP_FORMULA_REGEX, :name]) - if !Homebrew::API::Formula.all_formulae.key?(name) && - !Homebrew::API::Formula.all_aliases.key?(name) && - !Homebrew::API::Formula.all_renames.key?(name) + if Homebrew::API.formula_names.exclude?(name) && + !Homebrew::API.formula_aliases.key?(name) && + !Homebrew::API.formula_renames.key?(name) return end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 4d5d2df15e..989a1fff1d 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -1345,13 +1345,18 @@ class CoreTap < AbstractCoreTap end, T.nilable(Pathname)) end - sig { override.params(name: String).returns(Pathname) } - def new_formula_path(name) - formula_subdir = if name.start_with?("lib") + sig { params(name: String).returns(String) } + def new_formula_subdirectory(name) + if name.start_with?("lib") "lib" else name[0].to_s end + end + + sig { override.params(name: String).returns(Pathname) } + def new_formula_path(name) + formula_subdir = new_formula_subdirectory(name) return super unless (formula_dir/formula_subdir).directory? @@ -1373,7 +1378,7 @@ class CoreTap < AbstractCoreTap ensure_installed! super else - Homebrew::API::Formula.all_renames + Homebrew::API.formula_renames end, T.nilable(T::Hash[String, String]), ) @@ -1386,7 +1391,7 @@ class CoreTap < AbstractCoreTap ensure_installed! super else - Homebrew::API::Formula.tap_migrations + Homebrew::API.formula_tap_migrations end, T.nilable(T::Hash[String, T.untyped]), ) @@ -1443,7 +1448,7 @@ class CoreTap < AbstractCoreTap if Homebrew::EnvConfig.no_install_from_api? super else - Homebrew::API::Formula.all_aliases + Homebrew::API.formula_aliases end, T.nilable(T::Hash[String, String]), ) @@ -1460,7 +1465,7 @@ class CoreTap < AbstractCoreTap def formula_names return super if Homebrew::EnvConfig.no_install_from_api? - Homebrew::API::Formula.all_formulae.keys + Homebrew::API.formula_names end sig { override.returns(T::Hash[String, Pathname]) } @@ -1469,13 +1474,12 @@ class CoreTap < AbstractCoreTap @formula_files_by_name ||= T.let( begin - tap_path = path.to_s - Homebrew::API::Formula.all_formulae.each_with_object({}) do |item, hash| - name, formula_hash = item + formula_directory_path = formula_dir.to_s + Homebrew::API.formula_names.each_with_object({}) do |name, hash| # If there's more than one item with the same path: use the longer one to prioritise more specific results. existing_path = hash[name] # Pathname equivalent is slow in a tight loop - new_path = File.join(tap_path, formula_hash.fetch("ruby_source_path")) + new_path = File.join(formula_directory_path, new_formula_subdirectory(name), "#{name.downcase}.rb") hash[name] = Pathname(new_path) if existing_path.nil? || existing_path.to_s.length < new_path.length end end, @@ -1500,14 +1504,18 @@ class CoreCaskTap < AbstractCoreTap true end - sig { override.params(token: String).returns(Pathname) } - def new_cask_path(token) - cask_subdir = if token.start_with?("font-") + sig { params(token: String).returns(String) } + def new_cask_subdirectory(token) + if token.start_with?("font-") "font/font-#{token.delete_prefix("font-")[0]}" else token[0].to_s end - cask_dir/cask_subdir/"#{token.downcase}.rb" + end + + sig { override.params(token: String).returns(Pathname) } + def new_cask_path(token) + cask_dir/new_cask_subdirectory(token)/"#{token.downcase}.rb" end sig { override.returns(T::Array[Pathname]) } @@ -1521,7 +1529,7 @@ class CoreCaskTap < AbstractCoreTap def cask_tokens return super if Homebrew::EnvConfig.no_install_from_api? - Homebrew::API::Cask.all_casks.keys + Homebrew::API.cask_tokens end sig { override.returns(T::Hash[String, Pathname]) } @@ -1530,13 +1538,12 @@ class CoreCaskTap < AbstractCoreTap @cask_files_by_name ||= T.let( begin - tap_path = path.to_s - Homebrew::API::Cask.all_casks.each_with_object({}) do |item, hash| - name, cask_hash = item + cask_directory_path = cask_dir.to_s + Homebrew::API.cask_tokens.each_with_object({}) do |name, hash| # If there's more than one item with the same path: use the longer one to prioritise more specific results. existing_path = hash[name] # Pathname equivalent is slow in a tight loop - new_path = File.join(tap_path, cask_hash.fetch("ruby_source_path")) + new_path = File.join(cask_directory_path, new_cask_subdirectory(name), "#{name.downcase}.rb") hash[name] = Pathname(new_path) if existing_path.nil? || existing_path.to_s.length < new_path.length end end, @@ -1550,7 +1557,7 @@ class CoreCaskTap < AbstractCoreTap if Homebrew::EnvConfig.no_install_from_api? super else - Homebrew::API::Cask.all_renames + Homebrew::API.cask_renames end, T.nilable(T::Hash[String, String]), ) @@ -1562,7 +1569,7 @@ class CoreCaskTap < AbstractCoreTap if Homebrew::EnvConfig.no_install_from_api? super else - Homebrew::API::Cask.tap_migrations + Homebrew::API.cask_tap_migrations end, T.nilable(T::Hash[String, T.untyped]), ) diff --git a/Library/Homebrew/uninstall.rb b/Library/Homebrew/uninstall.rb index ce19765f81..6d88d2fc3b 100644 --- a/Library/Homebrew/uninstall.rb +++ b/Library/Homebrew/uninstall.rb @@ -68,7 +68,7 @@ module Homebrew unversioned_name = f.name.gsub(/@.+$/, "") maybe_paths = Dir.glob("#{f.etc}/#{unversioned_name}*") - excluded_names = Homebrew::API::Formula.all_formulae.keys + excluded_names = Homebrew::API.formula_names maybe_paths = maybe_paths.reject do |path| # Remove extension only if a file # (e.g. directory with name "openssl@1.1" will be trimmed to "openssl@1") diff --git a/Library/Homebrew/utils/analytics.rb b/Library/Homebrew/utils/analytics.rb index 305af3f6df..a22d3f8bae 100644 --- a/Library/Homebrew/utils/analytics.rb +++ b/Library/Homebrew/utils/analytics.rb @@ -329,7 +329,7 @@ module Utils require "api" - return unless Homebrew::API::Formula.all_formulae.key? formula.name + return unless Homebrew::API.formula_names.include? formula.name json = Homebrew::API::Formula.formula_json formula.name return if json.blank? || json["analytics"].blank? @@ -347,7 +347,7 @@ module Utils require "api" - return unless Homebrew::API::Cask.all_casks.key? cask.token + return unless Homebrew::API.cask_tokens.include? cask.token json = Homebrew::API::Cask.cask_json cask.token return if json.blank? || json["analytics"].blank?