bundler 2.6.9 → 4.0.11

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.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2229 -1879
  3. data/README.md +11 -11
  4. data/bundler.gemspec +5 -5
  5. data/lib/bundler/build_metadata.rb +10 -11
  6. data/lib/bundler/capistrano.rb +1 -19
  7. data/lib/bundler/checksum.rb +6 -0
  8. data/lib/bundler/cli/add.rb +10 -0
  9. data/lib/bundler/cli/cache.rb +1 -12
  10. data/lib/bundler/cli/common.rb +21 -4
  11. data/lib/bundler/cli/config.rb +1 -2
  12. data/lib/bundler/cli/console.rb +5 -0
  13. data/lib/bundler/cli/exec.rb +29 -4
  14. data/lib/bundler/cli/gem.rb +90 -64
  15. data/lib/bundler/cli/install.rb +15 -90
  16. data/lib/bundler/cli/issue.rb +2 -2
  17. data/lib/bundler/cli/list.rb +33 -2
  18. data/lib/bundler/cli/lock.rb +5 -5
  19. data/lib/bundler/cli/outdated.rb +1 -1
  20. data/lib/bundler/cli/plugin.rb +5 -1
  21. data/lib/bundler/cli/pristine.rb +5 -1
  22. data/lib/bundler/cli/show.rb +3 -7
  23. data/lib/bundler/cli/update.rb +5 -5
  24. data/lib/bundler/cli.rb +162 -127
  25. data/lib/bundler/compact_index_client.rb +1 -6
  26. data/lib/bundler/current_ruby.rb +17 -5
  27. data/lib/bundler/definition.rb +201 -117
  28. data/lib/bundler/dependency.rb +1 -1
  29. data/lib/bundler/deployment.rb +1 -64
  30. data/lib/bundler/digest.rb +1 -1
  31. data/lib/bundler/dsl.rb +48 -48
  32. data/lib/bundler/environment_preserver.rb +1 -0
  33. data/lib/bundler/errors.rb +1 -5
  34. data/lib/bundler/feature_flag.rb +5 -35
  35. data/lib/bundler/fetcher/compact_index.rb +1 -1
  36. data/lib/bundler/fetcher/dependency.rb +9 -2
  37. data/lib/bundler/fetcher/downloader.rb +33 -8
  38. data/lib/bundler/fetcher/gem_remote_fetcher.rb +6 -0
  39. data/lib/bundler/fetcher.rb +49 -19
  40. data/lib/bundler/friendly_errors.rb +4 -3
  41. data/lib/bundler/index.rb +7 -9
  42. data/lib/bundler/injector.rb +1 -2
  43. data/lib/bundler/inline.rb +9 -1
  44. data/lib/bundler/installer/gem_installer.rb +14 -11
  45. data/lib/bundler/installer/parallel_installer.rb +74 -36
  46. data/lib/bundler/installer.rb +6 -19
  47. data/lib/bundler/lazy_specification.rb +47 -20
  48. data/lib/bundler/lockfile_generator.rb +17 -2
  49. data/lib/bundler/lockfile_parser.rb +19 -6
  50. data/lib/bundler/man/bundle-add.1 +1 -1
  51. data/lib/bundler/man/bundle-binstubs.1 +3 -6
  52. data/lib/bundler/man/bundle-binstubs.1.ronn +4 -6
  53. data/lib/bundler/man/bundle-cache.1 +2 -14
  54. data/lib/bundler/man/bundle-cache.1.ronn +1 -14
  55. data/lib/bundler/man/bundle-check.1 +2 -5
  56. data/lib/bundler/man/bundle-check.1.ronn +0 -5
  57. data/lib/bundler/man/bundle-clean.1 +1 -1
  58. data/lib/bundler/man/bundle-config.1 +206 -148
  59. data/lib/bundler/man/bundle-config.1.ronn +136 -119
  60. data/lib/bundler/man/bundle-console.1 +1 -1
  61. data/lib/bundler/man/bundle-doctor.1 +43 -4
  62. data/lib/bundler/man/bundle-doctor.1.ronn +48 -4
  63. data/lib/bundler/man/bundle-env.1 +1 -1
  64. data/lib/bundler/man/bundle-exec.1 +2 -5
  65. data/lib/bundler/man/bundle-exec.1.ronn +1 -5
  66. data/lib/bundler/man/bundle-fund.1 +1 -1
  67. data/lib/bundler/man/bundle-gem.1 +64 -44
  68. data/lib/bundler/man/bundle-gem.1.ronn +10 -9
  69. data/lib/bundler/man/bundle-help.1 +1 -1
  70. data/lib/bundler/man/bundle-info.1 +1 -1
  71. data/lib/bundler/man/bundle-init.1 +1 -1
  72. data/lib/bundler/man/bundle-install.1 +16 -59
  73. data/lib/bundler/man/bundle-install.1.ronn +27 -108
  74. data/lib/bundler/man/bundle-issue.1 +1 -1
  75. data/lib/bundler/man/bundle-licenses.1 +1 -1
  76. data/lib/bundler/man/bundle-list.1 +6 -1
  77. data/lib/bundler/man/bundle-list.1.ronn +5 -0
  78. data/lib/bundler/man/bundle-lock.1 +1 -1
  79. data/lib/bundler/man/bundle-open.1 +1 -1
  80. data/lib/bundler/man/bundle-outdated.1 +1 -1
  81. data/lib/bundler/man/bundle-platform.1 +1 -1
  82. data/lib/bundler/man/bundle-plugin.1 +33 -15
  83. data/lib/bundler/man/bundle-plugin.1.ronn +36 -15
  84. data/lib/bundler/man/bundle-pristine.1 +1 -1
  85. data/lib/bundler/man/bundle-remove.1 +2 -8
  86. data/lib/bundler/man/bundle-remove.1.ronn +1 -8
  87. data/lib/bundler/man/bundle-show.1 +2 -5
  88. data/lib/bundler/man/bundle-show.1.ronn +0 -4
  89. data/lib/bundler/man/bundle-update.1 +5 -5
  90. data/lib/bundler/man/bundle-update.1.ronn +4 -4
  91. data/lib/bundler/man/bundle-version.1 +1 -1
  92. data/lib/bundler/man/bundle.1 +1 -10
  93. data/lib/bundler/man/bundle.1.ronn +0 -9
  94. data/lib/bundler/man/gemfile.5 +32 -1
  95. data/lib/bundler/man/gemfile.5.ronn +28 -0
  96. data/lib/bundler/man/index.txt +0 -2
  97. data/lib/bundler/match_platform.rb +31 -12
  98. data/lib/bundler/materialization.rb +3 -3
  99. data/lib/bundler/plugin/api/source.rb +8 -0
  100. data/lib/bundler/plugin/index.rb +6 -0
  101. data/lib/bundler/plugin/installer.rb +2 -11
  102. data/lib/bundler/plugin/source_list.rb +1 -1
  103. data/lib/bundler/plugin.rb +7 -4
  104. data/lib/bundler/resolver/package.rb +2 -1
  105. data/lib/bundler/resolver/strategy.rb +6 -3
  106. data/lib/bundler/resolver.rb +20 -4
  107. data/lib/bundler/retry.rb +30 -4
  108. data/lib/bundler/ruby_dsl.rb +17 -12
  109. data/lib/bundler/ruby_version.rb +1 -3
  110. data/lib/bundler/rubygems_ext.rb +117 -121
  111. data/lib/bundler/rubygems_gem_installer.rb +5 -4
  112. data/lib/bundler/rubygems_integration.rb +13 -12
  113. data/lib/bundler/runtime.rb +14 -3
  114. data/lib/bundler/self_manager.rb +34 -43
  115. data/lib/bundler/settings/validator.rb +5 -21
  116. data/lib/bundler/settings.rb +17 -32
  117. data/lib/bundler/shared_helpers.rb +12 -18
  118. data/lib/bundler/source/gemspec.rb +4 -0
  119. data/lib/bundler/source/git/git_proxy.rb +55 -29
  120. data/lib/bundler/source/git.rb +2 -3
  121. data/lib/bundler/source/metadata.rb +4 -0
  122. data/lib/bundler/source/path.rb +12 -7
  123. data/lib/bundler/source/rubygems.rb +59 -43
  124. data/lib/bundler/source/rubygems_aggregate.rb +4 -1
  125. data/lib/bundler/source.rb +3 -1
  126. data/lib/bundler/source_list.rb +5 -50
  127. data/lib/bundler/source_map.rb +8 -7
  128. data/lib/bundler/spec_set.rb +9 -14
  129. data/lib/bundler/stub_specification.rb +1 -0
  130. data/lib/bundler/templates/Executable +0 -11
  131. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +7 -129
  132. data/lib/bundler/templates/newgem/Cargo.toml.tt +6 -0
  133. data/lib/bundler/templates/newgem/Rakefile.tt +5 -0
  134. data/lib/bundler/templates/newgem/circleci/config.yml.tt +12 -0
  135. data/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +8 -1
  136. data/lib/bundler/templates/newgem/ext/newgem/build.rs.tt +5 -0
  137. data/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt +11 -0
  138. data/lib/bundler/templates/newgem/ext/newgem/go.mod.tt +5 -0
  139. data/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt +2 -0
  140. data/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt +31 -0
  141. data/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +13 -2
  142. data/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt +69 -0
  143. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +12 -1
  144. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +9 -0
  145. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +1 -1
  146. data/lib/bundler/templates/newgem/newgem.gemspec.tt +17 -11
  147. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +8 -0
  148. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +6 -0
  149. data/lib/bundler/ui/shell.rb +12 -8
  150. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +26 -23
  151. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  152. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +50 -6
  153. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +57 -52
  154. data/lib/bundler/vendor/net-http-persistent/README.rdoc +1 -1
  155. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +2 -1
  156. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +84 -42
  157. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +42 -6
  158. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +1 -1
  159. data/lib/bundler/vendor/thor/lib/thor/runner.rb +2 -2
  160. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +3 -7
  161. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  162. data/lib/bundler/vendor/thor/lib/thor.rb +1 -1
  163. data/lib/bundler/vendor/uri/lib/uri/common.rb +57 -15
  164. data/lib/bundler/vendor/uri/lib/uri/file.rb +1 -1
  165. data/lib/bundler/vendor/uri/lib/uri/generic.rb +34 -21
  166. data/lib/bundler/vendor/uri/lib/uri/http.rb +12 -0
  167. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +9 -8
  168. data/lib/bundler/vendor/uri/lib/uri/version.rb +2 -2
  169. data/lib/bundler/version.rb +10 -2
  170. data/lib/bundler/vlad.rb +1 -14
  171. data/lib/bundler/worker.rb +12 -4
  172. data/lib/bundler.rb +20 -40
  173. metadata +13 -25
  174. data/lib/bundler/cli/inject.rb +0 -60
  175. data/lib/bundler/cli/viz.rb +0 -31
  176. data/lib/bundler/gem_helpers.rb +0 -144
  177. data/lib/bundler/graph.rb +0 -152
  178. data/lib/bundler/man/bundle-inject.1 +0 -31
  179. data/lib/bundler/man/bundle-inject.1.ronn +0 -32
  180. data/lib/bundler/man/bundle-viz.1 +0 -30
  181. data/lib/bundler/man/bundle-viz.1.ronn +0 -36
  182. data/lib/bundler/similarity_detector.rb +0 -63
  183. data/lib/bundler/templates/Executable.bundler +0 -109
  184. data/lib/bundler/vendor/connection_pool/.document +0 -1
  185. data/lib/bundler/vendor/fileutils/.document +0 -1
  186. data/lib/bundler/vendor/net-http-persistent/.document +0 -1
  187. data/lib/bundler/vendor/pub_grub/.document +0 -1
  188. data/lib/bundler/vendor/securerandom/.document +0 -1
  189. data/lib/bundler/vendor/thor/.document +0 -1
  190. data/lib/bundler/vendor/tsort/.document +0 -1
  191. data/lib/bundler/vendor/uri/.document +0 -1
