Skip to content

Commit a3d6ee1

Browse files
committed
Refactor DownloadQueue handling
- Use undocumented (for now) `HOMEBREW_DOWNLOAD_CONCURRENCY` instead of `--concurrency` flag and avoid passing around `concurrency` - Create and use `Formula#enqueue_resources_and_patches` helper method - Rename some method calls to be more obvious - Use `Downloadable` type to simplify type checks - General refactoring
1 parent 46ba380 commit a3d6ee1

6 files changed

Lines changed: 37 additions & 29 deletions

File tree

Library/Homebrew/cmd/fetch.rb

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ class FetchCmd < AbstractCommand
2626
"(Pass `all` to download for all architectures.)"
2727
flag "--bottle-tag=",
2828
description: "Download a bottle for given tag."
29-
flag "--concurrency=", description: "Number of concurrent downloads.", hidden: true
3029
switch "--HEAD",
3130
description: "Fetch HEAD version instead of stable version."
3231
switch "-f", "--force",
@@ -150,12 +149,7 @@ def run
150149
download_queue.enqueue(resource)
151150
end
152151

153-
formula.resources.each do |r|
154-
download_queue.enqueue(r)
155-
r.patches.each { |patch| download_queue.enqueue(patch.resource) if patch.external? }
156-
end
157-
158-
formula.patchlist.each { |patch| download_queue.enqueue(patch.resource) if patch.external? }
152+
formula.enqueue_resources_and_patches(download_queue:)
159153
end
160154
end
161155
else
@@ -181,18 +175,13 @@ def run
181175
end
182176
end
183177

184-
download_queue.start
178+
download_queue.fetch
185179
ensure
186180
download_queue.shutdown
187181
end
188182

189183
private
190184

191-
sig { returns(Integer) }
192-
def concurrency
193-
@concurrency ||= T.let(args.concurrency&.to_i || 1, T.nilable(Integer))
194-
end
195-
196185
sig { returns(Integer) }
197186
def retries
198187
@retries ||= T.let(args.retry? ? FETCH_MAX_TRIES : 0, T.nilable(Integer))
@@ -201,7 +190,7 @@ def retries
201190
sig { returns(DownloadQueue) }
202191
def download_queue
203192
@download_queue ||= T.let(begin
204-
DownloadQueue.new(concurrency:, retries:, force: args.force?)
193+
DownloadQueue.new(retries:, force: args.force?)
205194
end, T.nilable(DownloadQueue))
206195
end
207196
end

Library/Homebrew/download_queue.rb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99
module Homebrew
1010
class DownloadQueue
11-
sig { params(concurrency: Integer, retries: Integer, force: T::Boolean).void }
12-
def initialize(concurrency:, retries:, force:)
13-
@concurrency = concurrency
14-
@quiet = T.let(concurrency > 1, T::Boolean)
11+
sig { params(retries: Integer, force: T::Boolean).void }
12+
def initialize(retries: 0, force: false)
13+
@concurrency = T.let(EnvConfig.download_concurrency, Integer)
14+
@quiet = T.let(@concurrency > 1, T::Boolean)
1515
@tries = T.let(retries + 1, Integer)
1616
@force = force
1717
@pool = T.let(Concurrent::FixedThreadPool.new(concurrency), Concurrent::FixedThreadPool)
1818
end
1919

