bundler 2.6.9 → 4.0.10

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 (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2212 -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 +89 -63
  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 +199 -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 +63 -17
  46. data/lib/bundler/installer.rb +6 -19
  47. data/lib/bundler/lazy_specification.rb +47 -20
  48. data/lib/bundler/lockfile_generator.rb +1 -1
  49. data/lib/bundler/lockfile_parser.rb +11 -5
  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 +135 -118
  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/path.rb +12 -7
  122. data/lib/bundler/source/rubygems.rb +59 -43
  123. data/lib/bundler/source/rubygems_aggregate.rb +4 -1
  124. data/lib/bundler/source.rb +3 -1
  125. data/lib/bundler/source_list.rb +5 -50
  126. data/lib/bundler/source_map.rb +8 -7
  127. data/lib/bundler/spec_set.rb +9 -14
  128. data/lib/bundler/stub_specification.rb +1 -0
  129. data/lib/bundler/templates/Executable +0 -11
  130. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +7 -129
  131. data/lib/bundler/templates/newgem/Cargo.toml.tt +6 -0
  132. data/lib/bundler/templates/newgem/Rakefile.tt +5 -0
  133. data/lib/bundler/templates/newgem/circleci/config.yml.tt +12 -0
  134. data/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +8 -1
  135. data/lib/bundler/templates/newgem/ext/newgem/build.rs.tt +5 -0
  136. data/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt +11 -0
  137. data/lib/bundler/templates/newgem/ext/newgem/go.mod.tt +5 -0
  138. data/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt +2 -0
  139. data/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt +31 -0
  140. data/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +13 -2
  141. data/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt +69 -0
  142. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +12 -1
  143. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +9 -0
  144. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +1 -1
  145. data/lib/bundler/templates/newgem/newgem.gemspec.tt +10 -10
  146. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +8 -0
  147. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +6 -0
  148. data/lib/bundler/ui/shell.rb +12 -8
  149. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +26 -23
  150. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  151. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +50 -6
  152. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +57 -52
  153. data/lib/bundler/vendor/net-http-persistent/README.rdoc +1 -1
  154. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +2 -1
  155. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +84 -42
  156. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +42 -6
  157. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +1 -1
  158. data/lib/bundler/vendor/thor/lib/thor/runner.rb +2 -2
  159. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +3 -7
  160. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  161. data/lib/bundler/vendor/thor/lib/thor.rb +1 -1
  162. data/lib/bundler/vendor/uri/lib/uri/common.rb +57 -15
  163. data/lib/bundler/vendor/uri/lib/uri/file.rb +1 -1
  164. data/lib/bundler/vendor/uri/lib/uri/generic.rb +34 -21
  165. data/lib/bundler/vendor/uri/lib/uri/http.rb +12 -0
  166. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +9 -8
  167. data/lib/bundler/vendor/uri/lib/uri/version.rb +2 -2
  168. data/lib/bundler/version.rb +10 -2
  169. data/lib/bundler/vlad.rb +1 -14
  170. data/lib/bundler/worker.rb +12 -4
  171. data/lib/bundler.rb +20 -40
  172. metadata +13 -25
  173. data/lib/bundler/cli/inject.rb +0 -60
  174. data/lib/bundler/cli/viz.rb +0 -31
  175. data/lib/bundler/gem_helpers.rb +0 -144
  176. data/lib/bundler/graph.rb +0 -152
  177. data/lib/bundler/man/bundle-inject.1 +0 -31
  178. data/lib/bundler/man/bundle-inject.1.ronn +0 -32
  179. data/lib/bundler/man/bundle-viz.1 +0 -30
  180. data/lib/bundler/man/bundle-viz.1.ronn +0 -36
  181. data/lib/bundler/similarity_detector.rb +0 -63
  182. data/lib/bundler/templates/Executable.bundler +0 -109
  183. data/lib/bundler/vendor/connection_pool/.document +0 -1
  184. data/lib/bundler/vendor/fileutils/.document +0 -1
  185. data/lib/bundler/vendor/net-http-persistent/.document +0 -1
  186. data/lib/bundler/vendor/pub_grub/.document +0 -1
  187. data/lib/bundler/vendor/securerandom/.document +0 -1
  188. data/lib/bundler/vendor/thor/.document +0 -1
  189. data/lib/bundler/vendor/tsort/.document +0 -1
  190. 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
@@ -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
- enqueue_specs
111
- process_specs until finished_installing?
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
- do_install(spec_install, worker_num)
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 do_install(spec_install, worker_num)
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
- enqueue_specs
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.ready_to_enqueue? && spec.dependencies_installed?(installed_specs)
197
- spec.state = :enqueued
198
- worker_pool.enq spec
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
@@ -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
@@ -95,7 +95,7 @@ module Bundler
95
95
  out << " #{key}: #{val}\n"
96
96
  end
97
97
  when String
98
- out << " #{value}\n"
98
+ out << " #{value}\n"
99
99
  else
100
100
  raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile"
101
101
  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)
