aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rubygems
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2021-01-04 10:09:05 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2021-01-04 13:14:43 +0900
commit5537adf719a37a30b17d39111cc03700f353aa2d (patch)
tree7523de9950b8a0118143f4ee0029aee17d043e04 /lib/rubygems
parent35c3a24c8cbcccff1108079360e2063fc354b4bd (diff)
downloadruby-5537adf719a37a30b17d39111cc03700f353aa2d.tar.gz
Track RubyGems master(3.3.0.dev) branch at 55634a8af18a52df86c4275d70fa1179118bcc20
Diffstat (limited to 'lib/rubygems')
-rw-r--r--lib/rubygems/command_manager.rb2
-rw-r--r--lib/rubygems/commands/install_command.rb7
-rw-r--r--lib/rubygems/commands/setup_command.rb78
-rw-r--r--lib/rubygems/commands/update_command.rb13
-rw-r--r--lib/rubygems/exceptions.rb25
-rw-r--r--lib/rubygems/ext/builder.rb14
-rw-r--r--lib/rubygems/ext/cmake_builder.rb3
-rw-r--r--lib/rubygems/ext/configure_builder.rb3
-rw-r--r--lib/rubygems/install_update_options.rb13
-rw-r--r--lib/rubygems/remote_fetcher.rb4
-rw-r--r--lib/rubygems/resolver/best_set.rb2
-rw-r--r--lib/rubygems/resolver/index_specification.rb5
-rw-r--r--lib/rubygems/source.rb4
-rw-r--r--lib/rubygems/test_case.rb22
-rw-r--r--lib/rubygems/text.rb41
-rw-r--r--lib/rubygems/unknown_command_spell_checker.rb21
16 files changed, 148 insertions, 109 deletions
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 97e52544ca..2409550882 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -188,7 +188,7 @@ class Gem::CommandManager
raise Gem::CommandLineError,
"Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
elsif possibilities.empty?
- raise Gem::CommandLineError, "Unknown command #{cmd_name}"
+ raise Gem::UnknownCommandError.new(cmd_name)
end
self[possibilities.first]
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 70825b88fd..a528ea087e 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -27,6 +27,8 @@ class Gem::Commands::InstallCommand < Gem::Command
:without_groups => [],
})
+ defaults.merge!(install_update_options)
+
super 'install', 'Install a gem into the local repository', defaults
add_install_update_options
@@ -43,8 +45,9 @@ class Gem::Commands::InstallCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--both --version '#{Gem::Requirement.default}' --document --no-force\n" +
- "--install-dir #{Gem.dir} --lock"
+ "--both --version '#{Gem::Requirement.default}' --no-force\n" +
+ "--install-dir #{Gem.dir} --lock\n" +
+ install_update_defaults_str
end
def description # :nodoc:
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 22b1371a1f..47e215c149 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -6,8 +6,8 @@ require 'rubygems/command'
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
- HISTORY_HEADER = /^===\s*[\d.a-zA-Z]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
- VERSION_MATCHER = /^===\s*([\d.a-zA-Z]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
+ HISTORY_HEADER = /^#\s*[\d.a-zA-Z]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
+ VERSION_MATCHER = /^#\s*([\d.a-zA-Z]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
ENV_PATHS = %w[/usr/bin/env /bin/env].freeze
@@ -167,19 +167,18 @@ By default, this RubyGems will install gem as:
extend MakeDirs
lib_dir, bin_dir = make_destination_dirs install_destdir
- man_dir = make_man_dir install_destdir
+ man_dir = generate_default_man_dir install_destdir
install_lib lib_dir
- install_man man_dir
-
install_executables bin_dir
remove_old_bin_files bin_dir
remove_old_lib_files lib_dir
- remove_old_man_files man_dir
+ # Can be removed one we drop support for bundler 2.2.3 (the last version installing man files to man_dir)
+ remove_old_man_files man_dir if man_dir && File.exist?(man_dir)
install_default_bundler_gem bin_dir
@@ -330,21 +329,6 @@ By default, this RubyGems will install gem as:
end
end
- def install_man(man_dir)
- mans = { 'Bundler' => 'bundler/man' }
- mans.each do |tool, path|
- say "Installing #{tool} manpages" if @verbose
-
- bundler_man1_files = bundler_man1_files_in(path)
- bundler_man5_files = bundler_man5_files_in(path)
-
- Dir.chdir path do
- install_file_list(bundler_man1_files, "#{man_dir}/man1")
- install_file_list(bundler_man5_files, "#{man_dir}/man5")
- end
- end
- end
-
def install_rdoc
gem_doc_dir = File.join Gem.dir, 'doc'
rubygems_name = "rubygems-#{Gem::VERSION}"
@@ -391,9 +375,7 @@ By default, this RubyGems will install gem as:
specs_dir = File.join(options[:destdir], specs_dir) unless Gem.win_platform?
mkdir_p specs_dir, :mode => 0755
- bundler_spec = Gem::Specification.load("bundler/bundler.gemspec")
- bundler_spec.files = Dir.chdir("bundler") { Dir["{*.md,{lib,exe,man}/**/*}"] }
- bundler_spec.executables -= %w[bundler bundle_ruby]
+ bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
# Remove bundler-*.gemspec in default specification directory.
Dir.entries(specs_dir).
@@ -455,19 +437,12 @@ By default, this RubyGems will install gem as:
return lib_dir, bin_dir
end
- def make_man_dir(install_destdir)
- man_dir = generate_default_man_dir(install_destdir)
-
- mkdir_p man_dir, :mode => 0755
-
- return man_dir
- end
-
def generate_default_man_dir(install_destdir)
prefix = options[:prefix]
if prefix.empty?
man_dir = RbConfig::CONFIG['mandir']
+ return unless man_dir
else
man_dir = File.join prefix, 'man'
end
@@ -518,20 +493,6 @@ By default, this RubyGems will install gem as:
end
end
- # for installation of bundler as default gems
- def bundler_man1_files_in(dir)
- Dir.chdir dir do
- Dir['bundle*.1']
- end
- end
-
- # for installation of bundler as default gems
- def bundler_man5_files_in(dir)
- Dir.chdir dir do
- Dir['gemfile.5']
- end
- end
-
def remove_old_bin_files(bin_dir)
old_bin_files = {
'gem_mirror' => 'gem mirror',
@@ -585,33 +546,26 @@ abort "#{deprecation_message}"
end
end
- def remove_old_man_files(man_dir)
- man_dirs = { man_dir => "bundler/man" }
- man_dirs.each do |old_man_dir, new_man_dir|
- man1_files = bundler_man1_files_in(new_man_dir)
-
- old_man1_dir = "#{old_man_dir}/man1"
- old_man1_files = bundler_man1_files_in(old_man1_dir)
- old_man1_files += Dir.chdir(old_man1_dir) { Dir["bundle*.1.{txt,ronn}"] }
+ def remove_old_man_files(old_man_dir)
+ old_man1_dir = "#{old_man_dir}/man1"
- man1_to_remove = old_man1_files - man1_files
+ if File.exist?(old_man1_dir)
+ man1_to_remove = Dir.chdir(old_man1_dir) { Dir["bundle*.1{,.txt,.ronn}"] }
remove_file_list(man1_to_remove, old_man1_dir)
+ end
- man5_files = bundler_man5_files_in(new_man_dir)
-
- old_man5_dir = "#{old_man_dir}/man5"
- old_man5_files = bundler_man5_files_in(old_man5_dir)
- old_man5_files += Dir.chdir(old_man5_dir) { Dir["gemfile.5.{txt,ronn}"] }
+ old_man5_dir = "#{old_man_dir}/man5"
- man5_to_remove = old_man5_files - man5_files
+ if File.exist?(old_man5_dir)
+ man5_to_remove = Dir.chdir(old_man5_dir) { Dir["gemfile.5{,.txt,.ronn}"] }
remove_file_list(man5_to_remove, old_man5_dir)
end
end
def show_release_notes
- release_notes = File.join Dir.pwd, 'History.txt'
+ release_notes = File.join Dir.pwd, 'CHANGELOG.md'
release_notes =
if File.exist? release_notes
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index fcc52c293e..41770d9805 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -19,9 +19,13 @@ class Gem::Commands::UpdateCommand < Gem::Command
attr_reader :updated # :nodoc:
def initialize
- super 'update', 'Update installed gems to the latest version',
- :document => %w[rdoc ri],
- :force => false
+ options = {
+ :force => false,
+ }
+
+ options.merge!(install_update_options)
+
+ super 'update', 'Update installed gems to the latest version', options
add_install_update_options
@@ -51,7 +55,8 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--document --no-force --install-dir #{Gem.dir}"
+ "--no-force --install-dir #{Gem.dir}\n" +
+ install_update_defaults_str
end
def description # :nodoc:
diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb
index 804863f693..55755ddfba 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'rubygems/deprecate'
+require 'rubygems/unknown_command_spell_checker'
##
# Base exception class for RubyGems. All exception raised by RubyGems are a
@@ -9,6 +10,30 @@ class Gem::Exception < RuntimeError; end
class Gem::CommandLineError < Gem::Exception; end
+class Gem::UnknownCommandError < Gem::Exception
+ attr_reader :unknown_command
+
+ def initialize(unknown_command)
+ self.class.attach_correctable
+
+ @unknown_command = unknown_command
+ super("Unknown command #{unknown_command}")
+ end
+
+ def self.attach_correctable
+ return if defined?(@attached)
+
+ if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
+ DidYouMean::SPELL_CHECKERS['Gem::UnknownCommandError'] =
+ Gem::UnknownCommandSpellChecker
+
+ prepend DidYouMean::Correctable
+ end
+
+ @attached = true
+ end
+end
+
class Gem::DependencyError < Gem::Exception; end
class Gem::DependencyRemovalException < Gem::Exception; end
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index f6de6a50d7..e089b3d57a 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -29,7 +29,7 @@ class Gem::Ext::Builder
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
end
- destdir = '"DESTDIR=%s"' % ENV['DESTDIR']
+ destdir = 'DESTDIR=%s' % ENV['DESTDIR']
['clean', '', 'install'].each do |target|
# Pass DESTDIR via command line to override what's in MAKEFLAGS
@@ -37,7 +37,7 @@ class Gem::Ext::Builder
make_program,
destdir,
target,
- ].join(' ').rstrip
+ ].reject(&:empty?)
begin
run(cmd, results, "make #{target}".rstrip, make_dir)
rescue Gem::InstallError
@@ -56,19 +56,21 @@ class Gem::Ext::Builder
p(command)
end
results << "current directory: #{dir}"
- results << (command.respond_to?(:shelljoin) ? command.shelljoin : command)
+ results << command.shelljoin
require "open3"
# Set $SOURCE_DATE_EPOCH for the subprocess.
env = {'SOURCE_DATE_EPOCH' => Gem.source_date_epoch_string}
- output, status = Open3.capture2e(env, *command, :chdir => dir)
+ output, status = begin
+ Open3.capture2e(env, *command, :chdir => dir)
+ rescue => error
+ raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}"
+ end
if verbose
puts output
else
results << output
end
- rescue => error
- raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}"
ensure
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
end
diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb
index 2efec91f15..269e876cfa 100644
--- a/lib/rubygems/ext/cmake_builder.rb
+++ b/lib/rubygems/ext/cmake_builder.rb
@@ -4,8 +4,7 @@ require_relative '../command'
class Gem::Ext::CmakeBuilder < Gem::Ext::Builder
def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd)
unless File.exist?(File.join(cmake_dir, 'Makefile'))
- cmd = "cmake . -DCMAKE_INSTALL_PREFIX=#{dest_path}"
- cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
+ cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args]
run cmd, results, class_name, cmake_dir
end
diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb
index 36a758989b..eb2f9fce61 100644
--- a/lib/rubygems/ext/configure_builder.rb
+++ b/lib/rubygems/ext/configure_builder.rb
@@ -8,8 +8,7 @@
class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd)
unless File.exist?(File.join(configure_dir, 'Makefile'))
- cmd = "sh ./configure --prefix=#{dest_path}"
- cmd << " #{args.join ' '}" unless args.empty?
+ cmd = ["sh", "./configure", "--prefix=#{dest_path}", *args]
run cmd, results, class_name, configure_dir
end
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index ef1ad1edcb..54a3950b64 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -181,10 +181,19 @@ module Gem::InstallUpdateOptions
end
##
- # Default options for the gem install command.
+ # Default options for the gem install and update commands.
+
+ def install_update_options
+ {
+ :document => %w[ri],
+ }
+ end
+
+ ##
+ # Default description for the gem install and update commands.
def install_update_defaults_str
- '--document=rdoc,ri --wrappers'
+ '--document=ri'
end
end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 285c80a95f..53e840978c 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -26,13 +26,15 @@ class Gem::RemoteFetcher
##
# The URI which was being accessed when the exception happened.
- attr_accessor :uri
+ attr_accessor :uri, :original_uri
def initialize(message, uri)
super message
uri = parse_uri(uri)
+ @original_uri = uri.dup
+
uri.password = 'REDACTED' if uri.respond_to?(:password) && uri.password
@uri = uri.to_s
diff --git a/lib/rubygems/resolver/best_set.rb b/lib/rubygems/resolver/best_set.rb
index b6a46a9403..300ea8015c 100644
--- a/lib/rubygems/resolver/best_set.rb
+++ b/lib/rubygems/resolver/best_set.rb
@@ -58,7 +58,7 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
# The calling method must retry the exception to repeat the lookup.
def replace_failed_api_set(error) # :nodoc:
- uri = error.uri
+ uri = error.original_uri
uri = URI uri unless URI === uri
uri = uri + "."
diff --git a/lib/rubygems/resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb
index 45ff130a14..2aa6b419ba 100644
--- a/lib/rubygems/resolver/index_specification.rb
+++ b/lib/rubygems/resolver/index_specification.rb
@@ -43,9 +43,12 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
##
# The required_rubygems_version constraint for this specification
#
+ # A fallback is included because the original version of the specification
+ # API didn't include that field, so some marshalled specs in the index have it
+ # set to +nil+.
def required_rubygems_version
- spec.required_rubygems_version
+ spec.required_rubygems_version || Gem::Requirement.default
end
def ==(other)
diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb
index 4ae84cf532..37e03cdfae 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -35,6 +35,7 @@ class Gem::Source
end
@uri = uri
+ @update_cache = nil
end
##
@@ -118,7 +119,8 @@ class Gem::Source
# Returns true when it is possible and safe to update the cache directory.
def update_cache?
- @update_cache ||=
+ return @update_cache unless @update_cache.nil?
+ @update_cache =
begin
File.stat(Gem.user_home).uid == Process.uid
rescue Errno::ENOENT
diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb
index a8261ef5c2..83a3c446a7 100644
--- a/lib/rubygems/test_case.rb
+++ b/lib/rubygems/test_case.rb
@@ -26,7 +26,20 @@ begin
rescue LoadError
end
-require 'bundler'
+if File.exist?(bundler_gemspec)
+ require_relative '../../bundler/lib/bundler'
+else
+ require 'bundler'
+end
+
+# Enable server plugin needed for bisection
+if ENV["RG_BISECT_SERVER_PLUGIN"]
+ require ENV["RG_BISECT_SERVER_PLUGIN"]
+
+ Minitest.extensions << "server"
+end
+
+ENV["MT_NO_PLUGINS"] = "true"
require 'minitest/autorun'
@@ -250,16 +263,16 @@ class Gem::TestCase < Minitest::Test
def assert_contains_make_command(target, output, msg = nil)
if output.match(/\n/)
msg = message(msg) do
- 'Expected output containing make command "%s": %s' % [
+ "Expected output containing make command \"%s\", but was \n\nBEGIN_OF_OUTPUT\n%sEND_OF_OUTPUT" % [
('%s %s' % [make_command, target]).rstrip,
- output.inspect,
+ output,
]
end
else
msg = message(msg) do
'Expected make command "%s": %s' % [
('%s %s' % [make_command, target]).rstrip,
- output.inspect,
+ output,
]
end
end
@@ -298,6 +311,7 @@ class Gem::TestCase < Minitest::Test
ENV['XDG_CONFIG_HOME'] = nil
ENV['XDG_DATA_HOME'] = nil
ENV['SOURCE_DATE_EPOCH'] = nil
+ ENV['BUNDLER_VERSION'] = nil
ENV["TMPDIR"] = @tmp
@current_dir = Dir.pwd
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index 667811192d..acf25a0bcd 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -49,37 +49,38 @@ module Gem::Text
end
end
- # This code is based directly on the Text gem implementation
# Returns a value representing the "cost" of transforming str1 into str2
+ # Vendored version of DidYouMean::Levenshtein.distance from the ruby/did_you_mean gem @ 1.4.0
+ # https://git.io/JJgZI
def levenshtein_distance(str1, str2)
- s = str1
- t = str2
- n = s.length
- m = t.length
-
- return m if (0 == n)
- return n if (0 == m)
+ n = str1.length
+ m = str2.length
+ return m if n.zero?
+ return n if m.zero?
d = (0..m).to_a
x = nil
- str1.each_char.each_with_index do |char1,i|
- e = i + 1
+ # to avoid duplicating an enumerable object, create it outside of the loop
+ str2_codepoints = str2.codepoints
- str2.each_char.each_with_index do |char2,j|
- cost = (char1 == char2) ? 0 : 1
+ str1.each_codepoint.with_index(1) do |char1, i|
+ j = 0
+ while j < m
+ cost = (char1 == str2_codepoints[j]) ? 0 : 1
x = min3(
- d[j + 1] + 1, # insertion
- e + 1, # deletion
- d[j] + cost # substitution
- )
- d[j] = e
- e = x
+ d[j + 1] + 1, # insertion
+ i + 1, # deletion
+ d[j] + cost # substitution
+ )
+ d[j] = i
+ i = x
+
+ j += 1
end
-
d[m] = x
end
- return x
+ x
end
end
diff --git a/lib/rubygems/unknown_command_spell_checker.rb b/lib/rubygems/unknown_command_spell_checker.rb
new file mode 100644
index 0000000000..ee5c2fbe04
--- /dev/null
+++ b/lib/rubygems/unknown_command_spell_checker.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class Gem::UnknownCommandSpellChecker
+ attr_reader :error
+
+ def initialize(error)
+ @error = error
+ end
+
+ def corrections
+ @corrections ||=
+ spell_checker.correct(error.unknown_command).map(&:inspect)
+ end
+
+ private
+
+ def spell_checker
+ dictionary = Gem::CommandManager.instance.command_names
+ DidYouMean::SpellChecker.new(dictionary: dictionary)
+ end
+end