rubygems-update 3.5.22 → 3.5.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/bundler/CHANGELOG.md +24 -0
  4. data/bundler/lib/bundler/build_metadata.rb +2 -2
  5. data/bundler/lib/bundler/cli/add.rb +2 -0
  6. data/bundler/lib/bundler/cli/check.rb +2 -2
  7. data/bundler/lib/bundler/cli.rb +1 -0
  8. data/bundler/lib/bundler/definition.rb +10 -16
  9. data/bundler/lib/bundler/dsl.rb +31 -15
  10. data/bundler/lib/bundler/inline.rb +12 -8
  11. data/bundler/lib/bundler/lazy_specification.rb +9 -2
  12. data/bundler/lib/bundler/lockfile_generator.rb +1 -1
  13. data/bundler/lib/bundler/man/bundle-add.1 +5 -2
  14. data/bundler/lib/bundler/man/bundle-add.1.ronn +4 -1
  15. data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
  16. data/bundler/lib/bundler/man/bundle-cache.1 +1 -1
  17. data/bundler/lib/bundler/man/bundle-check.1 +1 -1
  18. data/bundler/lib/bundler/man/bundle-clean.1 +1 -1
  19. data/bundler/lib/bundler/man/bundle-config.1 +1 -5
  20. data/bundler/lib/bundler/man/bundle-config.1.ronn +0 -7
  21. data/bundler/lib/bundler/man/bundle-console.1 +1 -1
  22. data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
  23. data/bundler/lib/bundler/man/bundle-exec.1 +1 -1
  24. data/bundler/lib/bundler/man/bundle-gem.1 +1 -1
  25. data/bundler/lib/bundler/man/bundle-help.1 +1 -1
  26. data/bundler/lib/bundler/man/bundle-info.1 +1 -1
  27. data/bundler/lib/bundler/man/bundle-init.1 +1 -1
  28. data/bundler/lib/bundler/man/bundle-inject.1 +1 -1
  29. data/bundler/lib/bundler/man/bundle-install.1 +2 -2
  30. data/bundler/lib/bundler/man/bundle-install.1.ronn +1 -2
  31. data/bundler/lib/bundler/man/bundle-list.1 +1 -1
  32. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  33. data/bundler/lib/bundler/man/bundle-open.1 +1 -1
  34. data/bundler/lib/bundler/man/bundle-outdated.1 +1 -1
  35. data/bundler/lib/bundler/man/bundle-platform.1 +1 -1
  36. data/bundler/lib/bundler/man/bundle-plugin.1 +1 -1
  37. data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
  38. data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
  39. data/bundler/lib/bundler/man/bundle-show.1 +1 -1
  40. data/bundler/lib/bundler/man/bundle-update.1 +1 -1
  41. data/bundler/lib/bundler/man/bundle-version.1 +1 -1
  42. data/bundler/lib/bundler/man/bundle-viz.1 +1 -1
  43. data/bundler/lib/bundler/man/bundle.1 +1 -1
  44. data/bundler/lib/bundler/man/gemfile.5 +1 -1
  45. data/bundler/lib/bundler/plugin.rb +20 -1
  46. data/bundler/lib/bundler/process_lock.rb +10 -14
  47. data/bundler/lib/bundler/resolver/base.rb +4 -0
  48. data/bundler/lib/bundler/rubygems_ext.rb +14 -0
  49. data/bundler/lib/bundler/rubygems_gem_installer.rb +3 -1
  50. data/bundler/lib/bundler/rubygems_integration.rb +2 -29
  51. data/bundler/lib/bundler/settings.rb +5 -1
  52. data/bundler/lib/bundler/shared_helpers.rb +27 -15
  53. data/bundler/lib/bundler/source/metadata.rb +2 -3
  54. data/bundler/lib/bundler/templates/newgem/Gemfile.tt +0 -3
  55. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +15 -15
  56. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +4 -4
  57. data/bundler/lib/bundler/version.rb +1 -1
  58. data/bundler/lib/bundler.rb +1 -1
  59. data/lib/rubygems/commands/setup_command.rb +6 -0
  60. data/lib/rubygems/gem_runner.rb +9 -0
  61. data/lib/rubygems/gemcutter_utilities.rb +8 -2
  62. data/lib/rubygems/installer.rb +6 -7
  63. data/lib/rubygems/package/tar_header.rb +11 -0
  64. data/lib/rubygems/package/tar_reader/entry.rb +1 -5
  65. data/lib/rubygems/spec_fetcher.rb +35 -7
  66. data/lib/rubygems/specification.rb +1 -1
  67. data/lib/rubygems.rb +2 -1
  68. data/rubygems-update.gemspec +1 -1
  69. metadata +3 -3
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-REMOVE" "1" "September 2024" ""
3
+ .TH "BUNDLE\-REMOVE" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-remove\fR \- Removes gems from the Gemfile
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-SHOW" "1" "September 2024" ""
3
+ .TH "BUNDLE\-SHOW" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-UPDATE" "1" "September 2024" ""
3
+ .TH "BUNDLE\-UPDATE" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-update\fR \- Update your gems to the latest available versions
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-VERSION" "1" "September 2024" ""
3
+ .TH "BUNDLE\-VERSION" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-version\fR \- Prints Bundler version information
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-VIZ" "1" "September 2024" ""
3
+ .TH "BUNDLE\-VIZ" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE" "1" "September 2024" ""
3
+ .TH "BUNDLE" "1" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\fR \- Ruby Dependency Management
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "GEMFILE" "5" "September 2024" ""
3
+ .TH "GEMFILE" "5" "October 2024" ""
4
4
  .SH "NAME"