@@ -94,7 +94,7 @@ module Bundler
94
94
  lockfile_contents.split(BUNDLED).last.strip
95
95
  end
96
96
 
97
- def initialize(lockfile)
97
+ def initialize(lockfile, strict: false)
98
98
  @platforms = []
99
99
  @sources = []
100
100
  @dependencies = {}
@@ -106,6 +106,7 @@ module Bundler
106
106
  "Gemfile.lock"
107
107
  end
108
108
  @pos = Position.new(1, 1)
109
+ @strict = strict
109
110
 
110
111
  if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
111
112
  raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
@@ -139,8 +140,13 @@ module Bundler
139
140
  end
140
141
  @pos.advance!(line)
141
142
  end
143
+
144
+ if @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
145
+ SharedHelpers.feature_deprecated!("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
146
+ end
147
+
142
148
  @most_specific_locked_platform = @platforms.min_by do |bundle_platform|
143
- platform_specificity_match(bundle_platform, local_platform)
149
+ Gem::Platform.platform_specificity_match(bundle_platform, Bundler.local_platform)
144
150
  end
145
151
  @specs = @specs.values.sort_by!(&:full_name).each do |spec|
146
152
  spec.most_specific_locked_platform = @most_specific_locked_platform
@@ -271,7 +277,7 @@ module Bundler
271
277
 
272
278
  version = Gem::Version.new(version)
273
279
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
274
- @current_spec = LazySpecification.new(name, version, platform, @current_source)
280
+ @current_spec = LazySpecification.new(name, version, platform, @current_source, strict: @strict)
275
281
  @current_source.add_dependency_names(name)
276
282
 
277
283
  @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" "March 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" "March 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" "March 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"
@@ -15,9 +15,6 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
15
15
 
16
16
  ## OPTIONS
17
17
 
18
- * `--all`:
19
- Include all sources (including path and git).
20
-
21
18
  * `--all-platforms`:
22
19
  Include gems for all platforms present in the lockfile, not only the current one.
23
20
 
@@ -30,23 +27,13 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
30
27
  * `--no-install`:
31
28
  Don't install the gems, only update the cache.
32
29
 
33
- * `--no-prune`:
34
- Don't remove stale gems from the cache.
35
-
36
- * `--path=PATH`:
37
- Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).
38
-
39
30
  * `--quiet`:
40
31
  Only output warnings and errors.
41
32
 
42
- * `--frozen`:
43
- Do not allow the Gemfile.lock to be updated after this bundle cache operation's install.
44
-
45
33
  ## GIT AND PATH GEMS
46
34
 
47
35
  The `bundle cache` command can also package `:git` and `:path` dependencies
48
- besides .gem files. This needs to be explicitly enabled via the `--all` option.
49
- Once used, the `--all` option will be remembered.
36
+ besides .gem files. This can be disabled setting `cache_all` to false.
50
37
 
51
38
  ## SUPPORT FOR MULTIPLE PLATFORMS
52
39
 
@@ -1,10 +1,10 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-CHECK" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CHECK" "1" "March 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
6
6
  .SH "SYNOPSIS"
7
- \fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH]
7
+ \fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE]
8
8
  .SH "DESCRIPTION"
9
9
  \fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\.
10
10
  .P
@@ -18,7 +18,4 @@ Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\.
18
18
  .TP
19
19
  \fB\-\-gemfile=GEMFILE\fR
20
20
  Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\.
21
- .TP
22
- \fB\-\-path=PATH\fR
23
- Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\.
24
21
 
@@ -5,7 +5,6 @@ bundle-check(1) -- Verifies if dependencies are satisfied by installed gems
5
5
 
6
6
  `bundle check` [--dry-run]
7
7
  [--gemfile=FILE]
8
- [--path=PATH]
9
8
 
10
9
  ## DESCRIPTION
11
10
 
@@ -25,7 +24,3 @@ installed on the local machine, if they satisfy the requirements.
25
24
 
26
25
  * `--gemfile=GEMFILE`:
27
26
  Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)].
28
-
29
- * `--path=PATH`:
30
- Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`).
31
- Bundler will remember this value for future installs on this machine.
@@ -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\-CLEAN" "1" "March 2025" ""
3
+ .TH "BUNDLE\-CLEAN" "1" "March 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
6
6
  .SH "SYNOPSIS"