diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-01-04 10:09:05 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-01-04 13:14:43 +0900 |
commit | 5537adf719a37a30b17d39111cc03700f353aa2d (patch) | |
tree | 7523de9950b8a0118143f4ee0029aee17d043e04 /lib/rubygems | |
parent | 35c3a24c8cbcccff1108079360e2063fc354b4bd (diff) | |
download | ruby-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.rb | 2 | ||||
-rw-r--r-- | lib/rubygems/commands/install_command.rb | 7 | ||||
-rw-r--r-- | lib/rubygems/commands/setup_command.rb | 78 | ||||
-rw-r--r-- | lib/rubygems/commands/update_command.rb | 13 | ||||
-rw-r--r-- | lib/rubygems/exceptions.rb | 25 | ||||
-rw-r--r-- | lib/rubygems/ext/builder.rb | 14 | ||||
-rw-r--r-- | lib/rubygems/ext/cmake_builder.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/ext/configure_builder.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/install_update_options.rb | 13 | ||||
-rw-r--r-- | lib/rubygems/remote_fetcher.rb | 4 | ||||
-rw-r--r-- | lib/rubygems/resolver/best_set.rb | 2 | ||||
-rw-r--r-- | lib/rubygems/resolver/index_specification.rb | 5 | ||||
-rw-r--r-- | lib/rubygems/source.rb | 4 | ||||
-rw-r--r-- | lib/rubygems/test_case.rb | 22 | ||||
-rw-r--r-- | lib/rubygems/text.rb | 41 | ||||
-rw-r--r-- | lib/rubygems/unknown_command_spell_checker.rb | 21 |
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 |