@@ -44,14 +44,16 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
44
44
  raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
45
45
 
46
46
  old_gemfile = ENV["BUNDLE_GEMFILE"]
47
+ old_lockfile = ENV["BUNDLE_LOCKFILE"]
47
48
 
48
49
  Bundler.unbundle_env!
49
50
 
50
51
  begin
51
52
  Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
52
53
  Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
54
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
53
55
 
54
- Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
56
+ Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
55
57
  builder = Bundler::Dsl.new
56
58
  builder.instance_eval(&gemfile)
57
59
 
@@ -94,5 +96,11 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
94
96
  else
95
97
  ENV["BUNDLE_GEMFILE"] = ""
96
98
  end
99
+
100
+ if old_lockfile
101
+ ENV["BUNDLE_LOCKFILE"] = old_lockfile
102
+ else
103
+ ENV["BUNDLE_LOCKFILE"] = ""
104
+ end
97
105
  end
98
106
  end
@@ -16,7 +16,6 @@ module Bundler
16
16
  def install_from_spec
17
17
  post_install_message = install
18
18
  Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
19
- generate_executable_stubs
20
19
  [true, post_install_message]
21
20
  rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError, Bundler::InsecureInstallPathError
22
21
  raise
@@ -26,6 +25,20 @@ module Bundler
26
25
  [false, specific_failure_message(e)]
