bundler 4.0.8 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/bundler/build_metadata.rb +2 -2
- data/lib/bundler/cli/pristine.rb +1 -1
- data/lib/bundler/definition.rb +3 -1
- data/lib/bundler/fetcher/gem_remote_fetcher.rb +1 -1
- data/lib/bundler/installer/gem_installer.rb +14 -0
- data/lib/bundler/installer/parallel_installer.rb +63 -17
- data/lib/bundler/installer.rb +1 -9
- data/lib/bundler/man/bundle-config.1 +1 -1
- data/lib/bundler/man/bundle-config.1.ronn +2 -2
- data/lib/bundler/plugin/api/source.rb +8 -0
- data/lib/bundler/plugin/installer.rb +2 -1
- data/lib/bundler/retry.rb +30 -4
- data/lib/bundler/self_manager.rb +1 -0
- data/lib/bundler/settings.rb +4 -0
- data/lib/bundler/source/git/git_proxy.rb +49 -15
- data/lib/bundler/source/rubygems.rb +48 -26
- data/lib/bundler/source.rb +2 -0
- data/lib/bundler/version.rb +1 -1
- data/lib/bundler/worker.rb +11 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff315eb3319300026b3ab3422e82399e6b0ce63ef727f94e125a226623101c27
|
|
4
|
+
data.tar.gz: 00bb903a5564f2565ebcbc350837283f724d1ef42d4f586b37a972fe568015da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6a4c93541bd76ee07370d4995487fe663f10d8aa021f1d9104d6adfeb373a36bbc47fd3498094da011c561702d7a84ebb1854c80c99176578b0fbc666e2dba2
|
|
7
|
+
data.tar.gz: 29943339931f1e5b37c836346171c51f2a00a2cadbd7d7b5f30da5dd5bacb1f1024b7601ded1e1d895a3da4e11cf1d6ea35768a7196b351e237179d63759cd13
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.0.9 / 2026-03-25
|
|
4
|
+
|
|
5
|
+
### Enhancements:
|
|
6
|
+
|
|
7
|
+
* Check the git version only **once** per `bundle install`. Pull request [#9406](https://github.com/ruby/rubygems/pull/9406) by Edouard-chin
|
|
8
|
+
* Normalize the number of workers when performing parallel operations. Pull request [#9400](https://github.com/ruby/rubygems/pull/9400) by Edouard-chin
|
|
9
|
+
* Add exponential backoff to bundler retries. Pull request [#9163](https://github.com/ruby/rubygems/pull/9163) by ChrisBr
|
|
10
|
+
* Introduce a priority queue. Pull request [#9389](https://github.com/ruby/rubygems/pull/9389) by Edouard-chin
|
|
11
|
+
* Split the download and install process of a gem. Pull request [#9381](https://github.com/ruby/rubygems/pull/9381) by Edouard-chin
|
|
12
|
+
|
|
13
|
+
### Bug fixes:
|
|
14
|
+
|
|
15
|
+
* Retry git fetch without --depth for dumb HTTP transport. Pull request [#9405](https://github.com/ruby/rubygems/pull/9405) by hsbt
|
|
16
|
+
|
|
3
17
|
## 4.0.8 (2026-03-11)
|
|
4
18
|
|
|
5
19
|
### Enhancements:
|
|
@@ -4,8 +4,8 @@ module Bundler
|
|
|
4
4
|
# Represents metadata from when the Bundler gem was built.
|
|
5
5
|
module BuildMetadata
|
|
6
6
|
# begin ivars
|
|
7
|
-
@built_at =
|
|
8
|
-
@git_commit_sha = "
|
|
7
|
+
@built_at = nil
|
|
8
|
+
@git_commit_sha = "3ce4a32411".freeze
|
|
9
9
|
# end ivars
|
|
10
10
|
|
|
11
11
|
# A hash representation of the build metadata.
|
data/lib/bundler/cli/pristine.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Bundler
|
|
|
53
53
|
true
|
|
54
54
|
end.map(&:name)
|
|
55
55
|
|
|
56
|
-
jobs =
|
|
56
|
+
jobs = Bundler.settings.installation_parallelization
|
|
57
57
|
pristine_count = definition.specs.count - installed_specs.count
|
|
58
58
|
# allow a pristining a single gem to skip the parallel worker
|
|
59
59
|
jobs = [jobs, pristine_count].min
|
data/lib/bundler/definition.rb
CHANGED
|
@@ -1122,7 +1122,9 @@ module Bundler
|
|
|
1122
1122
|
end
|
|
1123
1123
|
|
|
1124
1124
|
def preload_git_source_worker
|
|
1125
|
-
|
|
1125
|
+
workers = Bundler.settings.installation_parallelization
|
|
1126
|
+
|
|
1127
|
+
@preload_git_source_worker ||= Bundler::Worker.new(workers, "Git source preloading", ->(source, _) { source.specs })
|
|
1126
1128
|
end
|
|
1127
1129
|
|
|
1128
1130
|
def preload_git_sources
|
|
@@ -25,6 +25,20 @@ module Bundler
|
|
|
25
25
|
[false, specific_failure_message(e)]
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def download
|
|
29
|
+
spec.source.download(
|
|
30
|
+
spec,
|
|
31
|
+
force: force,
|
|
32
|
+
local: local,
|
|
33
|
+
build_args: Array(spec_settings),
|
|
34
|
+
previous_spec: previous_spec,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
[true, nil]
|
|
38
|
+
rescue Bundler::BundlerError => e
|
|
39
|
+
[false, specific_failure_message(e)]
|
|
40
|
+
end
|
|
41
|
+
|
|
28
42
|
private
|
|
29
43
|
|
|
30
44
|
def specific_failure_message(e)
|
|
@@ -24,6 +24,10 @@ module Bundler
|
|
|
24
24
|
state == :enqueued
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def enqueue_with_priority?
|
|
28
|
+
state == :installable && spec.extensions.any?
|
|
29
|
+
end
|
|
30
|
+
|
|
27
31
|
def failed?
|
|
28
32
|
state == :failed
|
|
29
33
|
end
|
|
@@ -32,6 +36,12 @@ module Bundler
|
|
|
32
36
|
state == :none
|
|
33
37
|
end
|
|
34
38
|
|
|
39
|
+
def ready_to_install?(installed_specs)
|
|
40
|
+
return false unless state == :downloaded
|
|
41
|
+
|
|
42
|
+
spec.extensions.none? || dependencies_installed?(installed_specs)
|
|
43
|
+
end
|
|
44
|
+
|
|
35
45
|
def has_post_install_message?
|
|
36
46
|
!post_install_message.empty?
|
|
37
47
|
end
|
|
@@ -84,6 +94,7 @@ module Bundler
|
|
|
84
94
|
|
|
85
95
|
def call
|
|
86
96
|
if @rake
|
|
97
|
+
do_download(@rake, 0)
|
|
87
98
|
do_install(@rake, 0)
|
|
88
99
|
Gem::Specification.reset
|
|
89
100
|
end
|
|
@@ -107,26 +118,54 @@ module Bundler
|
|
|
107
118
|
end
|
|
108
119
|
|
|
109
120
|
def install_with_worker
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
installed_specs = {}
|
|
122
|
+
enqueue_specs(installed_specs)
|
|
123
|
+
|
|
124
|
+
process_specs(installed_specs) until finished_installing?
|
|
112
125
|
end
|
|
113
126
|
|
|
114
127
|
def install_serially
|
|
115
128
|
until finished_installing?
|
|
116
129
|
raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?)
|
|
117
130
|
spec_install.state = :enqueued
|
|
131
|
+
do_download(spec_install, 0)
|
|
118
132
|
do_install(spec_install, 0)
|
|
119
133
|
end
|
|
120
134
|
end
|
|
121
135
|
|
|
122
136
|
def worker_pool
|
|
123
137
|
@worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num|
|
|
124
|
-
|
|
138
|
+
case spec_install.state
|
|
139
|
+
when :enqueued
|
|
140
|
+
do_download(spec_install, worker_num)
|
|
141
|
+
when :installable
|
|
142
|
+
do_install(spec_install, worker_num)
|
|
143
|
+
else
|
|
144
|
+
spec_install
|
|
145
|
+
end
|
|
125
146
|
}
|
|
126
147
|
end
|
|
127
148
|
|
|
128
|
-
def
|
|
149
|
+
def do_download(spec_install, worker_num)
|
|
129
150
|
Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install)
|
|
151
|
+
|
|
152
|
+
gem_installer = Bundler::GemInstaller.new(
|
|
153
|
+
spec_install.spec, @installer, @standalone, worker_num, @force, @local
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
success, message = gem_installer.download
|
|
157
|
+
|
|
158
|
+
if success
|
|
159
|
+
spec_install.state = :downloaded
|
|
160
|
+
else
|
|
161
|
+
spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
|
|
162
|
+
spec_install.state = :failed
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
spec_install
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def do_install(spec_install, worker_num)
|
|
130
169
|
gem_installer = Bundler::GemInstaller.new(
|
|
131
170
|
spec_install.spec, @installer, @standalone, worker_num, @force, @local
|
|
132
171
|
)
|
|
@@ -147,9 +186,19 @@ module Bundler
|
|
|
147
186
|
# Some specs might've had to wait til this spec was installed to be
|
|
148
187
|
# processed so the call to `enqueue_specs` is important after every
|
|
149
188
|
# dequeue.
|
|
150
|
-
def process_specs
|
|
151
|
-
worker_pool.deq
|
|
152
|
-
|
|
189
|
+
def process_specs(installed_specs)
|
|
190
|
+
spec = worker_pool.deq
|
|
191
|
+
|
|
192
|
+
if spec.installed?
|
|
193
|
+
installed_specs[spec.name] = true
|
|
194
|
+
return
|
|
195
|
+
elsif spec.failed?
|
|
196
|
+
return
|
|
197
|
+
elsif spec.ready_to_install?(installed_specs)
|
|
198
|
+
spec.state = :installable
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
worker_pool.enq(spec, priority: spec.enqueue_with_priority?)
|
|
153
202
|
end
|
|
154
203
|
|
|
155
204
|
def finished_installing?
|
|
@@ -185,18 +234,15 @@ module Bundler
|
|
|
185
234
|
# Later we call this lambda again to install specs that depended on
|
|
186
235
|
# previously installed specifications. We continue until all specs
|
|
187
236
|
# are installed.
|
|
188
|
-
def enqueue_specs
|
|
189
|
-
installed_specs = {}
|
|
190
|
-
@specs.each do |spec|
|
|
191
|
-
next unless spec.installed?
|
|
192
|
-
installed_specs[spec.name] = true
|
|
193
|
-
end
|
|
194
|
-
|
|
237
|
+
def enqueue_specs(installed_specs)
|
|
195
238
|
@specs.each do |spec|
|
|
196
|
-
if spec.
|
|
197
|
-
spec.
|
|
198
|
-
|
|
239
|
+
if spec.installed?
|
|
240
|
+
installed_specs[spec.name] = true
|
|
241
|
+
next
|
|
199
242
|
end
|
|
243
|
+
|
|
244
|
+
spec.state = :enqueued
|
|
245
|
+
worker_pool.enq spec
|
|
200
246
|
end
|
|
201
247
|
end
|
|
202
248
|
end
|
data/lib/bundler/installer.rb
CHANGED
|
@@ -189,21 +189,13 @@ module Bundler
|
|
|
189
189
|
standalone = options[:standalone]
|
|
190
190
|
force = options[:force]
|
|
191
191
|
local = options[:local] || options[:"prefer-local"]
|
|
192
|
-
jobs = installation_parallelization
|
|
192
|
+
jobs = Bundler.settings.installation_parallelization
|
|
193
193
|
spec_installations = ParallelInstaller.call(self, @definition.specs, jobs, standalone, force, local: local)
|
|
194
194
|
spec_installations.each do |installation|
|
|
195
195
|
post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
-
def installation_parallelization
|
|
200
|
-
if jobs = Bundler.settings[:jobs]
|
|
201
|
-
return jobs
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
Bundler.settings.processor_count
|
|
205
|
-
end
|
|
206
|
-
|
|
207
199
|
def load_plugins
|
|
208
200
|
Gem.load_plugins
|
|
209
201
|
|
|
@@ -146,7 +146,7 @@ When set, no post install messages will be printed\. To silence a single gem, us
|
|
|
146
146
|
Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\.
|
|
147
147
|
.TP
|
|
148
148
|
\fBjobs\fR (\fBBUNDLE_JOBS\fR)
|
|
149
|
-
The number of gems Bundler can install in parallel\. Defaults to the number of available processors\.
|
|
149
|
+
The number of gems Bundler can download and install in parallel\. Defaults to the number of available processors\.
|
|
150
150
|
.TP
|
|
151
151
|
\fBlockfile\fR (\fBBUNDLE_LOCKFILE\fR)
|
|
152
152
|
The path to the lockfile that bundler should use\. By default, Bundler adds \fB\.lock\fR to the end of the \fBgemfile\fR entry\. Can be set to \fBfalse\fR in the Gemfile to disable lockfile creation entirely (see gemfile(5))\.
|
|
@@ -192,8 +192,8 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
|
|
|
192
192
|
* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`):
|
|
193
193
|
Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`.
|
|
194
194
|
* `jobs` (`BUNDLE_JOBS`):
|
|
195
|
-
The number of gems Bundler can install in parallel.
|
|
196
|
-
available processors.
|
|
195
|
+
The number of gems Bundler can download and install in parallel.
|
|
196
|
+
Defaults to the number of available processors.
|
|
197
197
|
* `lockfile` (`BUNDLE_LOCKFILE`):
|
|
198
198
|
The path to the lockfile that bundler should use. By default, Bundler adds
|
|
199
199
|
`.lock` to the end of the `gemfile` entry. Can be set to `false` in the
|
|
@@ -74,6 +74,14 @@ module Bundler
|
|
|
74
74
|
{}
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
# Download the gem specified by the spec at appropriate path.
|
|
78
|
+
#
|
|
79
|
+
# A source plugin can implement this method to split the download and the
|
|
80
|
+
# installation of a gem.
|
|
81
|
+
#
|
|
82
|
+
# @return [Boolean] Whether the download of the gem succeeded.
|
|
83
|
+
def download(spec, opts); end
|
|
84
|
+
|
|
77
85
|
# Install the gem specified by the spec at appropriate path.
|
|
78
86
|
# `install_path` provides a sufficient default, if the source can only
|
|
79
87
|
# satisfy one gem, but is not binding.
|
data/lib/bundler/retry.rb
CHANGED
|
@@ -6,6 +6,8 @@ module Bundler
|
|
|
6
6
|
attr_accessor :name, :total_runs, :current_run
|
|
7
7
|
|
|
8
8
|
class << self
|
|
9
|
+
attr_accessor :default_base_delay
|
|
10
|
+
|
|
9
11
|
def default_attempts
|
|
10
12
|
default_retries + 1
|
|
11
13
|
end
|
|
@@ -16,11 +18,17 @@ module Bundler
|
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
# Set default base delay for exponential backoff
|
|
22
|
+
self.default_base_delay = 1.0
|
|
23
|
+
|
|
24
|
+
def initialize(name, exceptions = nil, retries = self.class.default_retries, opts = {})
|
|
20
25
|
@name = name
|
|
21
26
|
@retries = retries
|
|
22
27
|
@exceptions = Array(exceptions) || []
|
|
23
28
|
@total_runs = @retries + 1 # will run once, then upto attempts.times
|
|
29
|
+
@base_delay = opts[:base_delay] || self.class.default_base_delay
|
|
30
|
+
@max_delay = opts[:max_delay] || 60.0
|
|
31
|
+
@jitter = opts[:jitter] || 0.5
|
|
24
32
|
end
|
|
25
33
|
|
|
26
34
|
def attempt(&block)
|
|
@@ -48,9 +56,27 @@ module Bundler
|
|
|
48
56
|
Bundler.ui.info "" unless Bundler.ui.debug?
|
|
49
57
|
raise e
|
|
50
58
|
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
if name
|
|
60
|
+
Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this
|
|
61
|
+
Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", true
|
|
62
|
+
end
|
|
63
|
+
backoff_sleep if @base_delay > 0
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def backoff_sleep
|
|
68
|
+
# Exponential backoff: delay = base_delay * 2^(attempt - 1)
|
|
69
|
+
# Add jitter to prevent thundering herd: random value between 0 and jitter seconds
|
|
70
|
+
delay = @base_delay * (2**(@current_run - 1))
|
|
71
|
+
delay = [@max_delay, delay].min
|
|
72
|
+
jitter_amount = rand * @jitter
|
|
73
|
+
total_delay = delay + jitter_amount
|
|
74
|
+
Bundler.ui.debug "Sleeping for #{total_delay.round(2)} seconds before retry"
|
|
75
|
+
sleep(total_delay)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def sleep(duration)
|
|
79
|
+
Kernel.sleep(duration)
|
|
54
80
|
end
|
|
55
81
|
|
|
56
82
|
def keep_trying?
|
data/lib/bundler/self_manager.rb
CHANGED
data/lib/bundler/settings.rb
CHANGED
|
@@ -303,6 +303,10 @@ module Bundler
|
|
|
303
303
|
@app_cache_path ||= self[:cache_path] || "vendor/cache"
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
+
def installation_parallelization
|
|
307
|
+
self[:jobs] || processor_count
|
|
308
|
+
end
|
|
309
|
+
|
|
306
310
|
def validate!
|
|
307
311
|
all.each do |raw_key|
|
|
308
312
|
[@local_config, @env_config, @global_config].each do |settings|
|
|
@@ -57,6 +57,29 @@ module Bundler
|
|
|
57
57
|
attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref
|
|
58
58
|
attr_writer :revision
|
|
59
59
|
|
|
60
|
+
def self.version
|
|
61
|
+
@version ||= full_version[/((\.?\d+)+).*/, 1]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.full_version
|
|
65
|
+
@full_version ||= begin
|
|
66
|
+
raise GitNotInstalledError.new unless Bundler.git_present?
|
|
67
|
+
|
|
68
|
+
require "open3"
|
|
69
|
+
out, err, status = Open3.capture3("git", "--version")
|
|
70
|
+
|
|
71
|
+
raise GitCommandError.new("--version", SharedHelpers.pwd, err) unless status.success?
|
|
72
|
+
Bundler.ui.warn err unless err.empty?
|
|
73
|
+
|
|
74
|
+
out.sub(/git version\s*/, "").strip
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.reset
|
|
79
|
+
@version = nil
|
|
80
|
+
@full_version = nil
|
|
81
|
+
end
|
|
82
|
+
|
|
60
83
|
def initialize(path, uri, options = {}, revision = nil, git = nil)
|
|
61
84
|
@path = path
|
|
62
85
|
@uri = uri
|
|
@@ -92,11 +115,11 @@ module Bundler
|
|
|
92
115
|
end
|
|
93
116
|
|
|
94
117
|
def version
|
|
95
|
-
|
|
118
|
+
self.class.version
|
|
96
119
|
end
|
|
97
120
|
|
|
98
121
|
def full_version
|
|
99
|
-
|
|
122
|
+
self.class.full_version
|
|
100
123
|
end
|
|
101
124
|
|
|
102
125
|
def checkout
|
|
@@ -156,7 +179,7 @@ module Bundler
|
|
|
156
179
|
private
|
|
157
180
|
|
|
158
181
|
def git_remote_fetch(args)
|
|
159
|
-
command =
|
|
182
|
+
command = fetch_command(args)
|
|
160
183
|
command_with_no_credentials = check_allowed(command)
|
|
161
184
|
|
|
162
185
|
Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do
|
|
@@ -166,6 +189,11 @@ module Bundler
|
|
|
166
189
|
if err.include?("couldn't find remote ref") || err.include?("not our ref")
|
|
167
190
|
raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri)
|
|
168
191
|
else
|
|
192
|
+
if shallow?
|
|
193
|
+
args -= depth_args
|
|
194
|
+
command = fetch_command(args)
|
|
195
|
+
command_with_no_credentials = check_allowed(command)
|
|
196
|
+
end
|
|
169
197
|
raise GitCommandError.new(command_with_no_credentials, path, err)
|
|
170
198
|
end
|
|
171
199
|
end
|
|
@@ -178,7 +206,8 @@ module Bundler
|
|
|
178
206
|
FileUtils.mkdir_p(p)
|
|
179
207
|
end
|
|
180
208
|
|
|
181
|
-
|
|
209
|
+
clone_args = extra_clone_args
|
|
210
|
+
command = clone_command(clone_args)
|
|
182
211
|
command_with_no_credentials = check_allowed(command)
|
|
183
212
|
|
|
184
213
|
Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do
|
|
@@ -189,13 +218,10 @@ module Bundler
|
|
|
189
218
|
err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher
|
|
190
219
|
raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
|
|
191
220
|
else
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
command
|
|
195
|
-
command.delete_at(idx)
|
|
221
|
+
if shallow?
|
|
222
|
+
clone_args -= depth_args
|
|
223
|
+
command = clone_command(clone_args)
|
|
196
224
|
command_with_no_credentials = check_allowed(command)
|
|
197
|
-
|
|
198
|
-
err += "Retrying without --depth argument."
|
|
199
225
|
end
|
|
200
226
|
raise GitCommandError.new(command_with_no_credentials, path, err)
|
|
201
227
|
end
|
|
@@ -204,14 +230,14 @@ module Bundler
|
|
|
204
230
|
|
|
205
231
|
def clone_needs_unshallow?
|
|
206
232
|
return false unless path.join("shallow").exist?
|
|
207
|
-
return true
|
|
233
|
+
return true unless shallow?
|
|
208
234
|
|
|
209
235
|
@revision && @revision != head_revision
|
|
210
236
|
end
|
|
211
237
|
|
|
212
238
|
def extra_ref
|
|
213
239
|
return false if not_pinned?
|
|
214
|
-
return true
|
|
240
|
+
return true if shallow?
|
|
215
241
|
|
|
216
242
|
ref.start_with?("refs/")
|
|
217
243
|
end
|
|
@@ -427,8 +453,16 @@ module Bundler
|
|
|
427
453
|
args
|
|
428
454
|
end
|
|
429
455
|
|
|
456
|
+
def fetch_command(args)
|
|
457
|
+
["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def clone_command(args)
|
|
461
|
+
["clone", "--bare", "--no-hardlinks", "--quiet", *args, "--", configured_uri, path.to_s]
|
|
462
|
+
end
|
|
463
|
+
|
|
430
464
|
def depth_args
|
|
431
|
-
return []
|
|
465
|
+
return [] unless shallow?
|
|
432
466
|
|
|
433
467
|
["--depth", depth.to_s]
|
|
434
468
|
end
|
|
@@ -443,8 +477,8 @@ module Bundler
|
|
|
443
477
|
branch || tag
|
|
444
478
|
end
|
|
445
479
|
|
|
446
|
-
def
|
|
447
|
-
depth.nil?
|
|
480
|
+
def shallow?
|
|
481
|
+
!depth.nil?
|
|
448
482
|
end
|
|
449
483
|
|
|
450
484
|
def needs_allow_any_sha1_in_want?
|
|
@@ -9,6 +9,7 @@ module Bundler
|
|
|
9
9
|
|
|
10
10
|
# Ask for X gems per API request
|
|
11
11
|
API_REQUEST_SIZE = 100
|
|
12
|
+
REQUIRE_MUTEX = Mutex.new
|
|
12
13
|
|
|
13
14
|
attr_accessor :remotes
|
|
14
15
|
|
|
@@ -21,6 +22,8 @@ module Bundler
|
|
|
21
22
|
@allow_local = options["allow_local"] || false
|
|
22
23
|
@prefer_local = false
|
|
23
24
|
@checksum_store = Checksum::Store.new
|
|
25
|
+
@gem_installers = {}
|
|
26
|
+
@gem_installers_mutex = Mutex.new
|
|
24
27
|
|
|
25
28
|
Array(options["remotes"]).reverse_each {|r| add_remote(r) }
|
|
26
29
|
|
|
@@ -162,49 +165,40 @@ module Bundler
|
|
|
162
165
|
end
|
|
163
166
|
end
|
|
164
167
|
|
|
165
|
-
def
|
|
168
|
+
def download(spec, options = {})
|
|
166
169
|
if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
|
|
167
|
-
|
|
168
|
-
return nil # no post-install message
|
|
170
|
+
return true
|
|
169
171
|
end
|
|
170
172
|
|
|
171
|
-
|
|
172
|
-
raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
|
|
173
|
-
|
|
174
|
-
return if Bundler.settings[:no_install]
|
|
175
|
-
|
|
176
|
-
install_path = rubygems_dir
|
|
177
|
-
bin_path = Bundler.system_bindir
|
|
178
|
-
|
|
179
|
-
require_relative "../rubygems_gem_installer"
|
|
180
|
-
|
|
181
|
-
installer = Bundler::RubyGemsGemInstaller.at(
|
|
182
|
-
path,
|
|
183
|
-
security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
|
|
184
|
-
install_dir: install_path.to_s,
|
|
185
|
-
bin_dir: bin_path.to_s,
|
|
186
|
-
ignore_dependencies: true,
|
|
187
|
-
wrappers: true,
|
|
188
|
-
env_shebang: true,
|
|
189
|
-
build_args: options[:build_args],
|
|
190
|
-
bundler_extension_cache_path: extension_cache_path(spec)
|
|
191
|
-
)
|
|
173
|
+
installer = rubygems_gem_installer(spec, options)
|
|
192
174
|
|
|
193
175
|
if spec.remote
|
|
194
176
|
s = begin
|
|
195
177
|
installer.spec
|
|
196
178
|
rescue Gem::Package::FormatError
|
|
197
|
-
Bundler.rm_rf(
|
|
179
|
+
Bundler.rm_rf(installer.gem)
|
|
198
180
|
raise
|
|
199
181
|
rescue Gem::Security::Exception => e
|
|
200
182
|
raise SecurityError,
|
|
201
|
-
"The gem #{
|
|
183
|
+
"The gem #{installer.gem} can't be installed because " \
|
|
202
184
|
"the security policy didn't allow it, with the message: #{e.message}"
|
|
203
185
|
end
|
|
204
186
|
|
|
205
187
|
spec.__swap__(s)
|
|
206
188
|
end
|
|
207
189
|
|
|
190
|
+
spec
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def install(spec, options = {})
|
|
194
|
+
if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
|
|
195
|
+
print_using_message "Using #{version_message(spec, options[:previous_spec])}"
|
|
196
|
+
return nil # no post-install message
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
return if Bundler.settings[:no_install]
|
|
200
|
+
|
|
201
|
+
installer = rubygems_gem_installer(spec, options)
|
|
208
202
|
spec.source.checksum_store.register(spec, installer.gem_checksum)
|
|
209
203
|
|
|
210
204
|
message = "Installing #{version_message(spec, options[:previous_spec])}"
|
|
@@ -511,6 +505,34 @@ module Bundler
|
|
|
511
505
|
return unless remote = spec.remote
|
|
512
506
|
remote.cache_slug
|
|
513
507
|
end
|
|
508
|
+
|
|
509
|
+
# We are using a mutex to reaed and write from/to the hash.
|
|
510
|
+
# The reason this double synchronization was added is for performance
|
|
511
|
+
# and lock the mutex for the shortest possible amount of time. Otherwise,
|
|
512
|
+
# all threads are fighting over this mutex and when it gets acquired it gets locked
|
|
513
|
+
# until a threads finishes downloading a gem, leaving the other threads waiting
|
|
514
|
+
# doing nothing.
|
|
515
|
+
def rubygems_gem_installer(spec, options)
|
|
516
|
+
@gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
|
|
517
|
+
path = fetch_gem_if_possible(spec, options[:previous_spec])
|
|
518
|
+
raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
|
|
519
|
+
|
|
520
|
+
REQUIRE_MUTEX.synchronize { require_relative "../rubygems_gem_installer" }
|
|
521
|
+
|
|
522
|
+
installer = Bundler::RubyGemsGemInstaller.at(
|
|
523
|
+
path,
|
|
524
|
+
security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
|
|
525
|
+
install_dir: rubygems_dir.to_s,
|
|
526
|
+
bin_dir: Bundler.system_bindir.to_s,
|
|
527
|
+
ignore_dependencies: true,
|
|
528
|
+
wrappers: true,
|
|
529
|
+
env_shebang: true,
|
|
530
|
+
build_args: options[:build_args],
|
|
531
|
+
bundler_extension_cache_path: extension_cache_path(spec)
|
|
532
|
+
)
|
|
533
|
+
@gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer }
|
|
534
|
+
end
|
|
535
|
+
end
|
|
514
536
|
end
|
|
515
537
|
end
|
|
516
538
|
end
|
data/lib/bundler/source.rb
CHANGED
data/lib/bundler/version.rb
CHANGED
data/lib/bundler/worker.rb
CHANGED
|
@@ -22,6 +22,7 @@ module Bundler
|
|
|
22
22
|
def initialize(size, name, func)
|
|
23
23
|
@name = name
|
|
24
24
|
@request_queue = Thread::Queue.new
|
|
25
|
+
@request_queue_with_priority = Thread::Queue.new
|
|
25
26
|
@response_queue = Thread::Queue.new
|
|
26
27
|
@func = func
|
|
27
28
|
@size = size
|
|
@@ -32,9 +33,10 @@ module Bundler
|
|
|
32
33
|
# Enqueue a request to be executed in the worker pool
|
|
33
34
|
#
|
|
34
35
|
# @param obj [String] mostly it is name of spec that should be downloaded
|
|
35
|
-
def enq(obj)
|
|
36
|
+
def enq(obj, priority: false)
|
|
37
|
+
queue = priority ? @request_queue_with_priority : @request_queue
|
|
36
38
|
create_threads unless @threads
|
|
37
|
-
|
|
39
|
+
queue.enq obj
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
# Retrieves results of job function being executed in worker pool
|
|
@@ -52,7 +54,13 @@ module Bundler
|
|
|
52
54
|
|
|
53
55
|
def process_queue(i)
|
|
54
56
|
loop do
|
|
55
|
-
obj =
|
|
57
|
+
obj = begin
|
|
58
|
+
@request_queue_with_priority.deq(true)
|
|
59
|
+
rescue ThreadError
|
|
60
|
+
@request_queue.deq(false, timeout: 0.05)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
next if obj.nil?
|
|
56
64
|
break if obj.equal? POISON
|
|
57
65
|
@response_queue.enq apply_func(obj, i)
|
|
58
66
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bundler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- André Arko
|
|
@@ -402,7 +402,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
402
402
|
- !ruby/object:Gem::Version
|
|
403
403
|
version: 3.4.1
|
|
404
404
|
requirements: []
|
|
405
|
-
rubygems_version: 4.0.
|
|
405
|
+
rubygems_version: 4.0.6
|
|
406
406
|
specification_version: 4
|
|
407
407
|
summary: The best way to manage your application's dependencies
|
|
408
408
|
test_files: []
|