Merge pull request #20273 from Homebrew/api_download_queue
Optionally parallelise API file downloads
This commit is contained in:
commit
7bbc0a0aed
@ -13,6 +13,7 @@ module Homebrew
|
|||||||
|
|
||||||
HOMEBREW_CACHE_API = T.let((HOMEBREW_CACHE/"api").freeze, Pathname)
|
HOMEBREW_CACHE_API = T.let((HOMEBREW_CACHE/"api").freeze, Pathname)
|
||||||
HOMEBREW_CACHE_API_SOURCE = T.let((HOMEBREW_CACHE/"api-source").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]) }
|
sig { params(endpoint: String).returns(T::Hash[String, T.untyped]) }
|
||||||
def self.fetch(endpoint)
|
def self.fetch(endpoint)
|
||||||
@ -33,11 +34,11 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
sig {
|
sig {
|
||||||
params(endpoint: String, target: Pathname,
|
params(endpoint: String, target: Pathname, stale_seconds: Integer, download_queue: T.nilable(DownloadQueue))
|
||||||
stale_seconds: Integer).returns([T.any(T::Array[T.untyped], T::Hash[String, T.untyped]), T::Boolean])
|
.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,
|
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.
|
# Lazy-load dependency.
|
||||||
require "development_tools"
|
require "development_tools"
|
||||||
|
|
||||||
@ -65,6 +66,14 @@ module Homebrew
|
|||||||
((Time.now - stale_seconds) < target.mtime))
|
((Time.now - stale_seconds) < target.mtime))
|
||||||
skip_download ||= Homebrew.running_as_root_but_not_owned_by_root?
|
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
|
json_data = begin
|
||||||
begin
|
begin
|
||||||
args = curl_args.dup
|
args = curl_args.dup
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "cachable"
|
require "cachable"
|
||||||
|
require "api"
|
||||||
require "api/download"
|
require "api/download"
|
||||||
|
require "download_queue"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module API
|
module API
|
||||||
@ -52,9 +54,26 @@ module Homebrew
|
|||||||
HOMEBREW_CACHE_API/api_filename
|
HOMEBREW_CACHE_API/api_filename
|
||||||
end
|
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) }
|
sig { returns(T::Boolean) }
|
||||||
def self.download_and_cache_data!
|
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["renames"] = {}
|
||||||
cache["casks"] = json_casks.to_h do |json_cask|
|
cache["casks"] = json_casks.to_h do |json_cask|
|
||||||
@ -91,6 +110,16 @@ module Homebrew
|
|||||||
cache.fetch("renames")
|
cache.fetch("renames")
|
||||||
end
|
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 }
|
sig { params(regenerate: T::Boolean).void }
|
||||||
def self.write_names(regenerate: false)
|
def self.write_names(regenerate: false)
|
||||||
download_and_cache_data! unless cache.key?("casks")
|
download_and_cache_data! unless cache.key?("casks")
|
||||||
|
|||||||
@ -17,18 +17,20 @@ module Homebrew
|
|||||||
|
|
||||||
sig {
|
sig {
|
||||||
params(
|
params(
|
||||||
url: String,
|
url: String,
|
||||||
checksum: T.nilable(Checksum),
|
checksum: T.nilable(Checksum),
|
||||||
mirrors: T::Array[String],
|
mirrors: T::Array[String],
|
||||||
cache: T.nilable(Pathname),
|
cache: T.nilable(Pathname),
|
||||||
|
require_checksum: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def initialize(url, checksum, mirrors: [], cache: nil)
|
def initialize(url, checksum, mirrors: [], cache: nil, require_checksum: true)
|
||||||
super()
|
super()
|
||||||
@url = T.let(URL.new(url, using: API::DownloadStrategy), URL)
|
@url = T.let(URL.new(url, using: API::DownloadStrategy), URL)
|
||||||
@checksum = checksum
|
@checksum = checksum
|
||||||
@mirrors = mirrors
|
@mirrors = mirrors
|
||||||
@cache = cache
|
@cache = cache
|
||||||
|
@require_checksum = require_checksum
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { override.returns(API::DownloadStrategy) }
|
sig { override.returns(API::DownloadStrategy) }
|
||||||
@ -55,6 +57,13 @@ module Homebrew
|
|||||||
def symlink_location
|
def symlink_location
|
||||||
downloader.symlink_location
|
downloader.symlink_location
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
sig { override.returns(T::Boolean) }
|
||||||
|
def silence_checksum_missing_error?
|
||||||
|
!@require_checksum
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "cachable"
|
require "cachable"
|
||||||
|
require "api"
|
||||||
require "api/download"
|
require "api/download"
|
||||||
|
require "download_queue"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module API
|
module API
|
||||||
@ -52,9 +54,26 @@ module Homebrew
|
|||||||
HOMEBREW_CACHE_API/api_filename
|
HOMEBREW_CACHE_API/api_filename
|
||||||
end
|
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) }
|
sig { returns(T::Boolean) }
|
||||||
def self.download_and_cache_data!
|
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["aliases"] = {}
|
||||||
cache["renames"] = {}
|
cache["renames"] = {}
|
||||||
@ -80,7 +99,7 @@ module Homebrew
|
|||||||
write_names_and_aliases(regenerate: json_updated)
|
write_names_and_aliases(regenerate: json_updated)
|
||||||
end
|
end
|
||||||
|
|
||||||
cache["formulae"]
|
cache.fetch("formulae")
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T::Hash[String, String]) }
|
sig { returns(T::Hash[String, String]) }
|
||||||
@ -90,7 +109,7 @@ module Homebrew
|
|||||||
write_names_and_aliases(regenerate: json_updated)
|
write_names_and_aliases(regenerate: json_updated)
|
||||||
end
|
end
|
||||||
|
|
||||||
cache["aliases"]
|
cache.fetch("aliases")
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T::Hash[String, String]) }
|
sig { returns(T::Hash[String, String]) }
|
||||||
@ -100,29 +119,17 @@ module Homebrew
|
|||||||
write_names_and_aliases(regenerate: json_updated)
|
write_names_and_aliases(regenerate: json_updated)
|
||||||
end
|
end
|
||||||
|
|
||||||
cache["renames"]
|
cache.fetch("renames")
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T.untyped]) }
|
sig { returns(T::Hash[String, T.untyped]) }
|
||||||
def self.tap_migrations
|
def self.tap_migrations
|
||||||
# Not sure that we need to reload here.
|
|
||||||
unless cache.key?("tap_migrations")
|
unless cache.key?("tap_migrations")
|
||||||
json_updated = download_and_cache_data!
|
json_migrations, = fetch_tap_migrations!
|
||||||
write_names_and_aliases(regenerate: json_updated)
|
cache["tap_migrations"] = json_migrations
|
||||||
end
|
end
|
||||||
|
|
||||||
cache["tap_migrations"]
|
cache.fetch("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"]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { params(regenerate: T::Boolean).void }
|
sig { params(regenerate: T::Boolean).void }
|
||||||
|
|||||||
@ -88,6 +88,23 @@ begin
|
|||||||
cmd_class = Homebrew::AbstractCommand.command(cmd)
|
cmd_class = Homebrew::AbstractCommand.command(cmd)
|
||||||
Homebrew.running_command = cmd
|
Homebrew.running_command = cmd
|
||||||
if cmd_class
|
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
|
command_instance = cmd_class.new
|
||||||
|
|
||||||
require "utils/analytics"
|
require "utils/analytics"
|
||||||
|
|||||||
@ -28,6 +28,8 @@ module Homebrew
|
|||||||
if pour && download.bottle?
|
if pour && download.bottle?
|
||||||
UnpackStrategy.detect(download.cached_download, prioritize_extension: true)
|
UnpackStrategy.detect(download.cached_download, prioritize_extension: true)
|
||||||
.extract_nestedly(to: HOMEBREW_CELLAR)
|
.extract_nestedly(to: HOMEBREW_CELLAR)
|
||||||
|
elsif download.api?
|
||||||
|
FileUtils.touch(download.cached_download, mtime: Time.now)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -92,6 +92,9 @@ module Homebrew
|
|||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def bottle? = downloadable.is_a?(Bottle)
|
def bottle? = downloadable.is_a?(Bottle)
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def api? = downloadable.is_a?(API::Download)
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
sig { returns(Downloadable) }
|
sig { returns(Downloadable) }
|
||||||
|
|||||||
@ -31,9 +31,6 @@ class Tap
|
|||||||
HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR = "style_exceptions"
|
HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR = "style_exceptions"
|
||||||
private_constant :HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR
|
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_JSON_FILES = %W[
|
||||||
#{HOMEBREW_TAP_FORMULA_RENAMES_FILE}
|
#{HOMEBREW_TAP_FORMULA_RENAMES_FILE}
|
||||||
#{HOMEBREW_TAP_CASK_RENAMES_FILE}
|
#{HOMEBREW_TAP_CASK_RENAMES_FILE}
|
||||||
@ -1312,9 +1309,7 @@ class CoreTap < AbstractCoreTap
|
|||||||
ensure_installed!
|
ensure_installed!
|
||||||
super
|
super
|
||||||
else
|
else
|
||||||
migrations, = Homebrew::API.fetch_json_api_file "formula_tap_migrations.jws.json",
|
Homebrew::API::Formula.tap_migrations
|
||||||
stale_seconds: TAP_MIGRATIONS_STALE_SECONDS
|
|
||||||
migrations
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1471,9 +1466,7 @@ class CoreCaskTap < AbstractCoreTap
|
|||||||
@tap_migrations ||= if Homebrew::EnvConfig.no_install_from_api?
|
@tap_migrations ||= if Homebrew::EnvConfig.no_install_from_api?
|
||||||
super
|
super
|
||||||
else
|
else
|
||||||
migrations, = Homebrew::API.fetch_json_api_file "cask_tap_migrations.jws.json",
|
Homebrew::API::Cask.tap_migrations
|
||||||
stale_seconds: TAP_MIGRATIONS_STALE_SECONDS
|
|
||||||
migrations
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user