27
26
  end
28
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
+
29
42
  private
30
43
 
31
44
  def specific_failure_message(e)
@@ -71,15 +84,5 @@ module Bundler
71
84
  def out_of_space_message
72
85
  "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle."
73
86
  end
74
-
75
- def generate_executable_stubs
76
- return if Bundler.feature_flag.forget_cli_options?
77
- return if Bundler.settings[:inline]
78
- if Bundler.settings[:bin] && standalone
79
- installer.generate_standalone_bundler_executable_stubs(spec)
80
- elsif Bundler.settings[:bin]
81
- installer.generate_bundler_executable_stubs(spec, force: true)
82
- end
83
- end
84
87
  end
85
88
  end
@@ -6,7 +6,7 @@ require_relative "gem_installer"
6
6
  module Bundler
7
7
  class ParallelInstaller
8
8
  class SpecInstallation
9
- attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error
9
+ attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error, :dependencies
10
10
  def initialize(spec)
11
11
  @spec = spec
12
12
  @name = spec.name
@@ -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,29 +36,21 @@ module Bundler
32
36
  state == :none
33
37
  end
34
38
 
35
- def has_post_install_message?
36
- !post_install_message.empty?
37
- end
38
-
39
- def ignorable_dependency?(dep)
40
- dep.type == :development || dep.name == @name
41
- end
39
+ def ready_to_install?(installed_specs)
40
+ return false unless state == :downloaded
42
41
 