5
5
  \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
6
6
  .SH "SYNOPSIS"
@@ -342,7 +342,26 @@ module Bundler
342
342
  # done to avoid conflicts
343
343
  path = index.plugin_path(name)
344
344
 
345
- Gem.add_to_load_path(*index.load_paths(name))
345
+ paths = index.load_paths(name)
346
+ invalid_paths = paths.reject {|p| File.directory?(p) }
347
+
348
+ if invalid_paths.any?
349
+ Bundler.ui.warn <<~MESSAGE
350
+ The following plugin paths don't exist: #{invalid_paths.join(", ")}.
351
+
352
+ This can happen if the plugin was installed with a different version of Ruby that has since been uninstalled.
353
+
354
+ If you would like to reinstall the plugin, run:
355
+
356
+ bundler plugin uninstall #{name} && bundler plugin install #{name}
357
+
358
+ Continuing without installing plugin #{name}.
359
+ MESSAGE
360
+
361
+ return
362
+ end
363
+
364
+ Gem.add_to_load_path(*paths)
346
365
 
347
366
  load path.join(PLUGIN_FILE_NAME)
348
367
 
@@ -2,23 +2,19 @@
2
2
 
3
3
  module Bundler
4
4
  class ProcessLock
5
- def self.lock(bundle_path = Bundler.bundle_path)
5
+ def self.lock(bundle_path = Bundler.bundle_path, &block)
6
6
  lock_file_path = File.join(bundle_path, "bundler.lock")
7
- has_lock = false
7
+ base_lock_file_path = lock_file_path.delete_suffix(".lock")
8
8
 
9
- File.open(lock_file_path, "w") do |f|
10
- f.flock(File::LOCK_EX)
11
- has_lock = true
12
- yield
13
- f.flock(File::LOCK_UN)
9
+ require "fileutils" if Bundler.rubygems.provides?("< 3.5.23")
10
+
11
+ begin
12
+ SharedHelpers.filesystem_access(lock_file_path, :write) do
13
+ Gem.open_file_with_lock(base_lock_file_path, &block)
14
+ end
15
+ rescue PermissionError
16
+ block.call
14
17
  end
15
- rescue Errno::EACCES, Errno::ENOLCK, Errno::ENOTSUP, Errno::EPERM, Errno::EROFS
16
- # In the case the user does not have access to
17
- # create the lock file or is using NFS where
18
- # locks are not available we skip locking.
19
- yield
20
- ensure
21
- FileUtils.rm_f(lock_file_path) if has_lock
22
18
  end
23
19
  end
24
20
  end
@@ -107,6 +107,10 @@ module Bundler
107
107
  def build_base_requirements
108
108
  base_requirements = {}
109
109
  @base.each do |ls|
