Skip to content

Commit 9303785

Browse files
authored
Merge pull request #22394 from Homebrew/cask-shared-download-queue
Share cask upgrade download queues
2 parents ee2cdf4 + a30a580 commit 9303785

13 files changed

Lines changed: 227 additions & 41 deletions

File tree

Library/Homebrew/api/cask.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,33 @@ def self.fetch_cask_json!(name)
4949
).returns(Homebrew::API::SourceDownload)
5050
}
5151
def self.source_download(cask, download_queue: Homebrew.default_download_queue, enqueue: false)
52+
download = source_download_for(cask)
53+
54+
if enqueue
55+
download_queue.enqueue(download)
56+
elsif !download.symlink_location.exist?
57+
download.fetch
58+
end
59+
60+
download
61+
end
62+
63+
sig { params(cask: ::Cask::Cask).returns(Homebrew::API::SourceDownload) }
64+
def self.source_download_for(cask)
5265
path = cask.ruby_source_path.to_s
5366
sha256 = cask.ruby_source_checksum[:sha256]
5467
checksum = Checksum.new(sha256) if sha256
5568
git_head = cask.tap_git_head || "HEAD"
5669
tap = cask.tap&.full_name || "Homebrew/homebrew-cask"
5770

58-
download = Homebrew::API::SourceDownload.new(
71+
Homebrew::API::SourceDownload.new(
5972
"https://raw.githubusercontent.com/#{tap}/#{git_head}/#{path}",
6073
checksum,
6174
mirrors: [
6275
"#{HOMEBREW_API_DEFAULT_DOMAIN}/cask-source/#{File.basename(path)}",
6376
],
6477
cache: HOMEBREW_CACHE_API_SOURCE/"#{tap}/#{git_head}/Cask",
6578
)
66-
67-
if enqueue
68-
download_queue.enqueue(download)
69-
elsif !download.symlink_location.exist?
70-
download.fetch
71-
end
72-
73-
download
7479
end
7580

7681
sig { params(cask: ::Cask::Cask).returns(::Cask::Cask) }

Library/Homebrew/cask/installer.rb

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def initialize(cask, command: SystemCommand, force: false, adopt: false,
5454
@quiet = quiet
5555
@download_queue = download_queue
5656
@defer_fetch = defer_fetch
57+
@source_download = T.let(nil, T.nilable(Homebrew::API::SourceDownload))
58+
@ran_prelude_fetch = T.let(false, T::Boolean)
5759
@ran_prelude = T.let(false, T::Boolean)
5860
@cask_and_formula_dependencies = T.let(nil, T.nilable(T::Array[T.any(Formula, ::Cask::Cask)]))
5961
end
@@ -901,13 +903,7 @@ def forbidden_cask_artifacts_check
901903
def prelude
902904
return if @ran_prelude
903905

904-
check_deprecate_disable
905-
check_conflicts
906-
check_requirements
907-
# Run the cask-self forbidden checks before loading the caskfile from the
908-
# Source API so a forbidden cask never triggers a network fetch.
909-
forbidden_tap_check(cask_only: true)
910-
forbidden_cask_and_formula_check(cask_only: true)
906+
check_prelude_requirements unless @ran_prelude_fetch
911907
load_cask_from_source_api! if cask_from_source_api?
912908
forbidden_tap_check
913909
forbidden_cask_and_formula_check
@@ -916,26 +912,73 @@ def prelude
916912
@ran_prelude = true
917913
end
918914

915+
sig { returns(T::Boolean) }
916+
def source_download_requires_pre_fetch?
917+
cask_from_source_api? && @cask.languages.any?
918+
end
919+
920+
sig { params(download_queue: Homebrew::DownloadQueue).void }
921+
def prelude_fetch(download_queue: @download_queue)
922+
return unless (download = prelude_fetch_download)
923+
924+
download_queue.enqueue(download)
925+
end
926+
927+
sig { returns(T.nilable(Homebrew::API::SourceDownload)) }
928+
def prelude_fetch_download
929+
return if @ran_prelude_fetch
930+
931+
check_prelude_requirements
932+
@ran_prelude_fetch = true
933+
return unless source_download_requires_pre_fetch?
934+
935+
if source_download.downloaded?
936+
source_download.verify_download_integrity(source_download.cached_download)
937+
source_download.downloader.create_symlink_to_cached_download(source_download.cached_download)
938+
return
939+
end
940+
941+
source_download
942+
end
943+
919944
sig { void }
920945
def enqueue_downloads
921946
download_queue = @download_queue
922-
check_requirements
947+
prelude_fetch(download_queue:) unless @ran_prelude_fetch
923948

924949
# FIXME: We need to load Cask source before enqueuing to support
925950
# language-specific URLs, but this will block the main process.
926-
if cask_from_source_api?
927-
if @cask.languages.any?
928-
load_cask_from_source_api!
929-
else
930-
Homebrew::API::Cask.source_download(@cask, download_queue:, enqueue: true)
931-
end
951+
if source_download_requires_pre_fetch?
952+
load_cask_from_source_api!
953+
elsif cask_from_source_api?
954+
Homebrew::API::Cask.source_download(@cask, download_queue:, enqueue: true)
932955
end
933956

957+
forbidden_tap_check
958+
forbidden_cask_and_formula_check
959+
forbidden_cask_artifacts_check
960+
934961
download_queue.enqueue(downloader)
935962
end
936963

937964
private
938965

966+
sig { void }
967+
def check_prelude_requirements
968+
check_deprecate_disable
969+
check_conflicts
970+
check_requirements
971+
# Run the cask-self forbidden checks before loading the caskfile from the
972+
# Source API so a forbidden cask never triggers a network fetch.
973+
forbidden_tap_check(cask_only: true)
974+
forbidden_cask_and_formula_check(cask_only: true)
975+
end
976+
977+
sig { returns(Homebrew::API::SourceDownload) }
978+
def source_download
979+
@source_download ||= Homebrew::API::Cask.source_download_for(@cask)
980+
end
981+
939982
# load the same cask file that was used for installation, if possible
940983
sig { void }
941984
def load_installed_caskfile!

Library/Homebrew/cask/reinstall.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# frozen_string_literal: true
33

44
require "utils/output"
5+
require "install"
56

67
module Cask
78
class Reinstall
@@ -58,11 +59,9 @@ def self.reinstall_casks(
5859
end
5960

6061
unless skip_prefetch
61-
cask_installers.each(&:prelude)
62-
62+
Homebrew::Install.enqueue_cask_installers(cask_installers, download_queue:)
6363
oh1 "Fetching downloads for: #{casks.map { |cask| Formatter.identifier(cask.full_name) }.to_sentence}",
6464
truncate: false
65-
cask_installers.each(&:enqueue_downloads)
6665
download_queue.fetch
6766
end
6867
ensure

Library/Homebrew/cask/upgrade.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require "cask/config"
66
require "cask/quarantine"
77
require "deprecate_disable"
8+
require "install"
89
require "utils/output"
910

1011
module Cask
@@ -245,12 +246,10 @@ def self.upgrade_casks!(
245246
# rubocop:enable Style/DoubleNegation
246247
end
247248

248-
fetchable_cask_installers.each(&:prelude)
249-
250249
fetchable_casks_sentence = fetchable_casks.map { |cask| Formatter.identifier(cask.full_name) }.to_sentence
250+
Homebrew::Install.enqueue_cask_installers(fetchable_cask_installers,
251+
download_queue: prefetch_download_queue)
251252
oh1 "Fetching downloads for: #{fetchable_casks_sentence}", truncate: false
252-
253-
fetchable_cask_installers.each(&:enqueue_downloads)
254253
prefetch_download_queue.fetch
255254
ensure
256255
prefetch_download_queue.shutdown if created_download_queue

Library/Homebrew/cmd/install.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def run
369369
)
370370
end
371371

372-
Install.enqueue_cask_installers(fetch_cask_installers)
372+
Install.enqueue_cask_installers(fetch_cask_installers, download_queue:)
373373
end
374374

375375
download_queue.fetch

Library/Homebrew/cmd/reinstall.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def run
248248
defer_fetch: true,
249249
)
250250
end
251-
Install.enqueue_cask_installers(fetch_cask_installers)
251+
Install.enqueue_cask_installers(fetch_cask_installers, download_queue: shared_download_queue)
252252
shared_download_queue.fetch
253253
casks_prefetched = true
254254
valid_formula_installers

Library/Homebrew/cmd/upgrade.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ def prefetch_outdated_casks!(casks, download_queue:, prefetch_names: nil,
748748
)
749749
end
750750
cask_names = outdated_casks.map(&:full_name)
751-
Install.enqueue_cask_installers(fetchable_cask_installers)
751+
Install.enqueue_cask_installers(fetchable_cask_installers, download_queue:)
752752
prefetch_names&.replace(cask_names)
753753
prefetch_upgrades&.replace(
754754
outdated_casks.map { |cask| "#{cask.full_name} #{cask.installed_version} -> #{cask.version}" },

Library/Homebrew/install.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,17 @@ def show_combined_fetch_downloads_heading(formula_names: [], cask_names: [])
402402
oh1 "Fetching downloads for: #{combined_fetch_targets.to_sentence}", truncate: false
403403
end
404404

405-
sig { params(cask_installers: T::Array[T.untyped]).void }
406-
def enqueue_cask_installers(cask_installers)
407-
cask_installers.each(&:prelude)
405+
sig { params(cask_installers: T::Array[T.untyped], download_queue: Homebrew::DownloadQueue).void }
406+
def enqueue_cask_installers(cask_installers, download_queue:)
407+
if cask_installers.any?(&:source_download_requires_pre_fetch?)
408+
source_downloads = cask_installers.filter_map(&:prelude_fetch_download)
409+
if source_downloads.any?
410+
oh1 "Downloading Cask files"
411+
source_downloads.each { |source_download| download_queue.enqueue(source_download) }
412+
download_queue.fetch
413+
end
414+
end
415+
408416
cask_installers.each(&:enqueue_downloads)
409417
end
410418

Library/Homebrew/test/cask/installer_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,40 @@ class #{Formulary.class_s(dep_name)} < Formula
549549
end
550550
end
551551

552+
describe "#prelude_fetch" do
553+
it "enqueues source API caskfiles before the main cask download" do
554+
cask = Cask::Cask.new("source-api-cask") do
555+
url "file://#{TEST_FIXTURE_DIR}/cask/container.tar.gz"
556+
end
557+
allow(cask).to receive_messages(loaded_from_api?: true, caskfile_only?: true, languages: ["en"])
558+
download_queue = instance_double(Homebrew::DownloadQueue)
559+
installer = klass.new(cask, download_queue:)
560+
source_download = instance_double(Homebrew::API::SourceDownload, downloaded?: false)
561+
562+
expect(Homebrew::API::Cask).to receive(:source_download_for).with(cask).and_return(source_download)
563+
expect(download_queue).to receive(:enqueue).with(source_download)
564+
expect(Homebrew::API::Cask).not_to receive(:source_download_cask)
565+
expect(installer).not_to receive(:download)
566+
567+
installer.prelude_fetch
568+
end
569+
570+
it "leaves source API caskfiles in the main queue when their URL is known" do
571+
cask = Cask::Cask.new("source-api-cask") do
572+
url "file://#{TEST_FIXTURE_DIR}/cask/container.tar.gz"
573+
end
574+
allow(cask).to receive_messages(loaded_from_api?: true, caskfile_only?: true, languages: [])
575+
download_queue = instance_double(Homebrew::DownloadQueue)
576+
installer = klass.new(cask, download_queue:)
577+
578+
expect(Homebrew::API::Cask).to receive(:source_download).with(cask, download_queue:, enqueue: true)
579+
expect(Homebrew::API::Cask).not_to receive(:source_download_cask)
580+
expect(download_queue).to receive(:enqueue).with(instance_of(Cask::Download))
581+
582+
installer.enqueue_downloads
583+
end
584+
end
585+
552586
describe "rename operations" do
553587
let(:tmpdir) { mktmpdir }
554588
let(:staged_path) { Pathname(tmpdir) }

Library/Homebrew/test/cask/reinstall_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@
6969

7070
failing_installer = instance_double(Cask::Installer)
7171
allow(failing_installer).to receive(:prelude)
72+
allow(failing_installer).to receive(:source_download_requires_pre_fetch?).and_return(false)
7273
allow(failing_installer).to receive(:enqueue_downloads)
7374
allow(failing_installer).to receive(:install).and_raise(Cask::CaskError.new("reinstall failed"))
7475

7576
successful_installer = instance_double(Cask::Installer)
7677
allow(successful_installer).to receive(:prelude)
78+
allow(successful_installer).to receive(:source_download_requires_pre_fetch?).and_return(false)
7779
allow(successful_installer).to receive(:enqueue_downloads)
7880

7981
allow(Cask::Installer).to receive(:new).and_return(failing_installer, successful_installer)

0 commit comments

Comments
 (0)