43
- # Checks installed dependencies against spec's dependencies to make
44
- # sure needed dependencies have been installed.
45
- def dependencies_installed?(installed_specs)
46
- dependencies.all? {|d| installed_specs.include? d.name }
42
+ spec.extensions.none? || dependencies_installed?(installed_specs)
47
43
  end
48
44
 
49
- # Represents only the non-development dependencies, the ones that are
50
- # itself and are in the total list.
51
- def dependencies
52
- @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep }
45
+ def has_post_install_message?
46
+ !post_install_message.empty?
53
47
  end
54
48
 
55
- # Represents all dependencies
56
- def all_dependencies
57
- @spec.dependencies
49
+ # Recursively checks that all dependencies (direct and transitive) have been installed.
50
+ def dependencies_installed?(installed_specs)
51
+ dependencies.all? do |dep|
52
+ installed_specs.include?(dep.name) && dep.dependencies_installed?(installed_specs)
53
+ end
58
54
  end
59
55
 
60
56
  def to_s
@@ -75,6 +71,12 @@ module Bundler
75
71
  @force = force
76
72
  @local = local
77
73
  @specs = all_specs.map {|s| SpecInstallation.new(s) }
74
+ specs_by_name = @specs.to_h {|s| [s.name, s] }
75
+ @specs.each do |spec_install|
76
+ spec_install.dependencies = spec_install.spec.dependencies.filter_map do |dep|
77
+ specs_by_name[dep.name] unless dep.type == :development || dep.name == spec_install.name
78
+ end
79
+ end
78
80
  @specs.each do |spec_install|
79
81
  spec_install.state = :installed if skip.include?(spec_install.name)
80
82
  end if skip
@@ -84,6 +86,7 @@ module Bundler
84
86
 
85
87
  def call
86
88
  if @rake
89
+ do_download(@rake, 0)
87
90
  do_install(@rake, 0)
88
91
  Gem::Specification.reset
89
92
  end
@@ -107,26 +110,54 @@ module Bundler
107
110
  end
108
111
 
109
112
  def install_with_worker
110
- enqueue_specs
111
- process_specs until finished_installing?
113
+ installed_specs = {}
114
+ enqueue_specs(installed_specs)
115
+
116
+ process_specs(installed_specs) until finished_installing?
112
117
  end
113
118
 
114
119
  def install_serially
115
120
  until finished_installing?
116
121
  raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?)
117
122
  spec_install.state = :enqueued
123
+ do_download(spec_install, 0)
118
124
  do_install(spec_install, 0)
