Optionally parallelise API file downloads
This assumes that all should be downloaded (at least once) on `brew` commands being run. Requires a certain amount of cleanup and refactoring around our API handling and Tap migration methods (which were both weirdly placed and in some cases broken). Behaviour without `HOMEBREW_DOWNLOAD_CONCURRENCY` set should be unchanged.
This commit is contained in:
parent
5cc6722372
commit
36c7f4950c
@ -13,6 +13,7 @@ module Homebrew
|
||||
|
||||
HOMEBREW_CACHE_API = T.let((HOMEBREW_CACHE/"api").freeze, Pathname)
|
||||
HOMEBREW_CACHE_API_SOURCE = T.let((HOMEBREW_CACHE/"api-source").freeze, Pathname)
|
||||
TAP_MIGRATIONS_STALE_SECONDS = T.let(86400, Integer) # 1 day
|
||||
|
||||
sig { params(endpoint: String).returns(T::Hash[String, T.untyped]) }
|
||||
def self.fetch(endpoint)
|
||||
@ -33,11 +34,11 @@ module Homebrew
|
||||
end
|
||||
|
||||
sig {
|
||||
params(endpoint: String, target: Pathname,
|
||||
stale_seconds: Integer).returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
params(endpoint: String, target: Pathname, stale_seconds: Integer, download_queue: T.nilable(DownloadQueue))
|
||||
.returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
}
|
||||
def self.fetch_json_api_file(endpoint, target: HOMEBREW_CACHE_API/endpoint,
|
||||
stale_seconds: Homebrew::EnvConfig.api_auto_update_secs.to_i)
|
||||
stale_seconds: Homebrew::EnvConfig.api_auto_update_secs.to_i, download_queue: nil)
|
||||
# Lazy-load dependency.
|
||||
require "development_tools"
|
||||
|
||||
@ -65,6 +66,14 @@ module Homebrew
|
||||
((Time.now - stale_seconds) < target.mtime))
|
||||
skip_download ||= Homebrew.running_as_root_but_not_owned_by_root?
|
||||
|
||||
if download_queue
|
||||
unless skip_download
|
||||
download = Homebrew::API::Download.new(url, nil, cache: HOMEBREW_CACHE_API, require_checksum: false)
|
||||
download_queue.enqueue(download)
|
||||
end
|
||||
return [{}, false]
|
||||
end
|
||||
|
||||
json_data = begin
|
||||
begin
|
||||
args = curl_args.dup
|
||||
|
@ -2,7 +2,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cachable"
|
||||
require "api"
|
||||
require "api/download"
|
||||
require "download_queue"
|
||||
|
||||
module Homebrew
|
||||
module API
|
||||
@ -52,9 +54,26 @@ module Homebrew
|
||||
HOMEBREW_CACHE_API/api_filename
|
||||
end
|
||||
|
||||
sig {
|
||||
params(download_queue: T.nilable(::Homebrew::DownloadQueue))
|
||||
.returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
}
|
||||
def self.fetch_api!(download_queue: nil)
|
||||
Homebrew::API.fetch_json_api_file api_filename, download_queue:
|
||||
end
|
||||
|
||||
sig {
|
||||
params(download_queue: T.nilable(::Homebrew::DownloadQueue))
|
||||
.returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
}
|
||||
def self.fetch_tap_migrations!(download_queue: nil)
|
||||
stale_seconds = Homebrew::API::TAP_MIGRATIONS_STALE_SECONDS
|
||||
Homebrew::API.fetch_json_api_file "cask_tap_migrations.jws.json", stale_seconds:, download_queue:
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def self.download_and_cache_data!
|
||||
json_casks, updated = Homebrew::API.fetch_json_api_file api_filename
|
||||
json_casks, updated = fetch_api!
|
||||
|
||||
cache["renames"] = {}
|
||||
cache["casks"] = json_casks.to_h do |json_cask|
|
||||
@ -91,6 +110,16 @@ module Homebrew
|
||||
cache.fetch("renames")
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, T.untyped]) }
|
||||
def self.tap_migrations
|
||||
unless cache.key?("tap_migrations")
|
||||
json_migrations, = fetch_tap_migrations!
|
||||
cache["tap_migrations"] = json_migrations
|
||||
end
|
||||
|
||||
cache.fetch("tap_migrations")
|
||||
end
|
||||
|
||||
sig { params(regenerate: T::Boolean).void }
|
||||
def self.write_names(regenerate: false)
|
||||
download_and_cache_data! unless cache.key?("casks")
|
||||
|
@ -17,18 +17,20 @@ module Homebrew
|
||||
|
||||
sig {
|
||||
params(
|
||||
url: String,
|
||||
checksum: T.nilable(Checksum),
|
||||
mirrors: T::Array[String],
|
||||
cache: T.nilable(Pathname),
|
||||
url: String,
|
||||
checksum: T.nilable(Checksum),
|
||||
mirrors: T::Array[String],
|
||||
cache: T.nilable(Pathname),
|
||||
require_checksum: T::Boolean,
|
||||
).void
|
||||
}
|
||||
def initialize(url, checksum, mirrors: [], cache: nil)
|
||||
def initialize(url, checksum, mirrors: [], cache: nil, require_checksum: true)
|
||||
super()
|
||||
@url = T.let(URL.new(url, using: API::DownloadStrategy), URL)
|
||||
@checksum = checksum
|
||||
@mirrors = mirrors
|
||||
@cache = cache
|
||||
@require_checksum = require_checksum
|
||||
end
|
||||
|
||||
sig { override.returns(API::DownloadStrategy) }
|
||||
@ -55,6 +57,13 @@ module Homebrew
|
||||
def symlink_location
|
||||
downloader.symlink_location
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { override.returns(T::Boolean) }
|
||||
def silence_checksum_missing_error?
|
||||
!@require_checksum
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cachable"
|
||||
require "api"
|
||||
require "api/download"
|
||||
require "download_queue"
|
||||
|
||||
module Homebrew
|
||||
module API
|
||||
@ -52,9 +54,26 @@ module Homebrew
|
||||
HOMEBREW_CACHE_API/api_filename
|
||||
end
|
||||
|
||||
sig {
|
||||
params(download_queue: T.nilable(Homebrew::DownloadQueue))
|
||||
.returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
}
|
||||
def self.fetch_api!(download_queue: nil)
|
||||
Homebrew::API.fetch_json_api_file api_filename, download_queue:
|
||||
end
|
||||
|
||||
sig {
|
||||
params(download_queue: T.nilable(Homebrew::DownloadQueue))
|
||||
.returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
||||
}
|
||||
def self.fetch_tap_migrations!(download_queue: nil)
|
||||
stale_seconds = Homebrew::API::TAP_MIGRATIONS_STALE_SECONDS
|
||||
Homebrew::API.fetch_json_api_file "formula_tap_migrations.jws.json", stale_seconds:, download_queue:
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def self.download_and_cache_data!
|
||||
json_formulae, updated = Homebrew::API.fetch_json_api_file api_filename
|
||||
json_formulae, updated = fetch_api!
|
||||
|
||||
cache["aliases"] = {}
|
||||
cache["renames"] = {}
|
||||
@ -80,7 +99,7 @@ module Homebrew
|
||||
write_names_and_aliases(regenerate: json_updated)
|
||||
end
|
||||
|
||||
cache["formulae"]
|
||||
cache.fetch("formulae")
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
@ -90,7 +109,7 @@ module Homebrew
|
||||
write_names_and_aliases(regenerate: json_updated)
|
||||
end
|
||||
|
||||
cache["aliases"]
|
||||
cache.fetch("aliases")
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
@ -100,29 +119,17 @@ module Homebrew
|
||||
write_names_and_aliases(regenerate: json_updated)
|
||||
end
|
||||
|
||||
cache["renames"]
|
||||
cache.fetch("renames")
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, T.untyped]) }
|
||||
def self.tap_migrations
|
||||
# Not sure that we need to reload here.
|
||||
unless cache.key?("tap_migrations")
|
||||
json_updated = download_and_cache_data!
|
||||
write_names_and_aliases(regenerate: json_updated)
|
||||
json_migrations, = fetch_tap_migrations!
|
||||
cache["tap_migrations"] = json_migrations
|
||||
end
|
||||
|
||||
cache["tap_migrations"]
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def self.tap_git_head
|
||||
# Note sure we need to reload here.
|
||||
unless cache.key?("tap_git_head")
|
||||
json_updated = download_and_cache_data!
|
||||
write_names_and_aliases(regenerate: json_updated)
|
||||
end
|
||||
|
||||
cache["tap_git_head"]
|
||||
cache.fetch("tap_migrations")
|
||||
end
|
||||
|
||||
sig { params(regenerate: T::Boolean).void }
|
||||
|
@ -88,6 +88,23 @@ begin
|
||||
cmd_class = Homebrew::AbstractCommand.command(cmd)
|
||||
Homebrew.running_command = cmd
|
||||
if cmd_class
|
||||
if Homebrew::EnvConfig.download_concurrency > 1
|
||||
require "download_queue"
|
||||
require "api"
|
||||
require "api/formula"
|
||||
require "api/cask"
|
||||
download_queue = Homebrew::DownloadQueue.new
|
||||
Homebrew::API::Formula.fetch_api!(download_queue:)
|
||||
Homebrew::API::Formula.fetch_tap_migrations!(download_queue:)
|
||||
Homebrew::API::Cask.fetch_api!(download_queue:)
|
||||
Homebrew::API::Cask.fetch_tap_migrations!(download_queue:)
|
||||
begin
|
||||
download_queue.fetch
|
||||
ensure
|
||||
download_queue.shutdown
|
||||
end
|
||||
end
|
||||
|
||||
command_instance = cmd_class.new
|
||||
|
||||
require "utils/analytics"
|
||||
|
@ -28,6 +28,8 @@ module Homebrew
|
||||
if pour && download.bottle?
|
||||
UnpackStrategy.detect(download.cached_download, prioritize_extension: true)
|
||||
.extract_nestedly(to: HOMEBREW_CELLAR)
|
||||
elsif download.api?
|
||||
FileUtils.touch(download.cached_download, mtime: Time.now)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -92,6 +92,9 @@ module Homebrew
|
||||
sig { returns(T::Boolean) }
|
||||
def bottle? = downloadable.is_a?(Bottle)
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def api? = downloadable.is_a?(API::Download)
|
||||
|
||||
private
|
||||
|
||||
sig { returns(Downloadable) }
|
||||
|
@ -31,9 +31,6 @@ class Tap
|
||||
HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR = "style_exceptions"
|
||||
private_constant :HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR
|
||||
|
||||
TAP_MIGRATIONS_STALE_SECONDS = 86400 # 1 day
|
||||
private_constant :TAP_MIGRATIONS_STALE_SECONDS
|
||||
|
||||
HOMEBREW_TAP_JSON_FILES = %W[
|
||||
#{HOMEBREW_TAP_FORMULA_RENAMES_FILE}
|
||||
#{HOMEBREW_TAP_CASK_RENAMES_FILE}
|
||||
@ -1312,9 +1309,7 @@ class CoreTap < AbstractCoreTap
|
||||
ensure_installed!
|
||||
super
|
||||
else
|
||||
migrations, = Homebrew::API.fetch_json_api_file "formula_tap_migrations.jws.json",
|
||||
stale_seconds: TAP_MIGRATIONS_STALE_SECONDS
|
||||
migrations
|
||||
Homebrew::API::Formula.tap_migrations
|
||||
end
|
||||
end
|
||||
|
||||
@ -1471,9 +1466,7 @@ class CoreCaskTap < AbstractCoreTap
|
||||
@tap_migrations ||= if Homebrew::EnvConfig.no_install_from_api?
|
||||
super
|
||||
else
|
||||
migrations, = Homebrew::API.fetch_json_api_file "cask_tap_migrations.jws.json",
|
||||
stale_seconds: TAP_MIGRATIONS_STALE_SECONDS
|
||||
migrations
|
||||
Homebrew::API::Cask.tap_migrations
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user