110
+ if ls.source_changed? && ls.source.specs.search(ls.name).empty?
111
+ raise GemNotFound, "Could not find gem '#{ls.name}' in #{ls.source}"
112
+ end
113
+
110
114
  req = Gem::Requirement.new(ls.version)
111
115
  base_requirements[ls.name] = req
112
116
  end
@@ -452,4 +452,18 @@ module Gem
452
452
  end
453
453
  end
454
454
  end
455
+
456
+ unless Gem.rubygems_version >= Gem::Version.new("3.5.23")
457
+ class Package; end
458
+ require "rubygems/package/tar_reader"
459
+ require "rubygems/package/tar_reader/entry"
460
+
461
+ module FixFullNameEncoding
462
+ def full_name
463
+ super.force_encoding(Encoding::UTF_8)
464
+ end
465
+ end
466
+
467
+ Package::TarReader::Entry.prepend(FixFullNameEncoding)
468
+ end
455
469
  end
@@ -23,7 +23,9 @@ module Bundler
23
23
  FileUtils.mkdir_p gem_dir, mode: 0o755
24
24
  end
25
25
 
26
- extract_files
26
+ SharedHelpers.filesystem_access(gem_dir, :write) do
27
+ extract_files
28
+ end
27
29
 
28
30
  build_extensions if spec.extensions.any?
29
31
  write_build_info_file
@@ -220,9 +220,7 @@ module Bundler
220
220
  end
221
221
  end
222
222
 
223
- # Used to make bin stubs that are not created by bundler work
224
- # under bundler. The new Gem.bin_path only considers gems in
225
- # +specs+
223
+ # Used to give better error messages when activating specs outside of the current bundle
226
224
  def replace_bin_path(specs_by_name)
227
225
  gem_class = (class << Gem; self; end)
228
226
 
@@ -261,31 +259,6 @@ module Bundler
261
259
 
262
260
  spec
263
261
  end
264
-
265
- redefine_method(gem_class, :activate_bin_path) do |name, *args|
266
- exec_name = args.first
267
- return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle"
268
-
269
- # Copy of Rubygems activate_bin_path impl
270
- requirement = args.last
271
- spec = find_spec_for_exe name, exec_name, [requirement]
272
-
273
- gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name)
274
- gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name)
275
- File.exist?(gem_bin) ? gem_bin : gem_from_path_bin
276
- end
277
-
278
- redefine_method(gem_class, :bin_path) do |name, *args|
279
- exec_name = args.first
280
- return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle"
281
-
282
- spec = find_spec_for_exe(name, *args)
283
- exec_name ||= spec.default_executable
284
-
285
- gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name)
286
- gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name)
287
- File.exist?(gem_bin) ? gem_bin : gem_from_path_bin
288
- end
289
262
  end
290
263
 
291
264
  # Replace or hook into RubyGems to provide a bundlerized view
@@ -302,7 +275,7 @@ module Bundler
302
275
  Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require)
303
276
  end
304
277
  replace_gem(specs, specs_by_name)
305
- stub_rubygems(specs)
278
+ stub_rubygems(specs_by_name.values)
306
279
  replace_bin_path(specs_by_name)
307
280
 
308
281
  Gem.clear_paths
@@ -425,8 +425,12 @@ module Bundler
425
425
  Validator.validate!(raw_key, converted_value(value, raw_key), hash)
426
426
 
427
427
  return unless file
428
+
429
+ SharedHelpers.filesystem_access(file.dirname, :create) do |p|
430
+ FileUtils.mkdir_p(p)
431
+ end
432
+
428
433
  SharedHelpers.filesystem_access(file) do |p|
429
- FileUtils.mkdir_p(p.dirname)
430
434
  p.open("w") {|f| f.write(serializer_class.dump(hash)) }
431
435
  end
432
436
  end
@@ -96,14 +96,16 @@ module Bundler
96
96
  # given block
97
97
  #
98
98
  # @example
99
- # filesystem_access("vendor/cache", :write) do
99
+ # filesystem_access("vendor/cache", :create) do
100
100
  # FileUtils.mkdir_p("vendor/cache")
101
101
  # end
102
102
  #
103
103
  # @see {Bundler::PermissionError}
104
104
  def filesystem_access(path, action = :write, &block)