119
125
  end
120
126
  end
121
127
 
122
128
  def worker_pool
123
129
  @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num|
124
- do_install(spec_install, worker_num)
130
+ case spec_install.state
131
+ when :enqueued
132
+ do_download(spec_install, worker_num)
133
+ when :installable
134
+ do_install(spec_install, worker_num)
135
+ else
136
+ spec_install
137
+ end
125
138
  }
126
139
  end
127
140
 
128
- def do_install(spec_install, worker_num)
141
+ def do_download(spec_install, worker_num)
129
142
  Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install)
143
+
144
+ gem_installer = Bundler::GemInstaller.new(
145
+ spec_install.spec, @installer, @standalone, worker_num, @force, @local
146
+ )
147
+
148
+ success, message = gem_installer.download
149
+
150
+ if success
151
+ spec_install.state = :downloaded
152
+ else
153
+ spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
154
+ spec_install.state = :failed
155
+ end
156
+
157
+ spec_install
158
+ end
159
+
160
+ def do_install(spec_install, worker_num)
130
161
  gem_installer = Bundler::GemInstaller.new(
131
162
  spec_install.spec, @installer, @standalone, worker_num, @force, @local
132
163
  )
@@ -147,9 +178,19 @@ module Bundler
147
178
  # Some specs might've had to wait til this spec was installed to be
148
179
  # processed so the call to `enqueue_specs` is important after every
149
180
  # dequeue.
150
- def process_specs
151
- worker_pool.deq
152
- enqueue_specs
181
+ def process_specs(installed_specs)
182
+ spec = worker_pool.deq
183
+
184
+ if spec.installed?
185
+ installed_specs[spec.name] = true
186
+ return
187
+ elsif spec.failed?
188
+ return
189
+ elsif spec.ready_to_install?(installed_specs)
190
+ spec.state = :installable
191
+ end
192
+
193
+ worker_pool.enq(spec, priority: spec.enqueue_with_priority?)
153
194
  end
154
195
 
155
196
  def finished_installing?
@@ -185,18 +226,15 @@ module Bundler
185
226
  # Later we call this lambda again to install specs that depended on
186
227
  # previously installed specifications. We continue until all specs
187
228
  # are installed.
188
- def enqueue_specs
189
- installed_specs = {}
229
+ def enqueue_specs(installed_specs)
190
230
  @specs.each do |spec|
191
- next unless spec.installed?
192
- installed_specs[spec.name] = true
193
- end
194
-
195
- @specs.each do |spec|
196
- if spec.ready_to_enqueue? && spec.dependencies_installed?(installed_specs)
197
- spec.state = :enqueued
198
- worker_pool.enq spec
231
+ if spec.installed?
232
+ installed_specs[spec.name] = true
233
+ next
199
234
  end
235
+
236
+ spec.state = :enqueued
237
+ worker_pool.enq spec
200
238
  end
201
239
  end
202
240
  end
@@ -7,12 +7,6 @@ require_relative "installer/gem_installer"
7
7
 
8
8
  module Bundler
9
9
  class Installer
10
- class << self
11
- attr_accessor :ambiguous_gems
12
-
13
- Installer.ambiguous_gems = []
14
- end
15
-
16
10
  attr_reader :post_install_messages, :definition
17
11
 
18
12
  # Begins the installation process for Bundler.
@@ -91,6 +85,11 @@ module Bundler
91
85
  end
92
86
 
93
87
  def generate_bundler_executable_stubs(spec, options = {})
88
+ if spec.name == "bundler"
89
+ Bundler.ui.warn "Bundler itself does not use binstubs because its version is selected by RubyGems"
90
+ return
91
+ end
92
+
94
93
  if options[:binstubs_cmd] && spec.executables.empty?
95
94
  options = {}
96
95
  spec.runtime_dependencies.each do |dep|
@@ -115,10 +114,6 @@ module Bundler
115
114
  ruby_command = Thor::Util.ruby_command
116
115
  ruby_command = ruby_command
117
116
  template_path = File.expand_path("templates/Executable", __dir__)
118
- if spec.name == "bundler"
119
- template_path += ".bundler"
120
- spec.executables = %(bundle)
121
- end
122
117
  template = File.read(template_path)
123
118
 
124
119
  exists = []
@@ -194,21 +189,13 @@ module Bundler
194
189
  standalone = options[:standalone]
195
190
  force = options[:force]