20-
sig { params(downloadable: T.any(Resource, Bottle, Cask::Download)).void }
20+
sig { params(downloadable: Downloadable).void }
2121
def enqueue(downloadable)
2222
downloads[downloadable] ||= Concurrent::Promises.future_on(
2323
pool, RetryableDownload.new(downloadable, tries:), force, quiet
@@ -28,7 +28,7 @@ def enqueue(downloadable)
2828
end
2929

3030
sig { void }
31-
def start
31+
def fetch
3232
if concurrency == 1
3333
downloads.each do |downloadable, promise|
3434
promise.wait!
@@ -133,6 +133,8 @@ def start
133133
$stdout.flush
134134
end
135135
end
136+
137+
downloads.clear
136138
end
137139

138140
sig { void }
@@ -166,10 +168,9 @@ def cancel
166168
sig { returns(T::Boolean) }
167169
attr_reader :quiet
168170

169-
sig { returns(T::Hash[T.any(Resource, Bottle, Cask::Download), Concurrent::Promises::Future]) }
171+
sig { returns(T::Hash[Downloadable, Concurrent::Promises::Future]) }
170172
def downloads
171-
@downloads ||= T.let({}, T.nilable(T::Hash[T.any(Resource, Bottle, Cask::Download),
172-
Concurrent::Promises::Future]))
173+
@downloads ||= T.let({}, T.nilable(T::Hash[Downloadable, Concurrent::Promises::Future]))
173174
end
174175

175176
class Spinner

Library/Homebrew/env_config.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,5 +630,13 @@ def automatically_set_no_install_from_api?
630630
def devcmdrun?
631631
Homebrew::Settings.read("devcmdrun") == "true"
632632
end
633+
634+
sig { returns(Integer) }
635+
def download_concurrency
636+
# TODO: document this variable when ready to publicly announce it.
637+
concurrency = ENV.fetch("HOMEBREW_DOWNLOAD_CONCURRENCY", 1).to_i
638+
concurrency = 1 if concurrency <= 1
639+
concurrency
640+
end
633641
end
634642
end

Library/Homebrew/formula.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,15 @@ def xcodebuild(*args)
32023202
end
32033203
end
32043204

3205+
sig { params(download_queue: Homebrew::DownloadQueue).void }
3206+
def enqueue_resources_and_patches(download_queue:)
3207+
resources.each do |resource|
3208+
download_queue.enqueue(resource)
3209+
resource.patches.select(&:external?).each { |patch| download_queue.enqueue(patch.resource) }
3210+
end
3211+
patchlist.select(&:external?).each { |patch| download_queue.enqueue(patch.resource) }
3212+
end
3213+
32053214
sig { void }
32063215
def fetch_patches
32073216
patchlist.select(&:external?).each(&:fetch)

Library/Homebrew/retryable_download.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ module Homebrew
55
class RetryableDownload
66
include Downloadable
77

8-
sig { returns(Downloadable) }
9-
attr_reader :downloadable
10-
private :downloadable
11-
128
sig { override.returns(T.any(NilClass, String, URL)) }
139
def url = downloadable.url
1410

@@ -92,5 +88,10 @@ def verify_download_integrity(filename) = downloadable.verify_download_integrity
9288

9389
sig { override.returns(String) }
9490
def download_name = downloadable.download_name
91+
92+
private
93+
94+
sig { returns(Downloadable) }
95+
attr_reader :downloadable
9596
end
9697
end

Library/Homebrew/test/cmd/fetch_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
setup_test_formula "testball1"
2020
setup_test_formula "testball2"
2121

22-
expect { brew "fetch", "testball1", "testball2", "--concurrency=2" }.to be_a_success
22+
expect { brew "fetch", "testball1", "testball2", "HOMEBREW_DOWNLOAD_CONCURRENCY" => "2" }.to be_a_success
2323

2424
expect(HOMEBREW_CACHE/"testball1--0.1.tbz").to be_a_symlink
2525
expect(HOMEBREW_CACHE/"testball1--0.1.tbz").to exist
@@ -33,7 +33,7 @@
3333
setup_test_formula "testball1"
3434
setup_test_formula "testball3"
3535

36-
expect { brew "fetch", "testball1", "testball3", "--concurrency=2" }.to be_a_failure
36+
expect { brew "fetch", "testball1", "testball3", "HOMEBREW_DOWNLOAD_CONCURRENCY" => "2" }.to be_a_failure
3737
.and output(/Error:.*process has already locked/).to_stderr
3838
end
3939
end

0 commit comments

Comments
 (0)