105
105
  yield(path.dup)
106
- rescue Errno::EACCES
106
+ rescue Errno::EACCES => e
107
+ raise unless e.message.include?(path.to_s) || action == :create
108
+
107
109
  raise PermissionError.new(path, action)
108
110
  rescue Errno::EAGAIN
109
111
  raise TemporaryResourceError.new(path, action)
@@ -116,7 +118,7 @@ module Bundler
116
118
  rescue Errno::EEXIST, Errno::ENOENT
117
119
  raise
118
120
  rescue SystemCallError => e
119
- raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.")
121
+ raise GenericSystemCallError.new(e, "There was an error #{[:create, :write].include?(action) ? "creating" : "accessing"} `#{path}`.")
120
122
  end
121
123
 
122
124
  def major_deprecation(major_version, message, removed_message: nil, print_caller_location: false)
@@ -274,15 +276,7 @@ module Bundler
274
276
  until !File.directory?(current) || current == previous
275
277
  if ENV["BUNDLER_SPEC_RUN"]
276
278
  # avoid stepping above the tmp directory when testing
277
- gemspec = if ENV["GEM_COMMAND"]
278
- # for Ruby Core
279
- "lib/bundler/bundler.gemspec"
280
- else
281
- "bundler.gemspec"
282
- end
283
-
284
- # avoid stepping above the tmp directory when testing
285
- return nil if File.file?(File.join(current, gemspec))
279
+ return nil if File.directory?(File.join(current, "tmp"))
286
280
  end
287
281
 
288
282
  names.each do |name|
@@ -314,18 +308,36 @@ module Bundler
314
308
 
315
309
  def bundle_bin_path
316
310
  # bundler exe & lib folders have same root folder, typical gem installation
317
- exe_file = File.expand_path("../../exe/bundle", __dir__)
311
+ exe_file = File.join(source_root, "exe/bundle")
318
312
 
319
313
  # for Ruby core repository testing
320
- exe_file = File.expand_path("../../libexec/bundle", __dir__) unless File.exist?(exe_file)
314
+ exe_file = File.join(source_root, "libexec/bundle") unless File.exist?(exe_file)
321
315
 
322
316
  # bundler is a default gem, exe path is separate
323
- exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
317
+ exe_file = Gem.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
324
318
 
325
319
  exe_file
326
320
  end
327
321
  public :bundle_bin_path
328
322
 
323
+ def gemspec_path
324
+ # inside a gem repository, typical gem installation
325
+ gemspec_file = File.join(source_root, "../../specifications/bundler-#{VERSION}.gemspec")
326
+
327
+ # for Ruby core repository testing
328
+ gemspec_file = File.expand_path("bundler.gemspec", __dir__) unless File.exist?(gemspec_file)
329
+
330
+ # bundler is a default gem
331
+ gemspec_file = File.join(Gem.default_specifications_dir, "bundler-#{VERSION}.gemspec") unless File.exist?(gemspec_file)
332
+
333
+ gemspec_file
334
+ end
335
+ public :gemspec_path
336
+
337
+ def source_root
338
+ File.expand_path("../..", __dir__)
339
+ end
340
+
329
341
  def set_path
330
342
  validate_bundle_path
331
343
  paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
@@ -24,9 +24,8 @@ module Bundler
24
24
  s.bindir = "exe"
25
25
  s.homepage = "https://bundler.io"
26
26
  s.summary = "The best way to manage your application's dependencies"
27
- s.executables = %w[bundle]
28
- # can't point to the actual gemspec or else the require paths will be wrong
29
- s.loaded_from = __dir__
27
+ s.executables = %w[bundle bundler]
28
+ s.loaded_from = SharedHelpers.gemspec_path
30
29
  end
31
30
  end
32
31
 
@@ -9,9 +9,6 @@ gem "rake", "~> 13.0"
9
9
  <%- if config[:ext] -%>
10
10
 
11
11
  gem "rake-compiler"
12
- <%- if config[:ext] == 'rust' -%>
13
- gem "rb_sys", "~> 0.9.63"
14
- <%- end -%>
15
12
  <%- end -%>
16
13
  <%- if config[:test] -%>
17
14
 