196
191
  local = options[:local] || options[:"prefer-local"]
197
- jobs = installation_parallelization
192
+ jobs = Bundler.settings.installation_parallelization
198
193
  spec_installations = ParallelInstaller.call(self, @definition.specs, jobs, standalone, force, local: local)
199
194
  spec_installations.each do |installation|
200
195
  post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
201
196
  end
202
197
  end
203
198
 
204
- def installation_parallelization
205
- if jobs = Bundler.settings[:jobs]
206
- return jobs
207
- end
208
-
209
- Bundler.settings.processor_count
210
- end
211
-
212
199
  def load_plugins
213
200
  Gem.load_plugins
214
201
 
@@ -33,7 +33,7 @@ module Bundler
33
33
  lazy_spec
34
34
  end
35
35
 
36
- def initialize(name, version, platform, source = nil)
36
+ def initialize(name, version, platform, source = nil, **materialization_options)
37
37
  @name = name
38
38
  @version = version
39
39
  @dependencies = []
@@ -43,6 +43,7 @@ module Bundler
43
43
 
44
44
  @original_source = source
45
45
  @source = source
46
+ @materialization_options = materialization_options
46
47
 
47
48
  @force_ruby_platform = default_force_ruby_platform
48
49
  @most_specific_locked_platform = nil
@@ -137,24 +138,16 @@ module Bundler
137
138
  source.local!
138
139
 
139
140
  if use_exact_resolved_specifications?
140
- materialize(self) do |matching_specs|
141
- choose_compatible(matching_specs)
142
- end
143
- else
144
- materialize([name, version]) do |matching_specs|
145
- target_platform = source.is_a?(Source::Path) ? platform : local_platform
146
-
147
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
148
-
149
- specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
150
- return specification unless specification.nil?
141
+ spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) }
142
+ return spec if spec
151
143
 
152
- if target_platform != platform
153
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform)
154
- end
155
-
156
- choose_compatible(installable_candidates)
144
+ # Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
145
+ # In non-frozen mode, return nil to trigger re-resolution and lockfile update
146
+ if Bundler.frozen_bundle?
147
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
157
148
  end
149
+ else
150
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
158
151
  end
159
152
  end
160
153
 
@@ -189,8 +182,41 @@ module Bundler
189
182
  !source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
190
183
  end
191
184
 
185
+ # Try platforms in order of preference until finding a compatible spec.
186
+ # Used for legacy lockfiles and as a fallback when the exact locked spec
187
+ # is incompatible. Falls back to frozen bundle behavior if none match.
188
+ def resolve_best_platform(specs)
189
+ find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs)
190
+ end
191
+
192
+ def find_compatible_platform_spec(specs)
193
+ candidate_platforms.each do |plat|
194
+ candidates = MatchPlatform.select_best_platform_match(specs, plat)
195
+ spec = choose_compatible(candidates, fallback_to_non_installable: false)
196
+ return spec if spec
197
+ end
198
+ nil
199
+ end
200
+
201
+ # Platforms to try in order of preference. Ruby platform is last since it
202
+ # requires compilation, but works when precompiled gems are incompatible.
203
+ def candidate_platforms
204
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
205
+ [target, platform, Gem::Platform::RUBY].uniq
206
+ end
207
+
208
+ # In frozen mode, accept any candidate. Will error at install time.
209
+ # When target differs from locked platform, prefer locked platform's candidates
210
+ # to preserve lockfile integrity.
211
+ def frozen_bundle_fallback(specs)
212
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
213
+ fallback_platform = target == platform ? target : platform
214
+ candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform)
215
+ choose_compatible(candidates)
216
+ end
217
+
192
218
  def ruby_platform_materializes_to_ruby_platform?
193
- generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
219
+ generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
194
220
 
195
221
  (most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]
196
222
  end
@@ -226,12 +252,13 @@ module Bundler
226
252
  # Validate dependencies of this locked spec are consistent with dependencies
227
253
  # of the actual spec that was materialized.
228
254
  #
229
- # Note that we don't validate dependencies of locally installed gems but
255
+ # Note that unless we are in strict mode (which we set during installation)
256
+ # we don't validate dependencies of locally installed gems but
230
257
  # accept what's in the lockfile instead for performance, since loading
231
258
  # dependencies of locally installed gems would mean evaluating all gemspecs,
232
259
  # which would affect `bundler/setup` performance.
