bundler 4.0.19 → 4.0.22

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/bundler.gemspec +1 -1
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/cli/doctor/diagnose.rb +1 -1
  6. data/lib/bundler/cli/exec.rb +15 -1
  7. data/lib/bundler/cli/init.rb +4 -0
  8. data/lib/bundler/cli/outdated.rb +37 -7
  9. data/lib/bundler/cli/platform.rb +15 -1
  10. data/lib/bundler/cli/update.rb +1 -1
  11. data/lib/bundler/cli.rb +19 -7
  12. data/lib/bundler/definition.rb +12 -2
  13. data/lib/bundler/dsl.rb +1 -1
  14. data/lib/bundler/fetcher/downloader.rb +10 -1
  15. data/lib/bundler/gem_helper.rb +2 -2
  16. data/lib/bundler/installer.rb +4 -0
  17. data/lib/bundler/man/bundle-lock.1 +2 -2
  18. data/lib/bundler/man/bundle-lock.1.ronn +4 -3
  19. data/lib/bundler/man/bundle-outdated.1 +2 -2
  20. data/lib/bundler/man/bundle-outdated.1.ronn +8 -2
  21. data/lib/bundler/man/bundle-platform.1 +4 -0
  22. data/lib/bundler/man/bundle-platform.1.ronn +4 -0
  23. data/lib/bundler/man/bundle-update.1 +3 -3
  24. data/lib/bundler/man/bundle-update.1.ronn +5 -3
  25. data/lib/bundler/man/gemfile.5 +1 -1
  26. data/lib/bundler/man/gemfile.5.ronn +3 -1
  27. data/lib/bundler/runtime.rb +11 -11
  28. data/lib/bundler/self_manager.rb +15 -9
  29. data/lib/bundler/shared_helpers.rb +15 -0
  30. data/lib/bundler/source/git/git_proxy.rb +73 -4
  31. data/lib/bundler/source/git.rb +10 -8
  32. data/lib/bundler/source/path.rb +1 -1
  33. data/lib/bundler/source/rubygems.rb +1 -1
  34. data/lib/bundler/stub_specification.rb +3 -1
  35. data/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
  36. data/lib/bundler/version.rb +1 -1
  37. data/lib/bundler.rb +16 -8
  38. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b226f9f760a2d66f3b95d374178f56adb909e5cf3ffd2dc11c7605b2e87dba70
4
- data.tar.gz: 86e4c8a419331c322df10fa720ad136270b195de3550bd98760aae42d825f6c2
3
+ metadata.gz: ce74f459384799eda3343da15c0d6bf655b5fcf2187e2ddaf1b3147aebfea1de
4
+ data.tar.gz: 6db3f22f6acb9d79523eb10d02f09e813d38c966e8453b6b8a4ee2ab7cf9fb68
5
5
  SHA512:
6
- metadata.gz: 27f08e16ceebc01eb1d884c5307b55d993c5048184c4eb2cc3df91596f384b1f23cf038f3b95119bbf0b89aee8f2cad2b380ddf5f8bd0500470fc1a04f882e70
7
- data.tar.gz: 4aaac6eb994de8d3fe9d3305168cea18e2eecd31802681bb548f70cd4ebebcf996d5edb85a61f090cdb05447f57dd074c113872da11831072c07a0c9cc4341e6
6
+ metadata.gz: d3f31182a84dc873e148b3ea4c8bd2e4fde0abc5bc5a116ea99f76519a55680fc41bf3f801bcd83055d084dd6f766ecd40d02b6afe8f51e68edf553bbbe90f99
7
+ data.tar.gz: c34dc9b81612b1e6a23947545c089c40e03d2fdd8e5111dd04701c992b90d7cd5fd8f6fd0564ac340d961ab9bb030cdbfa81e44a9d2178ce3316c1d19ea07ffc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.22 / 2026-09-30
4
+
5
+ ### Enhancements:
6
+
7
+ * Report the effective platform in `bundle platform`. Pull request [#9898](https://github.com/ruby/rubygems/pull/9898) by Islam Elsayed
8
+ * Keep credentials on redirects only within the same origin. Pull request [#9909](https://github.com/ruby/rubygems/pull/9909) by Hiroshi SHIBATA
9
+ * Update Magnus version in Rust extension gem template. Pull request [#9904](https://github.com/ruby/rubygems/pull/9904) by Mat Sadler and Hiroshi SHIBATA
10
+
11
+ ### Bug fixes:
12
+
13
+ * Stop `Bundler.bin_path` creating the directory it reports. Pull request [#9887](https://github.com/ruby/rubygems/pull/9887) by Islam Elsayed and Hiroshi SHIBATA
14
+ * Look up `bundler-<command>` executables only in PATH. Pull request [#9874](https://github.com/ruby/rubygems/pull/9874) by Hiroshi SHIBATA
15
+
16
+ ### Documentation:
17
+
18
+ * Describe `--major` as preferring the latest major version. Pull request [#9891](https://github.com/ruby/rubygems/pull/9891) by Hiroshi SHIBATA
19
+
20
+ ## 4.0.21 / 2026-09-16
21
+
22
+ ### Enhancements:
23
+
24
+ * Don't update bundler to a prerelease unless asked for one. Pull request [#9869](https://github.com/ruby/rubygems/pull/9869) by Hiroshi SHIBATA
25
+ * Reject Bundler redirects that downgrade https to http. Pull request [#9859](https://github.com/ruby/rubygems/pull/9859) by Hiroshi SHIBATA
26
+
27
+ ### Bug fixes:
28
+
29
+ * Support `safe.bareRepository=explicit` in git sources. Pull request [#9876](https://github.com/ruby/rubygems/pull/9876) by Hiroshi SHIBATA
30
+ * Stop resolving locally for empty CHECKSUMS entries. Pull request [#9862](https://github.com/ruby/rubygems/pull/9862) by Hiroshi SHIBATA
31
+ * Expand the git source gemspec path before the chdir. Pull request [#9845](https://github.com/ruby/rubygems/pull/9845) by Hiroshi SHIBATA
32
+
33
+ ## 4.0.20 / 2026-09-02
34
+
35
+ ### Enhancements:
36
+
37
+ * Avoid duplicate relative path prefix in bundle exec. Pull request [#9596](https://github.com/ruby/rubygems/pull/9596) by samuel-williams-shopify
38
+ * Follow renamed default branch in git sources. Pull request [#9813](https://github.com/ruby/rubygems/pull/9813) by hsbt
39
+ * Bundler::Source::Git: avoid re-fetching the repo. Pull request [#9806](https://github.com/ruby/rubygems/pull/9806) by byroot
40
+ * Show the newest out-of-cooldown version in bundle outdated. Pull request [#9803](https://github.com/ruby/rubygems/pull/9803) by hsbt
41
+
42
+ ### Bug fixes:
43
+
44
+ * Error out when `bundle init --gemspec` gets no specification. Pull request [#9818](https://github.com/ruby/rubygems/pull/9818) by hsbt
45
+ * Fix relative gemspec paths being expanded twice. Pull request [#9814](https://github.com/ruby/rubygems/pull/9814) by hsbt
46
+ * Fix gemspec evaluation under Ruby::Box. Pull request [#9809](https://github.com/ruby/rubygems/pull/9809) by hsbt
47
+ * Fix release date extraction for the current changelog header format. Pull request [#9767](https://github.com/ruby/rubygems/pull/9767) by meganemura
48
+ * Resolve globbed entries literally in Gem::Util.glob_files_in_dir. Pull request [#9802](https://github.com/ruby/rubygems/pull/9802) by hsbt
49
+ * Preserve native extensions during implicit clean. Pull request [#9800](https://github.com/ruby/rubygems/pull/9800) by sjh9714
50
+
51
+ ### Documentation:
52
+
53
+ * Clarify :path expectations and cross-link platform docs in man pages. Pull request [#9724](https://github.com/ruby/rubygems/pull/9724) by hsbt
54
+
3
55
  ## 4.0.19 / 2026-08-20
4
56
 
5
57
  ### Enhancements:
data/bundler.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.metadata = {
26
26
  "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
27
- "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/CHANGELOG-bundler.md",
27
+ "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/CHANGELOG.md",
28
28
  "homepage_uri" => "https://bundler.io/",
29
29
  "source_code_uri" => "https://github.com/ruby/rubygems",
30
30
  }
@@ -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 = nil
8
- @git_commit_sha = "2d0e3df43a".freeze
7
+ @built_at = "2026-09-30".freeze
8
+ @git_commit_sha = "ff2bd50".freeze
9
9
  # end ivars
10
10
 
11
11
  # A hash representation of the build metadata.
@@ -53,7 +53,7 @@ module Bundler
53
53
  end
54
54
 
55
55
  def bundles_for_gem(spec)
56
- Dir.glob("#{spec.full_gem_path}/**/*.bundle")
56
+ SharedHelpers.glob_files_in_dir("**/*.bundle", spec.full_gem_path)
57
57
  end
58
58
 
59
59
  def lookup_with_fiddle(path)
@@ -23,7 +23,7 @@ module Bundler
23
23
  bin_path.delete_suffix!(".bat") if Gem.win_platform?
24
24
  kernel_load(bin_path, *args)
25
25
  else
26
- bin_path = "./" + bin_path unless File.absolute_path?(bin_path)
26
+ bin_path = explicit_path(bin_path)
27
27
  kernel_exec(bin_path, *args)
28
28
  end
29
29
  else
@@ -71,6 +71,20 @@ module Bundler
71
71
  "#{file} #{args.join(" ")}".strip
72
72
  end
73
73
 
74
+ def explicit_path(path)
75
+ if File.absolute_path?(path) || explicit_relative_path?(path)
76
+ path
77
+ else
78
+ ".#{File::SEPARATOR}#{path}"
79
+ end
80
+ end
81
+
82
+ def explicit_relative_path?(path)
83
+ [File::SEPARATOR, File::ALT_SEPARATOR].compact.any? do |separator|
84
+ path.start_with?(".#{separator}", "..#{separator}")
85
+ end
86
+ end
87
+
74
88
  def directly_loadable?(file)
75
89
  if Gem.win_platform?
76
90
  script_wrapper?(file)
@@ -26,6 +26,10 @@ module Bundler
26
26
  end
27
27
 
28
28
  spec = Bundler.load_gemspec_uncached(gemspec)
29
+ unless spec
30
+ Bundler.ui.error "Gem specification #{gemspec} did not produce a specification"
31
+ exit 1
32
+ end
29
33
 
30
34
  File.open(gemfile, "wb") do |file|
31
35
  file << "# Generated from #{gemspec}\n"
@@ -158,11 +158,29 @@ module Bundler
158
158
 
159
159
  return active_spec if strict
160
160
 
161
- active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.installable_on_platform?(current_spec.platform) }.sort_by(&:version)
162
- if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
163
- active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
161
+ matching_specs(active_spec, current_spec).last
162
+ end
163
+
164
+ def matching_specs(active_spec, current_spec)
165
+ @matching_specs ||= {}
166
+ @matching_specs[[active_spec.source, current_spec.name, current_spec.platform]] ||= begin
167
+ active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.installable_on_platform?(current_spec.platform) }.sort_by(&:version)
168
+ if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
169
+ active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
170
+ end
171
+ active_specs
164
172
  end
165
- active_specs.last
173
+ end
174
+
175
+ # The newest version the cooldown setting would let bundler adopt right
176
+ # now, when the newest overall version is still inside the window. Only a
177
+ # version strictly between the installed one and the newest one is an
178
+ # adoptable update worth showing.
179
+ def newest_out_of_cooldown(active_spec, current_spec)
180
+ newest = matching_specs(active_spec, current_spec).reverse_each.find {|spec| cooldown_days_remaining(spec).nil? }
181
+ return unless newest
182
+ return if newest.version >= active_spec.version || newest.version <= current_spec.version
183
+ newest
166
184
  end
167
185
 
168
186
  def print_gems(gems_list)
@@ -208,7 +226,11 @@ module Bundler
208
226
  spec_outdated_info += ", released #{release_date}" unless release_date.empty?
209
227
 
210
228
  remaining = cooldown_days_remaining(active_spec)
211
- spec_outdated_info += ", in cooldown for #{remaining} more day#{"s" if remaining > 1}" if remaining
229
+ if remaining
230
+ spec_outdated_info += ", in cooldown for #{remaining} more day#{"s" if remaining > 1}"
231
+ adoptable = newest_out_of_cooldown(active_spec, current_spec)
232
+ spec_outdated_info += ", newest out of cooldown #{adoptable.version}" if adoptable
233
+ end
212
234
 
213
235
  spec_outdated_info += ")"
214
236
 
@@ -227,7 +249,11 @@ module Bundler
227
249
  current_version = "#{current_spec.version}#{current_spec.git_version}"
228
250
  spec_version = "#{active_spec.version}#{active_spec.git_version}"
229
251
  remaining = cooldown_days_remaining(active_spec)
230
- spec_version += " (cooldown #{remaining}d)" if remaining
252
+ if remaining
253
+ adoptable = newest_out_of_cooldown(active_spec, current_spec)
254
+ adoptable_note = adoptable ? ", #{adoptable.version} out of cooldown" : ""
255
+ spec_version += " (cooldown #{remaining}d#{adoptable_note})"
256
+ end
231
257
  dependency = dependency.requirement if dependency
232
258
 
233
259
  ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s]
@@ -236,7 +262,7 @@ module Bundler
236
262
  ret_val
237
263
  end
238
264
 
239
- def cooldown_days_remaining(spec, now = Time.now)
265
+ def cooldown_days_remaining(spec, now = cooldown_now)
240
266
  return nil unless spec.respond_to?(:created_at) && spec.created_at
241
267
  return nil unless spec.respond_to?(:remote) && spec.remote
242
268
  days = spec.remote.effective_cooldown
@@ -245,6 +271,10 @@ module Bundler
245
271
  remaining > 0 ? remaining.ceil : nil
246
272
  end
247
273
 
274
+ def cooldown_now
275
+ @cooldown_now ||= Time.now
276
+ end
277
+
248
278
  def check_for_deployment_mode!
249
279
  return unless Bundler.frozen_bundle?
250
280
  suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any?
@@ -25,7 +25,7 @@ module Bundler
25
25
  else
26
26
  platforms = Bundler.definition.platforms.map {|p| "* #{p}" }
27
27
 
28
- output << "Your platform is: #{Gem::Platform.local}"
28
+ output << platform_info
29
29
  output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}"
30
30
 
31
31
  if ruby_version
@@ -44,5 +44,19 @@ module Bundler
44
44
 
45
45
  Bundler.ui.info output.join("\n\n")
46
46
  end
47
+
48
+ private
49
+
50
+ def platform_info
51
+ info = "Your platform is: #{Gem::Platform.local}"
52
+ return info if Bundler.local_platform == Gem::Platform.local
53
+
54
+ info + "\nHowever, your effective platform is: #{Bundler.local_platform} " \
55
+ "(because force_ruby_platform is #{force_ruby_platform_origin})"
56
+ end
57
+
58
+ def force_ruby_platform_origin
59
+ Bundler.settings.pretty_values_for(:force_ruby_platform).first.sub(/\ASet /, "set ")
60
+ end
47
61
  end
48
62
  end
@@ -13,7 +13,7 @@ module Bundler
13
13
 
14
14
  update_bundler = options[:bundler]
15
15
 
16
- Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler
16
+ Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler, pre: options[:pre]) if update_bundler
17
17
 
18
18
  Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
19
19
 
data/lib/bundler/cli.rb CHANGED
@@ -177,7 +177,7 @@ module Bundler
177
177
  else
178
178
  puts File.read("#{man_path}/#{File.basename(man_page)}.ronn")
179
179
  end
180
- elsif command_path = Bundler.which("bundler-#{cli}")
180
+ elsif command_path = self.class.bundler_command_path(cli)
181
181
  Kernel.exec(command_path, "--help")
182
182
  else
183
183
  super
@@ -189,11 +189,23 @@ module Bundler
189
189
  return Bundler::Plugin.exec_command(command, ARGV[1..-1])
190
190
  end
191
191
 
192
- return super unless command_path = Bundler.which("bundler-#{command}")
192
+ return super unless command_path = bundler_command_path(command)
193
193
 
194
194
  Kernel.exec(command_path, *ARGV[1..-1])
195
195
  end
196
196
 
197
+ # Only PATH is searched, unlike Bundler.which, which also finds a file in
198
+ # the current directory and returns a bare name that Kernel.exec cannot run.
199
+ def self.bundler_command_path(command)
200
+ ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).each do |path|
201
+ path = path[1..-2] if path.start_with?('"') && path.end_with?('"')
202
+ command_path = Bundler.find_executable(File.expand_path("bundler-#{command}", path))
203
+ return command_path if command_path
204
+ end
205
+
206
+ nil
207
+ end
208
+
197
209
  desc "init [OPTIONS]", "Generates a Gemfile into the current working directory"
198
210
  long_desc <<-D
199
211
  Init generates a default Gemfile in the current working directory. When adding a
@@ -317,10 +329,10 @@ module Bundler
317
329
  method_option "source", type: :array, banner: "Update a specific source (and all gems associated with it)"
318
330
  method_option "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed"
319
331
  method_option "ruby", type: :boolean, banner: "Update ruby specified in Gemfile.lock"
320
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
332
+ method_option "bundler", type: :string, lazy_default: ">= #{Bundler::VERSION}", banner: "Update the locked version of bundler"
321
333
  method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
322
334
  method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
323
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
335
+ method_option "major", type: :boolean, banner: "Prefer updating to latest major version (default)"
324
336
  method_option "pre", type: :boolean, banner: "Always choose the highest allowed version when updating gems, regardless of prerelease status"
325
337
  method_option "strict", type: :boolean, banner: "Do not allow any gem to be updated past latest --patch | --minor | --major"
326
338
  method_option "conservative", type: :boolean, banner: "Use bundle install conservative update behavior and do not allow shared dependencies to be updated."
@@ -431,7 +443,7 @@ module Bundler
431
443
  method_option "filter-strict", type: :boolean, aliases: "--strict", banner: "Only list newer versions allowed by your Gemfile requirements"
432
444
  method_option "update-strict", type: :boolean, banner: "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major"
433
445
  method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
434
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
446
+ method_option "major", type: :boolean, banner: "Prefer updating to latest major version (default)"
435
447
  method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
436
448
  method_option "filter-major", type: :boolean, banner: "Only list major newer versions"
437
449
  method_option "filter-minor", type: :boolean, banner: "Only list minor newer versions"
@@ -638,11 +650,11 @@ module Bundler
638
650
  method_option "normalize-platforms", type: :boolean, default: false, banner: "Normalize lockfile platforms"
639
651
  method_option "patch", type: :boolean, banner: "If updating, prefer updating only to next patch version"
640
652
  method_option "minor", type: :boolean, banner: "If updating, prefer updating only to next minor version"
641
- method_option "major", type: :boolean, banner: "If updating, prefer updating to next major version (default)"
653
+ method_option "major", type: :boolean, banner: "If updating, prefer updating to latest major version (default)"
642
654
  method_option "pre", type: :boolean, banner: "If updating, always choose the highest allowed version, regardless of prerelease status"
643
655
  method_option "strict", type: :boolean, banner: "If updating, do not allow any gem to be updated past latest --patch | --minor | --major"
644
656
  method_option "conservative", type: :boolean, banner: "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated"
645
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
657
+ method_option "bundler", type: :string, lazy_default: ">= #{Bundler::VERSION}", banner: "Update the locked version of bundler"
646
658
  method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
647
659
  def lock
648
660
  require_relative "cli/lock"
@@ -192,7 +192,7 @@ module Bundler
192
192
 
193
193
  sources.cached!
194
194
 
195
- if options[:add_checksums] || (!options[:local] && install_needed?)
195
+ if options[:add_checksums] || (!options[:local] && (install_needed? || @locked_spec_with_empty_checksums))
196
196
  sources.remote!
197
197
  true
198
198
  else
@@ -639,7 +639,7 @@ module Bundler
639
639
  @missing_lockfile_dep ||
640
640
  @unlocking_bundler ||
641
641
  @locked_spec_with_missing_checksums ||
642
- @locked_spec_with_empty_checksums ||
642
+ empty_checksums_actionable? ||
643
643
  @locked_spec_with_missing_deps ||
644
644
  @locked_spec_with_invalid_deps
645
645
  end
@@ -648,6 +648,16 @@ module Bundler
648
648
  unlocking? || something_changed?
649
649
  end
650
650
 
651
+ # Only a remote fetch can fill an empty CHECKSUMS entry, so it justifies a
652
+ # resolution only when one is coming. Resolving locally for it would repeat
653
+ # on every `Bundler.setup` without changing the lockfile. Frozen mode still
654
+ # has to refuse the entry.
655
+ def empty_checksums_actionable?
656
+ return false unless @locked_spec_with_empty_checksums
657
+
658
+ Bundler.frozen_bundle? || !sources.local_mode?
659
+ end
660
+
651
661
  def should_add_extra_platforms?
652
662
  !lockfile_exists? && Bundler::MatchPlatform.generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
653
663
  end
data/lib/bundler/dsl.rb CHANGED
@@ -68,7 +68,7 @@ module Bundler
68
68
  development_group = opts[:development_group] || :development
69
69
  expanded_path = gemfile_root.join(path)
70
70
 
71
- gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
71
+ gemspecs = SharedHelpers.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
72
72
  gemspecs.reject! {|s| s.name != name } if name
73
73
  specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] }
74
74
 
@@ -46,7 +46,12 @@ module Bundler
46
46
  response
47
47
  when Gem::Net::HTTPRedirection
48
48
  new_uri = Gem::URI.parse(response["location"])
49
- if new_uri.host == uri.host
49
+ # Following a downgrade would put the credentials this request carries
50
+ # on a plaintext connection, so refuse it like Gem::RemoteFetcher does.
51
+ if https?(uri) && !https?(new_uri)
52
+ raise HTTPError, "Redirecting to a non-https URI is not allowed: #{URICredentialsFilter.credential_filtered_uri(new_uri)}"
53
+ end
54
+ if [new_uri.scheme, new_uri.host, new_uri.port] == [uri.scheme, uri.host, uri.port]
50
55
  new_uri.user = uri.user
51
56
  new_uri.password = uri.password
52
57
  end
@@ -105,6 +110,10 @@ module Bundler
105
110
 
106
111
  private
107
112
 
113
+ def https?(uri)
114
+ uri.scheme&.casecmp("https")&.zero?
115
+ end
116
+
108
117
  def validate_uri_scheme!(uri)
109
118
  return if /\Ahttps?\z/.match?(uri.scheme)
110
119
  raise InvalidOption,
@@ -32,7 +32,7 @@ module Bundler
32
32
 
33
33
  def initialize(base = nil, name = nil)
34
34
  @base = File.expand_path(base || SharedHelpers.pwd)
35
- gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base)
35
+ gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : SharedHelpers.glob_files_in_dir("{,*}.gemspec", @base)
36
36
  raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
37
37
  @spec_path = gemspecs.first
38
38
  @gemspec = Bundler.load_gemspec(@spec_path)
@@ -124,7 +124,7 @@ module Bundler
124
124
  end
125
125
 
126
126
  def built_gem_path
127
- Gem::Util.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last
127
+ SharedHelpers.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last
128
128
  end
129
129
 
130
130
  def git_push(remote = nil)
@@ -127,6 +127,8 @@ module Bundler
127
127
  template_path = File.expand_path("templates/Executable", __dir__)
128
128
  template = File.read(template_path)
129
129
 
130
+ Bundler.mkdir_p(bin_path)
131
+
130
132
  exists = []
131
133
  spec.executables.each do |executable|
132
134
  binstub_path = "#{bin_path}/#{executable}"
@@ -173,6 +175,8 @@ module Bundler
173
175
  ruby_command = Thor::Util.ruby_command
174
176
  ruby_command = ruby_command
175
177
 
178
+ Bundler.mkdir_p(bin_path)
179
+
176
180
  spec.executables.each do |executable|
177
181
  next if executable == "bundle"
178
182
  executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path)
@@ -13,7 +13,7 @@ Lock the gems specified in Gemfile\.
13
13
  Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\.
14
14
  .TP
15
15
  \fB\-\-bundler[=BUNDLER]\fR
16
- Update the locked version of bundler to the given version or the latest version if no version is given\.
16
+ Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\.
17
17
  .TP
18
18
  \fB\-\-local\fR
19
19
  Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
@@ -49,7 +49,7 @@ If updating, prefer updating only to next patch version\.
49
49
  If updating, prefer updating only to next minor version\.
50
50
  .TP
51
51
  \fB\-\-major\fR
52
- If updating, prefer updating to next major version (default)\.
52
+ If updating, prefer updating to latest major version (default)\.
53
53
  .TP
54
54
  \fB\-\-pre\fR
55
55
  If updating, always choose the highest allowed version, regardless of prerelease status\.
@@ -33,8 +33,9 @@ Lock the gems specified in Gemfile.
33
33
  of gems or updating all gems if no list is given.
34
34
 
35
35
  * `--bundler[=BUNDLER]`:
36
- Update the locked version of bundler to the given version or the latest
37
- version if no version is given.
36
+ Update the locked version of bundler. BUNDLER can be a version such as
37
+ `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the
38
+ latest released version, which never selects a prerelease.
38
39
 
39
40
  * `--local`:
40
41
  Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the
@@ -74,7 +75,7 @@ Lock the gems specified in Gemfile.
74
75
  If updating, prefer updating only to next minor version.
75
76
 
76
77
  * `--major`:
77
- If updating, prefer updating to next major version (default).
78
+ If updating, prefer updating to latest major version (default).
78
79
 
79
80
  * `--pre`:
80
81
  If updating, always choose the highest allowed version, regardless of prerelease status.
@@ -37,7 +37,7 @@ List gems organized by groups\.
37
37
  Prefer updating only to next minor version\.
38
38
  .TP
39
39
  \fB\-\-major\fR
40
- Prefer updating to next major version (default)\.
40
+ Prefer updating to latest major version (default)\.
41
41
  .TP
42
42
  \fB\-\-patch\fR
43
43
  Prefer updating only to next patch version\.
@@ -55,7 +55,7 @@ Only list patch newer versions\.
55
55
  Only list gems specified in your Gemfile, not their dependencies\.
56
56
  .TP
57
57
  \fB\-\-cooldown=<number>\fR
58
- Annotate (rather than hide) versions that are still inside the cooldown window of \fInumber\fR days\. The prose output appends "in cooldown for Nd more days" and the table form adds "(cooldown Nd)" to the Latest column\. See \fBcooldown\fR in bundle\-config(1)\.
58
+ Annotate (rather than hide) versions that are still inside the cooldown window of \fInumber\fR days\. The prose output appends "in cooldown for Nd more days" and the table form adds "(cooldown Nd)" to the Latest column\. When a version outside the window is newer than the installed one, the prose output also appends "newest out of cooldown X" and the table form becomes "(cooldown Nd, X out of cooldown)"\. With \fB\-\-filter\-strict\fR (or \fB\-\-patch\fR, \fB\-\-minor\fR, \fB\-\-major\fR, which imply it), "newest" is already the cooldown\-filtered resolved version, so none of these annotations appear\. See \fBcooldown\fR in bundle\-config(1)\.
59
59
  .SH "PATCH LEVEL OPTIONS"
60
60
  See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
61
61
  .SH "FILTERING OUTPUT"
@@ -55,7 +55,7 @@ are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
55
55
  Prefer updating only to next minor version.
56
56
 
57
57
  * `--major`:
58
- Prefer updating to next major version (default).
58
+ Prefer updating to latest major version (default).
59
59
 
60
60
  * `--patch`:
61
61
  Prefer updating only to next patch version.
@@ -76,7 +76,13 @@ are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
76
76
  Annotate (rather than hide) versions that are still inside the
77
77
  cooldown window of <number> days. The prose output appends "in
78
78
  cooldown for Nd more days" and the table form adds "(cooldown Nd)" to
79
- the Latest column. See `cooldown` in bundle-config(1).
79
+ the Latest column. When a version outside the window is newer than the
80
+ installed one, the prose output also appends "newest out of cooldown
81
+ X" and the table form becomes "(cooldown Nd, X out of cooldown)".
82
+ With `--filter-strict` (or `--patch`, `--minor`, `--major`, which
83
+ imply it), "newest" is already the cooldown-filtered resolved version,
84
+ so none of these annotations appear. See `cooldown` in
85
+ bundle-config(1).
80
86
 
81
87
  ## PATCH LEVEL OPTIONS
82
88
 
@@ -38,6 +38,8 @@ Your current platform satisfies the Ruby version requirement\.
38
38
  .IP "" 0
39
39
  .P
40
40
  \fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn't match the running Ruby VM, it tells you what part does not\.
41
+ .P
42
+ For a detailed explanation of how bundler handles platforms, see the \fBPLATFORMS\fR section in Gemfile(5)\.
41
43
  .SH "OPTIONS"
42
44
  .TP
43
45
  \fB\-\-ruby\fR
@@ -45,5 +47,7 @@ It will display the ruby directive information, so you don't have to parse it fr
45
47
  .SH "SEE ALSO"
46
48
  .IP "\(bu" 4
47
49
  bundle\-lock(1) \fIbundle\-lock\.1\.html\fR
50
+ .IP "\(bu" 4
51
+ Gemfile(5) \fIgemfile\.5\.html\fR
48
52
  .IP "" 0
49
53
 
@@ -38,6 +38,9 @@ If you run `bundle platform` on Ruby 3.1.2, it displays the following output:
38
38
  if the `ruby` directive requirement has been met. If `ruby` directive doesn't
39
39
  match the running Ruby VM, it tells you what part does not.
40
40
 
41
+ For a detailed explanation of how bundler handles platforms, see the
42
+ `PLATFORMS` section in Gemfile(5).
43
+
41
44
  ## OPTIONS
42
45
 
43
46
  * `--ruby`:
@@ -47,3 +50,4 @@ match the running Ruby VM, it tells you what part does not.
47
50
  ## SEE ALSO
48
51
 
49
52
  * [bundle-lock(1)](bundle-lock.1.html)
53
+ * [Gemfile(5)](gemfile.5.html)
@@ -27,7 +27,7 @@ Do not attempt to fetch gems remotely and use the gem cache instead\.
27
27
  Update the locked version of Ruby to the current version of Ruby\.
28
28
  .TP
29
29
  \fB\-\-bundler[=BUNDLER]\fR
30
- Update the locked version of bundler to the invoked bundler version\.
30
+ Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\.
31
31
  .TP
32
32
  \fB\-\-force\fR, \fB\-\-redownload\fR
33
33
  Force reinstalling every gem, even if already installed\.
@@ -54,7 +54,7 @@ Prefer updating only to next patch version\.
54
54
  Prefer updating only to next minor version\.
55
55
  .TP
56
56
  \fB\-\-major\fR
57
- Prefer updating to next major version (default)\.
57
+ Prefer updating to latest major version (default)\.
58
58
  .TP
59
59
  \fB\-\-pre\fR
60
60
  Always choose the highest allowed version, regardless of prerelease status\.
@@ -175,7 +175,7 @@ Prefer updating only to next patch version\.
175
175
  Prefer updating only to next minor version\.
176
176
  .TP
177
177
  \fB\-\-major\fR
178
- Prefer updating to next major version (default)\.
178
+ Prefer updating to latest major version (default)\.
179
179
  .TP
180
180
  \fB\-\-strict\fR
181
181
  Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
@@ -53,7 +53,9 @@ gem.
53
53
  Update the locked version of Ruby to the current version of Ruby.
54
54
 
55
55
  * `--bundler[=BUNDLER]`:
56
- Update the locked version of bundler to the invoked bundler version.
56
+ Update the locked version of bundler. BUNDLER can be a version such as
57
+ `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the
58
+ latest released version, which never selects a prerelease.
57
59
 
58
60
  * `--force`, `--redownload`:
59
61
  Force reinstalling every gem, even if already installed.
@@ -81,7 +83,7 @@ gem.
81
83
  Prefer updating only to next minor version.
82
84
 
83
85
  * `--major`:
84
- Prefer updating to next major version (default).
86
+ Prefer updating to latest major version (default).
85
87
 
86
88
  * `--pre`:
87
89
  Always choose the highest allowed version, regardless of prerelease status.
@@ -236,7 +238,7 @@ versions are resolved. One of the following options can be used: `--patch`,
236
238
  Prefer updating only to next minor version.
237
239
 
238
240
  * `--major`:
239
- Prefer updating to next major version (default).
241
+ Prefer updating to latest major version (default).
240
242
 
241
243
  * `--strict`:
242
244
  Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`.
@@ -392,7 +392,7 @@ gem "rails", git: "https://rails@bitbucket\.org/rails/rails\.git"
392
392
  .P
393
393
  Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
394
394
  .SS "PATH"
395
- You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\.
395
+ You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\. The path must point to a directory containing the gem's unpacked source code, not to a packaged \fB\.gem\fR file\.
396
396
  .P
397
397
  Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\.
398
398
  .P
@@ -451,7 +451,9 @@ Since the `bitbucket` method is a specialization of `git_source`, it accepts a `
451
451
 
452
452
  You can specify that a gem is located in a particular location
453
453
  on the file system. Relative paths are resolved relative to the
454
- directory containing the `Gemfile`.
454
+ directory containing the `Gemfile`. The path must point to a
455
+ directory containing the gem's unpacked source code, not to a
456
+ packaged `.gem` file.
455
457
 
456
458
  Similar to the semantics of the `:git` option, the `:path`
457
459
  option requires that the directory in question either contains
@@ -141,7 +141,7 @@ module Bundler
141
141
  end
142
142
  end
143
143
 
144
- Gem::Util.glob_files_in_dir("*/.git", cache_path.to_s).each do |git_dir|
144
+ SharedHelpers.glob_files_in_dir("*/.git", cache_path.to_s).each do |git_dir|
145
145
  FileUtils.rm_rf(git_dir)
146
146
  FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
147
147
  end
@@ -159,13 +159,13 @@ module Bundler
159
159
  end
160
160
 
161
161
  def clean(dry_run = false)
162
- gem_bins = Gem::Util.glob_files_in_dir("bin/*", Gem.dir)
163
- git_dirs = Gem::Util.glob_files_in_dir("bundler/gems/*", Gem.dir)
164
- git_cache_dirs = Gem::Util.glob_files_in_dir("cache/bundler/git/*", Gem.dir)
165
- gem_dirs = Gem::Util.glob_files_in_dir("gems/*", Gem.dir)
166
- gem_files = Gem::Util.glob_files_in_dir("cache/*.gem", Gem.dir)
167
- gemspec_files = Gem::Util.glob_files_in_dir("specifications/*.gemspec", Gem.dir)
168
- extension_dirs = Gem::Util.glob_files_in_dir("extensions/*/*/*", Gem.dir) + Gem::Util.glob_files_in_dir("bundler/gems/extensions/*/*/*", Gem.dir)
162
+ gem_bins = SharedHelpers.glob_files_in_dir("bin/*", Gem.dir)
163
+ git_dirs = SharedHelpers.glob_files_in_dir("bundler/gems/*", Gem.dir)
164
+ git_cache_dirs = SharedHelpers.glob_files_in_dir("cache/bundler/git/*", Gem.dir)
165
+ gem_dirs = SharedHelpers.glob_files_in_dir("gems/*", Gem.dir)
166
+ gem_files = SharedHelpers.glob_files_in_dir("cache/*.gem", Gem.dir)
167
+ gemspec_files = SharedHelpers.glob_files_in_dir("specifications/*.gemspec", Gem.dir)
168
+ extension_dirs = SharedHelpers.glob_files_in_dir("extensions/*/*/*", Gem.dir) + SharedHelpers.glob_files_in_dir("bundler/gems/extensions/*/*/*", Gem.dir)
169
169
  spec_gem_paths = []
170
170
  # need to keep git sources around
171
171
  spec_git_paths = @definition.spec_git_paths
@@ -232,7 +232,7 @@ module Bundler
232
232
  private
233
233
 
234
234
  def prune_gem_cache(resolve, cache_path)
235
- cached = Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s)
235
+ cached = SharedHelpers.glob_files_in_dir("*.gem", cache_path.to_s)
236
236
 
237
237
  cached = cached.delete_if do |path|
238
238
  spec = Bundler.rubygems.spec_from_gem path
@@ -257,7 +257,7 @@ module Bundler
257
257
  end
258
258
 
259
259
  def prune_git_and_path_cache(resolve, cache_path)
260
- cached = Gem::Util.glob_files_in_dir("*/.bundlecache", cache_path.to_s)
260
+ cached = SharedHelpers.glob_files_in_dir("*/.bundlecache", cache_path.to_s)
261
261
 
262
262
  cached = cached.delete_if do |path|
263
263
  name = File.basename(File.dirname(path))
@@ -283,7 +283,7 @@ module Bundler
283
283
  # Add man/ subdirectories from activated bundles to MANPATH for man(1)
284
284
  manuals = $LOAD_PATH.filter_map do |path|
285
285
  man_subdir = path.sub(/lib$/, "man")
286
- man_subdir unless Dir.glob("man?/", base: man_subdir).empty?
286
+ man_subdir unless SharedHelpers.glob_files_in_dir("man?/", man_subdir).empty?
287
287
  end
288
288
 
289
289
  return if manuals.empty?
@@ -30,8 +30,8 @@ module Bundler
30
30
  install_and_restart_with(restart_version)
31
31
  end
32
32
 
33
- def update_bundler_and_restart_with_it_if_needed(target)
34
- spec = resolve_update_version_from(target)
33
+ def update_bundler_and_restart_with_it_if_needed(target, pre: false)
34
+ spec = resolve_update_version_from(target, pre: pre)
35
35
  return unless spec
36
36
 
37
37
  version = spec.version
@@ -108,9 +108,9 @@ module Bundler
108
108
  lockfile_version
109
109
  end
110
110
 
111
- def resolve_update_version_from(target)
111
+ def resolve_update_version_from(target, pre: false)
112
112
  requirement = Gem::Requirement.new(target)
113
- update_candidate = find_latest_matching_spec(requirement)
113
+ update_candidate = find_latest_matching_spec(requirement, pre: pre)
114
114
 
115
115
  if update_candidate.nil?
116
116
  raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist"
@@ -137,18 +137,24 @@ module Bundler
137
137
  end
138
138
  end
139
139
 
140
- def find_latest_matching_spec(requirement)
140
+ def find_latest_matching_spec(requirement, pre: false)
141
141
  Bundler.configure
142
- local_result = find_latest_matching_spec_from_collection(local_specs, requirement)
142
+ # A bare `bundle update --bundler` must stay on releases, like `gem update
143
+ # --system`, so only `--pre` or a prerelease requirement opts into one.
144
+ allow_prerelease = pre || requirement.prerelease?
145
+
146
+ local_result = find_latest_matching_spec_from_collection(local_specs, requirement, allow_prerelease)
143
147
  return local_result if local_result && requirement.specific?
144
148
 
145
- remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement)
149
+ remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement, allow_prerelease)
146
150
  return remote_result if local_result.nil?
147
151
 
148
- [local_result, remote_result].max
152
+ [local_result, remote_result].compact.max
149
153
  end
150
154
 
151
- def find_latest_matching_spec_from_collection(specs, requirement)
155
+ def find_latest_matching_spec_from_collection(specs, requirement, allow_prerelease)
156
+ specs = specs.reject {|spec| spec.version.prerelease? } unless allow_prerelease
157
+
152
158
  specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) }
153
159
  end
154
160
 
@@ -231,6 +231,21 @@ module Bundler
231
231
  destination
232
232
  end
233
233
 
234
+ # Globs for entries matching +glob+ inside of +base_path+, returning
235
+ # absolute paths. Glob metacharacters in +base_path+ are not treated as
236
+ # part of the pattern, and matched entries are joined literally, so an
237
+ # entry starting with `~` is not expanded into the home directory.
238
+ #
239
+ # Bundler runs against whatever RubyGems the host provides, so this cannot
240
+ # delegate to Gem::Util.glob_files_in_dir, which only gained the literal
241
+ # join in RubyGems 4.1.
242
+ def glob_files_in_dir(glob, base_path)
243
+ expanded_path = nil
244
+ Dir.glob(glob, base: base_path).map! do |f|
245
+ File.join(expanded_path ||= File.expand_path(base_path), f)
246
+ end
247
+ end
248
+
234
249
  private
235
250
 
236
251
  def validate_bundle_path
@@ -193,7 +193,13 @@ module Bundler
193
193
  return out if status.success?
194
194
 
195
195
  if err.include?("couldn't find remote ref") || err.include?("not our ref")
196
- raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri)
196
+ default_branch = renamed_remote_default_branch if tracking_remote_default_branch?
197
+ if default_branch
198
+ out = follow_remote_default_branch(args, default_branch)
199
+ return out if out
200
+ end
201
+
202
+ raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref || current_branch, credential_filtered_uri)
197
203
  else
198
204
  if shallow?
199
205
  args -= depth_args
@@ -298,6 +304,61 @@ module Bundler
298
304
  branch_option || ref.nil?
299
305
  end
300
306
 
307
+ def tracking_remote_default_branch?
308
+ explicit_ref.nil? && commit.nil?
309
+ end
310
+
311
+ # Returns nil on any failure, leaving HEAD untouched so the caller reports
312
+ # the original fetch failure. Runs inside the retry block, so it must not
313
+ # touch the caller's command locals.
314
+ def follow_remote_default_branch(args, default_branch)
315
+ reference = "refs/heads/#{default_branch}"
316
+ command = fetch_command(args, "#{reference}:#{reference}")
317
+ check_allowed(command)
318
+
319
+ out, err, status = capture(command, path)
320
+ unless status.success?
321
+ Bundler.ui.debug "Could not fetch #{reference} from #{credential_filtered_uri}: #{err}"
322
+ return
323
+ end
324
+
325
+ previous_branch = current_branch
326
+ begin
327
+ git "symbolic-ref", "HEAD", reference, dir: path
328
+ rescue GitError => e
329
+ Bundler.ui.debug "Could not repoint the cached clone at #{reference}: #{e.message}"
330
+ return
331
+ end
332
+ @current_branch = nil
333
+ Bundler.ui.warn "#{credential_filtered_uri} no longer has #{previous_branch}, " \
334
+ "now following its default branch #{default_branch}"
335
+ out
336
+ end
337
+
338
+ # The cached clone's HEAD branch is gone from the remote, so the remote's
339
+ # own idea of its default branch is the only thing left to follow.
340
+ def renamed_remote_default_branch
341
+ default_branch = remote_default_branch
342
+ return if default_branch.nil? || default_branch == current_branch
343
+
344
+ default_branch
345
+ end
346
+
347
+ def remote_default_branch
348
+ command = ["ls-remote", "--symref", "--", configured_uri, "HEAD"]
349
+ check_allowed(command)
350
+
351
+ out, err, status = capture(command, path)
352
+ unless status.success?
353
+ Bundler.ui.debug "Could not ask #{credential_filtered_uri} for its default branch: #{err}"
354
+ return
355
+ end
356
+
357
+ # A remote is free to advertise a ref name that is not valid UTF-8, and
358
+ # matching that as text raises out of the GitError family.
359
+ out.b[%r{^ref:\s+refs/heads/(.+?)\s+HEAD}, 1]
360
+ end
361
+
301
362
  def pinned_to_full_sha?
302
363
  full_sha_revision?(ref)
303
364
  end
@@ -446,7 +507,15 @@ module Bundler
446
507
 
447
508
  return ["git", *opts, *cmd] unless dir
448
509
 
449
- ["git", "-C", dir.to_s, *opts, *cmd]
510
+ # With safe.bareRepository=explicit, git refuses to discover a bare
511
+ # repository from -C, so the cache clone is named with --git-dir.
512
+ # Working trees, like a local override, still go through -C.
513
+ location = bare_repo?(dir) ? "--git-dir" : "-C"
514
+ ["git", location, dir.to_s, *opts, *cmd]
515
+ end
516
+
517
+ def bare_repo?(dir)
518
+ File.exist?(File.join(dir, "objects")) && File.exist?(File.join(dir, "HEAD"))
450
519
  end
451
520
 
452
521
  def extra_clone_args
@@ -465,8 +534,8 @@ module Bundler
465
534
  args
466
535
  end
467
536
 
468
- def fetch_command(args)
469
- ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
537
+ def fetch_command(args, spec = refspec)
538
+ ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, spec].compact
470
539
  end
471
540
 
472
541
  def clone_command(args)
@@ -91,9 +91,9 @@ module Bundler
91
91
 
92
92
  def to_s
93
93
  begin
94
- at = humanized_ref || current_branch
95
-
96
- rev = "at #{at}@#{shortref_for_display(revision)}"
94
+ at = humanized_ref
95
+ at = "#{at}@" if at
96
+ rev = "at #{at}#{shortref_for_display(revision)}"
97
97
  rescue GitError
98
98
  ""
99
99
  end
@@ -320,7 +320,7 @@ module Bundler
320
320
 
321
321
  def serialize_gemspecs_in(destination)
322
322
  destination = destination.expand_path(Bundler.root) if destination.relative?
323
- Gem::Util.glob_files_in_dir(@glob, destination.to_s).each do |spec_path|
323
+ SharedHelpers.glob_files_in_dir(@glob, destination.to_s).each do |spec_path|
324
324
  # Evaluate gemspecs and cache the result. Gemspecs
325
325
  # in git might require git or other dependencies.
326
326
  # The gemspecs we cache should already be evaluated.
@@ -423,10 +423,12 @@ module Bundler
423
423
  def validate_spec(_spec); end
424
424
 
425
425
  def load_gemspec(file)
426
- dirname = Pathname.new(file).dirname
427
- SharedHelpers.chdir(dirname.to_s) do
428
- stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
429
- stub.full_gem_path = dirname.expand_path(root).to_s
426
+ # Expand the path before the chdir below, since resolving it inside the
427
+ # block would base it on the gemspec directory instead of `root`.
428
+ gemspec_path = Pathname.new(file).expand_path(root)
429
+ SharedHelpers.chdir(gemspec_path.dirname.to_s) do
430
+ stub = Gem::StubSpecification.gemspec_stub(gemspec_path.to_s, install_path.parent, install_path.parent)
431
+ stub.full_gem_path = gemspec_path.dirname.to_s
430
432
  StubSpecification.from_stub(stub)
431
433
  end
432
434
  end
@@ -161,7 +161,7 @@ module Bundler
161
161
 
162
162
  if File.directory?(expanded_path)
163
163
  # We sort depth-first since `<<` will override the earlier-found specs
164
- Gem::Util.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file|
164
+ SharedHelpers.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file|
165
165
  next unless spec = load_gemspec(file)
166
166
  spec.source = self
167
167
 
@@ -406,7 +406,7 @@ module Bundler
406
406
  @cached_specs ||= begin
407
407
  idx = Index.new
408
408
 
409
- Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s).each do |gemfile|
409
+ SharedHelpers.glob_files_in_dir("*.gem", cache_path.to_s).each do |gemfile|
410
410
  s ||= Bundler.rubygems.spec_from_gem(gemfile)
411
411
  s.source = self
412
412
  idx << s
@@ -126,7 +126,9 @@ module Bundler
126
126
  def _remote_specification
127
127
  @_remote_specification ||= begin
128
128
  rs = stub.to_spec
129
- if rs.equal?(self) # happens when to_spec gets the spec from Gem.loaded_specs
129
+ # Gem::StubSpecification#to_spec may return an activated specification
130
+ # with the same name and version from a different gem installation.
131
+ if rs.equal?(self) || rs.loaded_from != loaded_from
130
132
  rs = Gem::Specification.load(loaded_from)
131
133
  Bundler.rubygems.stub_set_spec(stub, rs)
132
134
  end
@@ -12,7 +12,7 @@ publish = false
12
12
  crate-type = ["cdylib"]
13
13
 
14
14
  [dependencies]
15
- magnus = { version = "0.8.2" }
15
+ magnus = { version = "0.9" }
16
16
  rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
17
17
 
18
18
  [build-dependencies]
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "4.0.19".freeze
4
+ VERSION = "4.0.22".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= gem_version.segments.first
data/lib/bundler.rb CHANGED
@@ -119,9 +119,7 @@ module Bundler
119
119
  def bin_path
120
120
  @bin_path ||= begin
121
121
  path = Bundler.settings[:bin] || "bin"
122
- path = Pathname.new(path).expand_path(root).expand_path
123
- mkdir_p(path)
124
- path
122
+ Pathname.new(path).expand_path(root).expand_path
125
123
  end
126
124
  end
127
125
 
@@ -527,11 +525,11 @@ module Bundler
527
525
  end
528
526
 
529
527
  def load_gemspec_uncached(file, validate = false)
530
- path = Pathname.new(file)
531
- contents = read_file(file)
528
+ path = Pathname.new(file).expand_path
529
+ contents = read_file(path.to_s)
532
530
  spec = eval_gemspec(path, contents)
533
531
  return unless spec
534
- spec.loaded_from = path.expand_path.to_s
532
+ spec.loaded_from = path.to_s
535
533
  Bundler.rubygems.validate(spec) if validate
536
534
  spec
537
535
  end
@@ -646,9 +644,19 @@ module Bundler
646
644
  eval_yaml_gemspec(path, contents)
647
645
  else
648
646
  # Eval the gemspec from its parent directory, because some gemspecs
649
- # depend on "./" relative paths.
647
+ # depend on "./" relative paths. The caller expands `path` first, since
648
+ # expanding it here would resolve against the gemspec directory once
649
+ # the chdir is active.
650
650
  SharedHelpers.chdir(path.dirname.to_s) do
651
- eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s)
651
+ # TOPLEVEL_BINDING always belongs to the main box, so inside a
652
+ # Ruby::Box use a binding from the box Bundler is loaded in, where
653
+ # Gem::Specification carries Bundler's own monkey patches.
654
+ eval_binding = if defined?(Ruby::Box) && Ruby::Box.enabled?
655
+ Ruby::Box.current.eval("binding")
656
+ else
657
+ TOPLEVEL_BINDING.dup
658
+ end
659
+ eval(contents, eval_binding, path.to_s)
652
660
  end
653
661
  end
654
662
  rescue ScriptError, StandardError => e
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.19
4
+ version: 4.0.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Arko
@@ -384,7 +384,7 @@ licenses:
384
384
  - MIT
385
385
  metadata:
386
386
  bug_tracker_uri: https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler
387
- changelog_uri: https://github.com/ruby/rubygems/blob/master/CHANGELOG-bundler.md
387
+ changelog_uri: https://github.com/ruby/rubygems/blob/master/CHANGELOG.md
388
388
  homepage_uri: https://bundler.io/
389
389
  source_code_uri: https://github.com/ruby/rubygems
390
390
  rdoc_options: []
@@ -401,7 +401,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
401
401
  - !ruby/object:Gem::Version
402
402
  version: 3.4.1
403
403
  requirements: []
404
- rubygems_version: 3.6.9
404
+ rubygems_version: 4.0.16
405
405
  specification_version: 4
406
406
  summary: The best way to manage your application's dependencies
407
407
  test_files: []