@@ -17,21 +17,21 @@ jobs:
17
17
  - '<%= RUBY_VERSION %>'
18
18
 
19
19
  steps:
20
- - uses: actions/checkout@v4
20
+ - uses: actions/checkout@v4
21
21
  <%- if config[:ext] == 'rust' -%>
22
- - name: Set up Ruby & Rust
23
- uses: oxidize-rb/actions/setup-ruby-and-rust@v1
24
- with:
25
- ruby-version: ${{ matrix.ruby }}
26
- bundler-cache: true
27
- cargo-cache: true
28
- rubygems: '<%= ::Gem.rubygems_version %>'
22
+ - name: Set up Ruby & Rust
23
+ uses: oxidize-rb/actions/setup-ruby-and-rust@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+ bundler-cache: true
27
+ cargo-cache: true
28
+ rubygems: '<%= ::Gem.rubygems_version %>'
29
29
  <%- else -%>
30
- - name: Set up Ruby
31
- uses: ruby/setup-ruby@v1
32
- with:
33
- ruby-version: ${{ matrix.ruby }}
34
- bundler-cache: true
30
+ - name: Set up Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby }}
34
+ bundler-cache: true
35
35
  <%- end -%>
36
- - name: Run the default task
37
- run: bundle exec rake
36
+ - name: Run the default task
37
+ run: bundle exec rake
@@ -37,15 +37,15 @@ Gem::Specification.new do |spec|
37
37
  spec.bindir = "exe"
38
38
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
39
39
  spec.require_paths = ["lib"]
40
- <%- if config[:ext] == 'c' -%>
40
+ <%- if config[:ext] == 'c' || config[:ext] == 'rust' -%>
41
41
  spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"]
42
42
  <%- end -%>
43
- <%- if config[:ext] == 'rust' -%>
44
- spec.extensions = ["ext/<%= config[:underscored_name] %>/Cargo.toml"]
45
- <%- end -%>
46
43
 
47
44
  # Uncomment to register a new dependency of your gem
48
45
  # spec.add_dependency "example-gem", "~> 1.0"
46
+ <%- if config[:ext] == 'rust' -%>
47
+ spec.add_dependency "rb_sys", "~> 0.9.91"
48
+ <%- end -%>
49
49
 
50
50
  # For more information and examples about making a new gem, check out our
51
51
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.5.22".freeze
4
+ VERSION = "2.5.23".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -492,7 +492,7 @@ module Bundler
492
492
  end
493
493
 
494
494
  def mkdir_p(path)
495
- SharedHelpers.filesystem_access(path, :write) do |p|
495
+ SharedHelpers.filesystem_access(path, :create) do |p|
496
496
  FileUtils.mkdir_p(p)
497
497
  end
498
498
  end
@@ -365,9 +365,15 @@ By default, this RubyGems will install gem as:
365
365
  def install_default_bundler_gem(bin_dir)
366
366
  current_default_spec = Gem::Specification.default_stubs.find {|s| s.name == "bundler" }
367
367
  specs_dir = if current_default_spec && default_dir == Gem.default_dir
368
+ all_specs_current_version = Gem::Specification.stubs.select {|s| s.full_name == current_default_spec.full_name }
369
+
368
370
  Gem::Specification.remove_spec current_default_spec
369
371
  loaded_from = current_default_spec.loaded_from
370
372
  File.delete(loaded_from)
373
+
374
+ # Remove previous default gem executables if they were not shadowed by a regular gem
375
+ FileUtils.rm_rf current_default_spec.full_gem_path if all_specs_current_version.size == 1
376
+
371
377
  File.dirname(loaded_from)
372
378
  else
373
379
  target_specs_dir = File.join(default_dir, "specifications", "default")
@@ -29,6 +29,7 @@ class Gem::GemRunner
29
29
  # Run the gem command with the following arguments.
30
30
 
31
31
  def run(args)
32
+ validate_encoding args
32
33
  build_args = extract_build_args args
33
34
 
34
35
  do_configuration args
@@ -72,6 +73,14 @@ class Gem::GemRunner
72
73
 
73
74
  private
74
75
 