233
260
  def validate_dependencies(spec)
234
- if spec.is_a?(StubSpecification)
261
+ if !@materialization_options[:strict] && spec.is_a?(StubSpecification)
235
262
  spec.dependencies = dependencies
236
263
  else
237
264
  if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort
@@ -71,7 +71,8 @@ module Bundler
71
71
  checksums = definition.resolve.map do |spec|
72
72
  spec.source.checksum_store.to_lock(spec)
73
73
  end
74
- add_section("CHECKSUMS", checksums)
74
+
75
+ add_section("CHECKSUMS", checksums + bundler_checksum)
75
76
  end
76
77
 
77
78
  def add_locked_ruby_version
@@ -95,10 +96,24 @@ module Bundler
95
96
  out << " #{key}: #{val}\n"
96
97
  end
97
98
  when String
98
- out << " #{value}\n"
99
+ out << " #{value}\n"
99
100
  else
100
101
  raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile"
101
102
  end
102
103
  end
104
+
105
+ def bundler_checksum
106
+ return [] if Bundler.gem_version.to_s.end_with?(".dev") || ENV["SKIP_BUNDLER_CHECKSUM"]
107
+
108
+ bundler_spec = definition.sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
109
+ return [] unless File.exist?(bundler_spec.cache_file)
110
+
111
+ require "rubygems/package"
112
+
113
+ package = Gem::Package.new(bundler_spec.cache_file)
114
+ definition.sources.metadata_source.checksum_store.register(bundler_spec, Checksum.from_gem_package(package))
115
+
116
+ [definition.sources.metadata_source.checksum_store.to_lock(bundler_spec)]
117
+ end
103
118
  end
104
119
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "shared_helpers"
4
+
3
5
  module Bundler
4
6
  class LockfileParser
5
- include GemHelpers
6
-
7
7
  class Position
8
8
  attr_reader :line, :column
9
9
  def initialize(line, column)
@@ -28,6 +28,7 @@ module Bundler
28
28
 
29
29
  attr_reader(
30
30
  :sources,
31
+ :metadata_source,
31
32
  :dependencies,
32
33
  :specs,
33
34
  :platforms,
@@ -94,9 +95,10 @@ module Bundler
94
95
  lockfile_contents.split(BUNDLED).last.strip
95
96
  end
96
97
 
97
- def initialize(lockfile)
98
+ def initialize(lockfile, strict: false)
98
99
  @platforms = []
99
100
  @sources = []
101
+ @metadata_source = Source::Metadata.new
100
102
  @dependencies = {}
101
103
  @parse_method = nil
102
104
  @specs = {}
@@ -106,6 +108,7 @@ module Bundler
106
108
  "Gemfile.lock"
107
109
  end
108
110
  @pos = Position.new(1, 1)
111
+ @strict = strict
109
112
 
110
113
  if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
111
114
  raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
@@ -139,8 +142,13 @@ module Bundler
139
142
  end
140
143
  @pos.advance!(line)
141
144
  end
145
+
146
+ if @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
147
+ SharedHelpers.feature_deprecated!("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
148
+ end
149
+
142
150
  @most_specific_locked_platform = @platforms.min_by do |bundle_platform|
143
- platform_specificity_match(bundle_platform, local_platform)
151
+ Gem::Platform.platform_specificity_match(bundle_platform, Bundler.local_platform)
144
152
  end
145
153
  @specs = @specs.values.sort_by!(&:full_name).each do |spec|
146
154
  spec.most_specific_locked_platform = @most_specific_locked_platform
@@ -246,7 +254,12 @@ module Bundler
246
254
  version = Gem::Version.new(version)
247
255
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
248
256
  full_name = Gem::NameTuple.new(name, version, platform).full_name
249
- return unless spec = @specs[full_name]
257
+ spec = @specs[full_name]
258
+
259
+ if name == "bundler"
260
+ spec ||= LazySpecification.new(name, version, platform, @metadata_source)
261
+ end
262
+ return unless spec
250
263
 
251
264
  if checksums
252
265
  checksums.split(",") do |lock_checksum|
@@ -271,7 +284,7 @@ module Bundler
271
284
 
272
285
  version = Gem::Version.new(version)
273
286
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
274
- @current_spec = LazySpecification.new(name, version, platform, @current_source)
287
+ @current_spec = LazySpecification.new(name, version, platform, @current_source, strict: @strict)
275
288
  @current_source.add_dependency_names(name)
276
289
 
277
290
  @specs[@current_spec.full_name] = @current_spec
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-ADD" "1" "March 2025" ""
3
+ .TH "BUNDLE\-ADD" "1" "April 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
6
6
  .SH "SYNOPSIS"
@@ -1,24 +1,21 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-BINSTUBS" "1" "March 2025" ""
3
+ .TH "BUNDLE\-BINSTUBS" "1" "April 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
6
6
  .SH "SYNOPSIS"
7
- \fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] [\-\-all\-platforms]
7
+ \fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-standalone] [\-\-all\-platforms]
8
8
  .SH "DESCRIPTION"
9
9
  Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\.
10
10
  .P
11
11
  For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\.
12
12
  .P
13
- This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\.
13
+ This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the directory specified by \fBbin\fR setting if it has been configured\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\.
14
14
  .SH "OPTIONS"
15
15
  .TP
16
16
  \fB\-\-force\fR
17
17
  Overwrite existing binstubs if they exist\.
18
18
  .TP
19
- \fB\-\-path[=PATH]\fR
20
- The location to install the specified binstubs to\. This defaults to \fBbin\fR\.
21
- .TP
22
19
  \fB\-\-standalone\fR
23
20
  Makes binstubs that can work without depending on Rubygems or Bundler at runtime\.
24
21
  .TP
@@ -3,7 +3,7 @@ bundle-binstubs(1) -- Install the binstubs of the listed gems
3
3
 
4
4
  ## SYNOPSIS
5
5
 
6
- `bundle binstubs` <GEM_NAME> [--force] [--path PATH] [--standalone] [--all-platforms]
6
+ `bundle binstubs` <GEM_NAME> [--force] [--standalone] [--all-platforms]
7
7
 
8
8
  ## DESCRIPTION
9
9
 
@@ -19,17 +19,15 @@ the file `bin/rspec`. That file will contain enough code to load Bundler,
19
19
  tell it to load the bundled gems, and then run rspec.
20
20
 
21
21
  This command generates binstubs for executables in `GEM_NAME`.
22
- Binstubs are put into `bin`, or the `--path` directory if one has been set.
23
- Calling binstubs with [GEM [GEM]] will create binstubs for all given gems.
22
+ Binstubs are put into `bin`, or the directory specified by `bin` setting if it
23
+ has been configured. Calling binstubs with [GEM [GEM]] will create binstubs for
24
+ all given gems.
24
25
 
25
26
  ## OPTIONS
26
27
 
27
28
  * `--force`:
28
29
  Overwrite existing binstubs if they exist.
29
30
 
30
- * `--path[=PATH]`:
31
- The location to install the specified binstubs to. This defaults to `bin`.
32
-
33
31
  * `--standalone`:
34
32
  Makes binstubs that can work without depending on Rubygems or Bundler at
35
33
  runtime.
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-CACHE" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CACHE" "1" "April 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
6
6
  .SH "SYNOPSIS"
@@ -11,9 +11,6 @@ alias: \fBpackage\fR, \fBpack\fR
11
11
  Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\.
12
12
  .SH "OPTIONS"
13
13
  .TP
14
- \fB\-\-all\fR
15
- Include all sources (including path and git)\.
16
- .TP
17
14
  \fB\-\-all\-platforms\fR
18
15
  Include gems for all platforms present in the lockfile, not only the current one\.
19
16
  .TP
@@ -26,19 +23,10 @@ Use the specified gemfile instead of Gemfile\.
26
23
  \fB\-\-no\-install\fR
27
24
  Don't install the gems, only update the cache\.
28
25
  .TP
29
- \fB\-\-no\-prune\fR
30
- Don't remove stale gems from the cache\.
31
- .TP
32
- \fB\-\-path=PATH\fR
33
- Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME)\.
34
- .TP
35
26
  \fB\-\-quiet\fR
36
27
  Only output warnings and errors\.
37
- .TP
38
- \fB\-\-frozen\fR
39
- Do not allow the Gemfile\.lock to be updated after this bundle cache operation's install\.
40
28
  .SH "GIT AND PATH GEMS"
41
- The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\.
29
+ The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This can be disabled setting \fBcache_all\fR to false\.
42
30
  .SH "SUPPORT FOR MULTIPLE PLATFORMS"
43
31
  When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\.
44
32
  .SH "REMOTE FETCHING"