76
+ def validate_encoding(args)
77
+ invalid_arg = args.find {|arg| !arg.valid_encoding? }
78
+
79
+ if invalid_arg
80
+ raise Gem::OptionParser::InvalidArgument.new("'#{invalid_arg.scrub}' has invalid encoding")
81
+ end
82
+ end
83
+
75
84
  def do_configuration(args)
76
85
  Gem.configuration = @config_file_class.new(args)
77
86
  Gem.use_paths Gem.configuration[:gemhome], Gem.configuration[:gempath]
@@ -62,6 +62,10 @@ module Gem::GemcutterUtilities
62
62
  options[:otp] || ENV["GEM_HOST_OTP_CODE"]
63
63
  end
64
64
 
65
+ def webauthn_enabled?
66
+ options[:webauthn]
67
+ end
68
+
65
69
  ##
66
70
  # The host to connect to either from the RUBYGEMS_HOST environment variable
67
71
  # or from the user's configuration
@@ -136,7 +140,6 @@ module Gem::GemcutterUtilities
136
140
  response = rubygems_api_request(:put, "api/v1/api_key",
137
141
  sign_in_host, scope: scope) do |request|
138
142
  request.basic_auth identifier, password
139
- request["OTP"] = otp if otp
140
143
  request.body = Gem::URI.encode_www_form({ api_key: api_key }.merge(update_scope_params))
141
144
  end
142
145
 
@@ -176,7 +179,6 @@ module Gem::GemcutterUtilities
176
179
  response = rubygems_api_request(:post, "api/v1/api_key",
177
180
  sign_in_host, credentials: credentials, scope: scope) do |request|
178
181
  request.basic_auth identifier, password
179
- request["OTP"] = otp if otp
180
182
  request.body = Gem::URI.encode_www_form({ name: key_name }.merge(all_params))
181
183
  end
182
184
 
@@ -251,6 +253,8 @@ module Gem::GemcutterUtilities
251
253
  req["OTP"] = otp if otp
252
254
  block.call(req)
253
255
  end
256
+ ensure
257
+ options[:otp] = nil if webauthn_enabled?
254
258
  end
255
259
 
256
260
  def fetch_otp(credentials)
@@ -271,6 +275,8 @@ module Gem::GemcutterUtilities
271
275
  terminate_interaction(1)
272
276
  end
273
277
 
278
+ options[:webauthn] = true
279
+
274
280
  say "You are verified with a security device. You may close the browser window."
275
281
  otp_thread[:otp]
276
282
  else
@@ -998,18 +998,17 @@ TEXT
998
998
 
999
999
  def bash_prolog_script
1000
1000
  if load_relative_enabled?
1001
- script = +<<~EOS
1002
- bindir="${0%/*}"
1003
- EOS
1004
-
1005
- script << %(exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n)
1006
-
1007
1001
  <<~EOS
1008
1002
  #!/bin/sh
1009
1003
  # -*- ruby -*-
1010
1004
  _=_\\
1011
1005
  =begin
1012
- #{script.chomp}
1006
+ bindir="${0%/*}"
1007
+ ruby="$bindir/#{ruby_install_name}"
1008
+ if [ ! -f "$ruby" ]; then
1009
+ ruby="#{ruby_install_name}"
1010
+ fi
1011
+ exec "$ruby" "-x" "$0" "$@"
1013
1012
  =end
1014
1013
  EOS
1015
1014
  else
@@ -228,6 +228,17 @@ class Gem::Package::TarHeader
228
228
  @checksum = oct calculate_checksum(header), 6
229
229
  end
230
230
 
231
+ ##
232
+ # Header's full name, including prefix
233
+
234
+ def full_name
235
+ if prefix != ""
236
+ File.join prefix, name
237
+ else
238
+ name
239
+ end
240
+ end
241
+
231
242
  private
232
243
 
233
244
  def calculate_checksum(header)
@@ -87,11 +87,7 @@ class Gem::Package::TarReader::Entry
87
87
  # Full name of the tar entry
88
88
 
89
89
  def full_name
90
- if @header.prefix != ""
91
- File.join @header.prefix, @header.name
92
- else
93
- @header.name
94
- end
90
+ @header.full_name.force_encoding(Encoding::UTF_8)
95
91
  rescue ArgumentError => e
96
92
  raise unless e.message == "string contains null byte"
97
93
  raise Gem::Package::TarInvalidError,
@@ -170,17 +170,45 @@ class Gem::SpecFetcher
170
170
  # alternative gem names.
171
171
 
172
172
  def suggest_gems_from_name(gem_name, type = :latest, num_results = 5)
173
- gem_name = gem_name.downcase.tr("_-", "")
174
- max = gem_name.size / 2
175
- names = available_specs(type).first.values.flatten(1)
173
+ gem_name = gem_name.downcase.tr("_-", "")
176
174
 
177
- matches = names.map do |n|
175
+ # All results for 3-character-or-shorter (minus hyphens/underscores) gem
176
+ # names get rejected, so we just return an empty array immediately instead.
177
+ return [] if gem_name.length <= 3
178
+
179
+ max = gem_name.size / 2
180
+ names = available_specs(type).first.values.flatten(1)
181
+
182
+ min_length = gem_name.length - max
183
+ max_length = gem_name.length + max
184
+
185
+ matches = names.filter_map do |n|
186
+ len = n.name.length
187
+ # If the length is min_length or shorter, we've done `max` deletions.
188
+ # If the length is max_length or longer, we've done `max` insertions.
189
+ # These would both be rejected later, so we skip early for performance.
190
+ next if len <= min_length || len >= max_length
191
+
192
+ # If the gem doesn't support the current platform, bail early.
178
193
  next unless n.match_platform?
179
- distance = levenshtein_distance gem_name, n.name.downcase.tr("_-", "")
194
+
195
+ # The candidate name, normalized the same as gem_name.
196
+ normalized_name = n.name.downcase
197
+ normalized_name.tr!("_-", "")
198
+
199
+ # If we found an exact match (after stripping underscores and hyphens),
200
+ # that's our most likely candidate.
201
+ # Return it immediately, and skip the rest of the loop.
202
+ return [n.name] if normalized_name == gem_name
203
+
204
+ distance = levenshtein_distance gem_name, normalized_name
205
+
206
+ # Skip current candidate, if the edit distance is greater than allowed.
180
207
  next if distance >= max
181
- return [n.name] if distance == 0
208
+
209
+ # If all else fails, return the name and the calculated distance.
182
210
  [n.name, distance]
183
- end.compact
211
+ end
184
212
 
185
213
  matches = if matches.empty? && type != :prerelease
186
214
  suggest_gems_from_name gem_name, :prerelease
@@ -391,7 +391,7 @@ class Gem::Specification < Gem::BasicSpecification
391
391
  # "homepage_uri" => "https://bestgemever.example.io",
392
392
  # "mailing_list_uri" => "https://groups.example.com/bestgemever",
393
393
  # "source_code_uri" => "https://example.com/user/bestgemever",
394
- # "wiki_uri" => "https://example.com/user/bestgemever/wiki"
394
+ # "wiki_uri" => "https://example.com/user/bestgemever/wiki",
395
395
  # "funding_uri" => "https://example.com/donate"
396
396
  # }
397
397
  #
data/lib/rubygems.rb CHANGED
@@ -9,7 +9,7 @@
9
9
  require "rbconfig"
10
10
 
11
11
  module Gem
12
- VERSION = "3.5.22"
12
+ VERSION = "3.5.23"
13
13
  end
14
14
 
15
15
  # Must be first since it unloads the prelude from 1.9.2
@@ -781,6 +781,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
781
781
  file_lock = "#{path}.lock"
782
782
  open_file_with_flock(file_lock, &block)
783
783
  ensure
784
+ require "fileutils"
784
785
  FileUtils.rm_f file_lock
785
786
  end
786
787
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rubygems-update"
5
- s.version = "3.5.22"
5
+ s.version = "3.5.23"
6
6
  s.authors = ["Jim Weirich", "Chad Fowler", "Eric Hodel", "Luis Lavena", "Aaron Patterson", "Samuel Giddins", "André Arko", "Evan Phoenix", "Hiroshi SHIBATA"]
7
7
  s.email = ["", "", "drbrain@segment7.net", "luislavena@gmail.com", "aaron@tenderlovemaking.com", "segiddins@segiddins.me", "andre@arko.net", "evan@phx.io", "hsbt@ruby-lang.org"]
8
8