From 600a715c9bde99fe2e9a669465d78833445273e8 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 1 Feb 2020 11:14:04 +0900 Subject: Merge the current master branch of rubygems/rubygems. Just started to develop RubyGems 3.2.0. --- lib/rubygems.rb | 156 ++-- lib/rubygems/basic_specification.rb | 8 +- lib/rubygems/command.rb | 6 +- lib/rubygems/command_manager.rb | 1 + lib/rubygems/commands/help_command.rb | 2 +- lib/rubygems/commands/info_command.rb | 13 +- lib/rubygems/commands/install_command.rb | 6 +- lib/rubygems/commands/list_command.rb | 15 +- lib/rubygems/commands/pristine_command.rb | 12 +- lib/rubygems/commands/search_command.rb | 14 +- lib/rubygems/commands/setup_command.rb | 19 +- lib/rubygems/commands/sources_command.rb | 6 +- lib/rubygems/commands/update_command.rb | 37 +- lib/rubygems/deprecate.rb | 18 +- lib/rubygems/doctor.rb | 2 + lib/rubygems/exceptions.rb | 13 +- lib/rubygems/gem_runner.rb | 10 +- lib/rubygems/installer.rb | 38 +- lib/rubygems/installer_test_case.rb | 4 +- lib/rubygems/installer_uninstaller_utils.rb | 24 + lib/rubygems/package.rb | 3 +- lib/rubygems/query_utils.rb | 362 +++++++++ lib/rubygems/remote_fetcher.rb | 14 - lib/rubygems/request_set/gem_dependency_api.rb | 2 +- lib/rubygems/resolver/api_set.rb | 2 +- lib/rubygems/resolver/api_specification.rb | 2 +- lib/rubygems/security.rb | 8 +- lib/rubygems/security/signer.rb | 2 +- lib/rubygems/server.rb | 2 +- lib/rubygems/specification.rb | 33 +- lib/rubygems/specification_policy.rb | 3 +- lib/rubygems/test_case.rb | 58 +- lib/rubygems/uninstaller.rb | 36 +- lib/rubygems/user_interaction.rb | 8 - lib/rubygems/version.rb | 2 +- test/rubygems/test_deprecate.rb | 18 + test/rubygems/test_gem.rb | 79 +- test/rubygems/test_gem_command_manager.rb | 41 +- test/rubygems/test_gem_commands_build_command.rb | 2 +- .../rubygems/test_gem_commands_pristine_command.rb | 37 +- test/rubygems/test_gem_commands_query_command.rb | 857 --------------------- test/rubygems/test_gem_commands_setup_command.rb | 37 + test/rubygems/test_gem_commands_sources_command.rb | 40 +- test/rubygems/test_gem_commands_update_command.rb | 54 +- test/rubygems/test_gem_config_file.rb | 7 - test/rubygems/test_gem_dependency_installer.rb | 2 +- test/rubygems/test_gem_doctor.rb | 28 + test/rubygems/test_gem_gem_runner.rb | 30 + test/rubygems/test_gem_installer.rb | 74 +- test/rubygems/test_gem_remote_fetcher.rb | 25 +- test/rubygems/test_gem_request_set.rb | 52 ++ test/rubygems/test_gem_specification.rb | 13 +- test/rubygems/test_gem_uninstaller.rb | 104 +++ test/rubygems/test_gem_version.rb | 2 +- 54 files changed, 1236 insertions(+), 1207 deletions(-) create mode 100644 lib/rubygems/installer_uninstaller_utils.rb create mode 100644 lib/rubygems/query_utils.rb delete mode 100644 test/rubygems/test_gem_commands_query_command.rb diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 57cb70cc2b..f7380c7154 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -9,7 +9,7 @@ require 'rbconfig' module Gem - VERSION = "3.1.2".freeze + VERSION = "3.2.0.pre1".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -26,27 +26,27 @@ require 'rubygems/errors' # For user documentation, see: # # * gem help and gem help [command] -# * {RubyGems User Guide}[http://guides.rubygems.org/] -# * {Frequently Asked Questions}[http://guides.rubygems.org/faqs] +# * {RubyGems User Guide}[https://guides.rubygems.org/] +# * {Frequently Asked Questions}[https://guides.rubygems.org/faqs] # # For gem developer documentation see: # -# * {Creating Gems}[http://guides.rubygems.org/make-your-own-gem] +# * {Creating Gems}[https://guides.rubygems.org/make-your-own-gem] # * Gem::Specification # * Gem::Version for version dependency notes # # Further RubyGems documentation can be found at: # -# * {RubyGems Guides}[http://guides.rubygems.org] -# * {RubyGems API}[http://www.rubydoc.info/github/rubygems/rubygems] (also available from +# * {RubyGems Guides}[https://guides.rubygems.org] +# * {RubyGems API}[https://www.rubydoc.info/github/rubygems/rubygems] (also available from # gem server) # # == RubyGems Plugins # -# As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or +# RubyGems will load plugins in the latest version of each installed gem or # $LOAD_PATH. Plugins must be named 'rubygems_plugin' (.rb, .so, etc) and -# placed at the root of your gem's #require_path. Plugins are discovered via -# Gem::find_files and then loaded. +# placed at the root of your gem's #require_path. Plugins are installed at a +# special location and loaded on boot. # # For an example plugin, see the {Graph gem}[https://github.com/seattlerb/graph] # which adds a `gem graph` command. @@ -148,6 +148,7 @@ module Gem doc extensions gems + plugins specifications ].freeze @@ -409,8 +410,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} ## # The path where gems are to be installed. - #-- - # FIXME deprecate these once everything else has been done -ebh def self.dir paths.home @@ -424,6 +423,10 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} paths.spec_cache_dir end + def self.plugins_dir + File.join(dir, "plugins") + end + ## # Quietly ensure the Gem directory +dir+ contains all the proper # subdirectories. If we can't create a directory due to a permission @@ -573,50 +576,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} private_class_method :find_home - # TODO: remove in RubyGems 4.0 - - ## - # Zlib::GzipReader wrapper that unzips +data+. - - def self.gunzip(data) - Gem::Util.gunzip data - end - - class << self - - extend Gem::Deprecate - deprecate :gunzip, "Gem::Util.gunzip", 2018, 12 - - end - - ## - # Zlib::GzipWriter wrapper that zips +data+. - - def self.gzip(data) - Gem::Util.gzip data - end - - class << self - - extend Gem::Deprecate - deprecate :gzip, "Gem::Util.gzip", 2018, 12 - - end - - ## - # A Zlib::Inflate#inflate wrapper - - def self.inflate(data) - Gem::Util.inflate data - end - - class << self - - extend Gem::Deprecate - deprecate :inflate, "Gem::Util.inflate", 2018, 12 - - end - ## # Top level install helper method. Allows you to install gems interactively: # @@ -1018,10 +977,27 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} @suffix_pattern ||= "{#{suffixes.join(',')}}" end + ## + # Regexp for require-able path suffixes. + def self.suffix_regexp @suffix_regexp ||= /#{Regexp.union(suffixes)}\z/ end + ## + # Glob pattern for require-able plugin suffixes. + + def self.plugin_suffix_pattern + @plugin_suffix_pattern ||= "_plugin#{suffix_pattern}" + end + + ## + # Regexp for require-able plugin suffixes. + + def self.plugin_suffix_regexp + @plugin_suffix_regexp ||= /_plugin#{suffix_regexp}\z/ + end + ## # Suffixes for require-able paths. @@ -1120,35 +1096,17 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} end ## - # Find the 'rubygems_plugin' files in the latest installed gems and load - # them + # Find rubygems plugin files in the standard location and load them def self.load_plugins - # Remove this env var by at least 3.0 - if ENV['RUBYGEMS_LOAD_ALL_PLUGINS'] - load_plugin_files find_files('rubygems_plugin', false) - else - load_plugin_files find_latest_files('rubygems_plugin', false) - end + load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugins_dir) end ## # Find all 'rubygems_plugin' files in $LOAD_PATH and load them def self.load_env_plugins - path = "rubygems_plugin" - - files = [] - glob = "#{path}#{Gem.suffix_pattern}" - $LOAD_PATH.each do |load_path| - globbed = Gem::Util.glob_files_in_dir(glob, load_path) - - globbed.each do |load_path_file| - files << load_path_file if File.file?(load_path_file.tap(&Gem::UNTAINT)) - end - end - - load_plugin_files files + load_plugin_files find_files_from_load_path("rubygems_plugin") end ## @@ -1223,18 +1181,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} end end - class << self - - ## - # TODO remove with RubyGems 4.0 - - alias detect_gemdeps use_gemdeps # :nodoc: - - extend Gem::Deprecate - deprecate :detect_gemdeps, "Gem.use_gemdeps", 2018, 12 - - end - ## # The SOURCE_DATE_EPOCH environment variable (or, if that's not set, the current time), converted to Time object. # This is used throughout RubyGems for enabling reproducible builds. @@ -1366,23 +1312,23 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze - autoload :BundlerVersionFinder, 'rubygems/bundler_version_finder' - autoload :ConfigFile, 'rubygems/config_file' - autoload :Dependency, 'rubygems/dependency' - autoload :DependencyList, 'rubygems/dependency_list' - autoload :Installer, 'rubygems/installer' - autoload :Licenses, 'rubygems/util/licenses' - autoload :PathSupport, 'rubygems/path_support' - autoload :Platform, 'rubygems/platform' - autoload :RequestSet, 'rubygems/request_set' - autoload :Requirement, 'rubygems/requirement' - autoload :Resolver, 'rubygems/resolver' - autoload :Source, 'rubygems/source' - autoload :SourceList, 'rubygems/source_list' - autoload :SpecFetcher, 'rubygems/spec_fetcher' - autoload :Specification, 'rubygems/specification' - autoload :Util, 'rubygems/util' - autoload :Version, 'rubygems/version' + autoload :BundlerVersionFinder, File.expand_path('rubygems/bundler_version_finder', __dir__) + autoload :ConfigFile, File.expand_path('rubygems/config_file', __dir__) + autoload :Dependency, File.expand_path('rubygems/dependency', __dir__) + autoload :DependencyList, File.expand_path('rubygems/dependency_list', __dir__) + autoload :Installer, File.expand_path('rubygems/installer', __dir__) + autoload :Licenses, File.expand_path('rubygems/util/licenses', __dir__) + autoload :PathSupport, File.expand_path('rubygems/path_support', __dir__) + autoload :Platform, File.expand_path('rubygems/platform', __dir__) + autoload :RequestSet, File.expand_path('rubygems/request_set', __dir__) + autoload :Requirement, File.expand_path('rubygems/requirement', __dir__) + autoload :Resolver, File.expand_path('rubygems/resolver', __dir__) + autoload :Source, File.expand_path('rubygems/source', __dir__) + autoload :SourceList, File.expand_path('rubygems/source_list', __dir__) + autoload :SpecFetcher, File.expand_path('rubygems/spec_fetcher', __dir__) + autoload :Specification, File.expand_path('rubygems/specification', __dir__) + autoload :Util, File.expand_path('rubygems/util', __dir__) + autoload :Version, File.expand_path('rubygems/version', __dir__) require "rubygems/specification" end diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb index c6d63ac473..a4bd11cae3 100644 --- a/lib/rubygems/basic_specification.rb +++ b/lib/rubygems/basic_specification.rb @@ -274,12 +274,18 @@ class Gem::BasicSpecification # Return all files in this gem that match for +glob+. def matches_for_glob(glob) # TODO: rename? - # TODO: do we need these?? Kill it glob = File.join(self.lib_dirs_glob, glob) Dir[glob].map { |f| f.tap(&Gem::UNTAINT) } # FIX our tests are broken, run w/ SAFE=1 end + ## + # Returns the list of plugins in this spec. + + def plugins + matches_for_glob("rubygems#{Gem.plugin_suffix_pattern}") + end + ## # Returns a string usable in Dir.glob to match all requirable paths # for this spec. diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index c1e5e13c5a..d9a0700b95 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -466,6 +466,10 @@ class Gem::Command result end + def deprecated? + false + end + private def option_is_deprecated?(option) @@ -646,7 +650,7 @@ basic help message containing pointers to more information. http://localhost:8808/ with info about installed gems Further information: - http://guides.rubygems.org + https://guides.rubygems.org HELP # :startdoc: diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 8ad723be55..03b859e501 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -176,6 +176,7 @@ class Gem::CommandManager cmd_name = args.shift.downcase cmd = find_command cmd_name cmd.invoke_with_build_args args, build_args + cmd.deprecation_warning if cmd.deprecated? end end diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb index 9f14e22f90..259e8b5622 100644 --- a/lib/rubygems/commands/help_command.rb +++ b/lib/rubygems/commands/help_command.rb @@ -38,7 +38,7 @@ Some examples of 'gem' usage. * Create a gem: - See http://guides.rubygems.org/make-your-own-gem/ + See https://guides.rubygems.org/make-your-own-gem/ * See information about RubyGems: diff --git a/lib/rubygems/commands/info_command.rb b/lib/rubygems/commands/info_command.rb index 6a737b178b..a64843405e 100644 --- a/lib/rubygems/commands/info_command.rb +++ b/lib/rubygems/commands/info_command.rb @@ -1,14 +1,19 @@ # frozen_string_literal: true require 'rubygems/command' -require 'rubygems/commands/query_command' +require 'rubygems/query_utils' -class Gem::Commands::InfoCommand < Gem::Commands::QueryCommand +class Gem::Commands::InfoCommand < Gem::Command + + include Gem::QueryUtils def initialize - super "info", "Show information for the given gem" + super "info", "Show information for the given gem", + :name => //, :domain => :local, :details => false, :versions => true, + :installed => nil, :version => Gem::Requirement.default + + add_query_options - remove_option('--name-matches') remove_option('-d') defaults[:details] = true diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index 753ff33eb5..6f9a8d2a08 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -218,7 +218,7 @@ You can use `i` command instead of `install`. gem_version ||= options[:version] domain = options[:domain] domain = :local unless options[:suggest_alternate] - supress_suggestions = (domain == :local) + suppress_suggestions = (domain == :local) begin install_gem gem_name, gem_version @@ -226,11 +226,11 @@ You can use `i` command instead of `install`. alert_error "Error installing #{gem_name}:\n\t#{e.message}" exit_code |= 1 rescue Gem::GemNotFoundException => e - show_lookup_failure e.name, e.version, e.errors, supress_suggestions + show_lookup_failure e.name, e.version, e.errors, suppress_suggestions exit_code |= 2 rescue Gem::UnsatisfiableDependencyError => e - show_lookup_failure e.name, e.version, e.errors, supress_suggestions, + show_lookup_failure e.name, e.version, e.errors, suppress_suggestions, "'#{gem_name}' (#{gem_version})" exit_code |= 2 diff --git a/lib/rubygems/commands/list_command.rb b/lib/rubygems/commands/list_command.rb index cd21543537..f94038920f 100644 --- a/lib/rubygems/commands/list_command.rb +++ b/lib/rubygems/commands/list_command.rb @@ -1,17 +1,20 @@ # frozen_string_literal: true require 'rubygems/command' -require 'rubygems/commands/query_command' +require 'rubygems/query_utils' ## -# An alternate to Gem::Commands::QueryCommand that searches for gems starting -# with the supplied argument. +# Searches for gems starting with the supplied argument. -class Gem::Commands::ListCommand < Gem::Commands::QueryCommand +class Gem::Commands::ListCommand < Gem::Command + + include Gem::QueryUtils def initialize - super 'list', 'Display local gems whose name matches REGEXP' + super 'list', 'Display local gems whose name matches REGEXP', + :name => //, :domain => :local, :details => false, :versions => true, + :installed => nil, :version => Gem::Requirement.default - remove_option('--name-matches') + add_query_options end def arguments # :nodoc: diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index 2248a821c8..d10060923f 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -40,6 +40,11 @@ class Gem::Commands::PristineCommand < Gem::Command options[:only_executables] = value end + add_option('--only-plugins', + 'Only restore plugins') do |value, options| + options[:only_plugins] = value + end + add_option('-E', '--[no-]env-shebang', 'Rewrite executables with a shebang', 'of /usr/bin/env') do |value, options| @@ -126,14 +131,14 @@ extensions will be restored. end end - unless spec.extensions.empty? or options[:extensions] or options[:only_executables] + unless spec.extensions.empty? or options[:extensions] or options[:only_executables] or options[:only_plugins] say "Skipped #{spec.full_name}, it needs to compile an extension" next end gem = spec.cache_file - unless File.exist? gem or options[:only_executables] + unless File.exist? gem or options[:only_executables] or options[:only_plugins] require 'rubygems/remote_fetcher' say "Cached gem for #{spec.full_name} not found, attempting to fetch..." @@ -172,6 +177,9 @@ extensions will be restored. if options[:only_executables] installer = Gem::Installer.for_spec(spec, installer_options) installer.generate_bin + elsif options[:only_plugins] + installer = Gem::Installer.for_spec(spec) + installer.generate_plugins else installer = Gem::Installer.at(gem, installer_options) installer.install diff --git a/lib/rubygems/commands/search_command.rb b/lib/rubygems/commands/search_command.rb index c9cb1f2d43..65ee25167c 100644 --- a/lib/rubygems/commands/search_command.rb +++ b/lib/rubygems/commands/search_command.rb @@ -1,15 +1,17 @@ # frozen_string_literal: true require 'rubygems/command' -require 'rubygems/commands/query_command' +require 'rubygems/query_utils' -class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand +class Gem::Commands::SearchCommand < Gem::Command - def initialize - super 'search', 'Display remote gems whose name matches REGEXP' + include Gem::QueryUtils - remove_option '--name-matches' + def initialize + super 'search', 'Display remote gems whose name matches REGEXP', + :name => //, :domain => :remote, :details => false, :versions => true, + :installed => nil, :version => Gem::Requirement.default - defaults[:domain] = :remote + add_query_options end def arguments # :nodoc: diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index 579776df7e..d67caca91c 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -20,7 +20,8 @@ class Gem::Commands::SetupCommand < Gem::Command :force => true, :site_or_vendor => 'sitelibdir', :destdir => '', :prefix => '', :previous_version => '', - :regenerate_binstubs => true + :regenerate_binstubs => true, + :regenerate_plugins => true add_option '--previous-version=VERSION', 'Previous version of RubyGems', @@ -89,6 +90,11 @@ class Gem::Commands::SetupCommand < Gem::Command options[:regenerate_binstubs] = value end + add_option '--[no-]regenerate-plugins', + 'Regenerate gem plugins' do |value, options| + options[:regenerate_plugins] = value + end + add_option '-f', '--[no-]force', 'Forcefully overwrite binstubs' do |value, options| options[:force] = value @@ -181,6 +187,7 @@ By default, this RubyGems will install gem as: say "RubyGems #{Gem::VERSION} installed" regenerate_binstubs if options[:regenerate_binstubs] + regenerate_plugins if options[:regenerate_plugins] uninstall_old_gemcutter @@ -626,6 +633,16 @@ abort "#{deprecation_message}" command.invoke(*args) end + def regenerate_plugins + require "rubygems/commands/pristine_command" + say "Regenerating plugins" + + args = %w[--all --only-plugins --silent] + + command = Gem::Commands::PristineCommand.new + command.invoke(*args) + end + private def target_bin_path(bin_dir, bin_file) diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb index feab23237d..ca9d425232 100644 --- a/lib/rubygems/commands/sources_command.rb +++ b/lib/rubygems/commands/sources_command.rb @@ -136,7 +136,7 @@ RubyGems has been configured to serve gems via the following URLs through its history: * http://gems.rubyforge.org (RubyGems 1.3.6 and earlier) -* http://rubygems.org (RubyGems 1.3.7 through 1.8.25) +* https://rubygems.org/ (RubyGems 1.3.7 through 1.8.25) * https://rubygems.org (RubyGems 2.0.1 and newer) Since all of these sources point to the same set of gems you only need one @@ -153,8 +153,8 @@ before it is added. To remove a source use the --remove argument: - $ gem sources --remove http://rubygems.org - http://rubygems.org removed from sources + $ gem sources --remove https://rubygems.org/ + https://rubygems.org/ removed from sources EOF end diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index e8031a259d..7031ac0dd0 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -73,8 +73,6 @@ command to remove old versions. say "Latest version already installed. Done." terminate_interaction end - - options[:user_install] = false end def check_update_arguments # :nodoc: @@ -90,9 +88,10 @@ command to remove old versions. return end - hig = highest_installed_gems - - gems_to_update = which_to_update hig, options[:args].uniq + gems_to_update = which_to_update( + highest_installed_gems, + options[:args].uniq + ) if options[:explain] say "Gems to update:" @@ -137,6 +136,9 @@ command to remove old versions. def highest_installed_gems # :nodoc: hig = {} # highest installed gems + # Get only gem specifications installed as --user-install + Gem::Specification.dirs = Gem.user_dir if options[:user_install] + Gem::Specification.each do |spec| if hig[spec.name].nil? or hig[spec.name].version < spec.version hig[spec.name] = spec @@ -168,11 +170,34 @@ command to remove old versions. Dir.chdir update_dir do say "Installing RubyGems #{version}" - installed = system Gem.ruby, '--disable-gems', 'setup.rb', *args + installed = preparing_gem_layout_for(version) do + system Gem.ruby, '--disable-gems', 'setup.rb', *args + end + say "RubyGems system software updated" if installed end end + def preparing_gem_layout_for(version) + if Gem::Version.new(version) >= Gem::Version.new("3.2.a") + yield + else + require "tmpdir" + tmpdir = Dir.mktmpdir + FileUtils.mv Gem.plugins_dir, tmpdir + + status = yield + + if status + FileUtils.rm_rf tmpdir + else + FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugins_dir + end + + status + end + end + def rubygems_target_version version = options[:system] update_latest = version == true diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb index 8accfb6174..19c0aa0752 100644 --- a/lib/rubygems/deprecate.rb +++ b/lib/rubygems/deprecate.rb @@ -65,6 +65,22 @@ module Gem::Deprecate end end - module_function :deprecate, :skip_during + # Deprecation method to deprecate Rubygems commands + def deprecate_command(year, month) + class_eval do + define_method "deprecated?" do + true + end + + define_method "deprecation_warning" do + msg = [ "#{self.command} command is deprecated", + ". It will be removed on or after %4d-%02d-01.\n" % [year, month], + ] + + alert_warning "#{msg.join}" unless Gem::Deprecate.skip + end + end + end + module_function :deprecate, :deprecate_command, :skip_during end diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb index 661ae5a4e1..cb800f11ec 100644 --- a/lib/rubygems/doctor.rb +++ b/lib/rubygems/doctor.rb @@ -26,6 +26,7 @@ class Gem::Doctor ['doc', ''], ['extensions', ''], ['gems', ''], + ['plugins', ''], ].freeze missing = @@ -112,6 +113,7 @@ class Gem::Doctor next if installed_specs.include? basename next if /^rubygems-\d/ =~ basename next if 'specifications' == sub_directory and 'default' == basename + next if 'plugins' == sub_directory and Gem.plugin_suffix_regexp =~ basename type = File.directory?(child) ? 'directory' : 'file' diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 3924f9dde6..ac1e8b49cf 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -5,18 +5,7 @@ require 'rubygems/deprecate' ## # Base exception class for RubyGems. All exception raised by RubyGems are a # subclass of this one. -class Gem::Exception < RuntimeError - - ## - #-- - # TODO: remove in RubyGems 4, nobody sets this - - attr_accessor :source_exception # :nodoc: - - extend Gem::Deprecate - deprecate :source_exception, :none, 2018, 12 - -end +class Gem::Exception < RuntimeError; end class Gem::CommandLineError < Gem::Exception; end diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb index 4159d81389..80aebd579a 100644 --- a/lib/rubygems/gem_runner.rb +++ b/lib/rubygems/gem_runner.rb @@ -26,13 +26,9 @@ Gem.load_env_plugins rescue nil class Gem::GemRunner - def initialize(options={}) - if !options.empty? && !Gem::Deprecate.skip - Kernel.warn "NOTE: passing options to Gem::GemRunner.new is deprecated with no replacement. It will be removed on or after 2016-10-01." - end - - @command_manager_class = options[:command_manager] || Gem::CommandManager - @config_file_class = options[:config_file] || Gem::ConfigFile + def initialize + @command_manager_class = Gem::CommandManager + @config_file_class = Gem::ConfigFile end ## diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index ad39ec81bf..2ba92482cc 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -6,6 +6,7 @@ #++ require 'rubygems/command' +require 'rubygems/installer_uninstaller_utils' require 'rubygems/exceptions' require 'rubygems/deprecate' require 'rubygems/package' @@ -43,6 +44,8 @@ class Gem::Installer include Gem::UserInteraction + include Gem::InstallerUninstallerUtils + ## # Filename of the gem being installed. @@ -180,15 +183,7 @@ class Gem::Installer require 'fileutils' @options = options - if package.is_a? String - security_policy = options[:security_policy] - @package = Gem::Package.new package, security_policy - if $VERBOSE - warn "constructing an Installer object with a string is deprecated. Please use Gem::Installer.at (called from: #{caller.first})" - end - else - @package = package - end + @package = package process_options @@ -330,6 +325,7 @@ class Gem::Installer end generate_bin + generate_plugins unless @options[:install_as_default] write_spec @@ -520,7 +516,17 @@ class Gem::Installer else generate_bin_symlink filename, @bin_dir end + end + end + def generate_plugins # :nodoc: + latest = Gem::Specification.latest_spec_for(spec.name) + return if latest && latest.version > spec.version + + if spec.plugins.empty? + remove_plugins_for(spec) + else + regenerate_plugins_for(spec) end end @@ -810,7 +816,7 @@ TEXT ruby_exe = "ruby.exe" if ruby_exe.empty? if File.exist?(File.join bindir, ruby_exe) - # stub & ruby.exe withing same folder. Portable + # stub & ruby.exe within same folder. Portable <<-TEXT @ECHO OFF @"%~dp0#{ruby_exe}" "%~dpn0" %* @@ -844,18 +850,6 @@ TEXT builder.build_extensions end - ## - # Logs the build +output+ in +build_dir+, then raises Gem::Ext::BuildError. - # - # TODO: Delete this for RubyGems 4. It remains for API compatibility - - def extension_build_error(build_dir, output, backtrace = nil) # :nodoc: - builder = Gem::Ext::Builder.new spec, @build_args - - builder.build_error build_dir, output, backtrace - end - deprecate :extension_build_error, :none, 2018, 12 - ## # Reads the file index and extracts each file into the gem directory. # diff --git a/lib/rubygems/installer_test_case.rb b/lib/rubygems/installer_test_case.rb index f48466d3ea..5a3ce75c26 100644 --- a/lib/rubygems/installer_test_case.rb +++ b/lib/rubygems/installer_test_case.rb @@ -171,10 +171,10 @@ class Gem::InstallerTestCase < Gem::TestCase ## # Sets up the base @gem, builds it and returns an installer for it. # - def util_setup_installer + def util_setup_installer(&block) @gem = setup_base_gem - util_setup_gem + util_setup_gem(&block) end ## diff --git a/lib/rubygems/installer_uninstaller_utils.rb b/lib/rubygems/installer_uninstaller_utils.rb new file mode 100644 index 0000000000..b8436f4f0a --- /dev/null +++ b/lib/rubygems/installer_uninstaller_utils.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +## +# Helper methods for both Gem::Installer and Gem::Uninstaller + +module Gem::InstallerUninstallerUtils + + def regenerate_plugins_for(spec) + spec.plugins.each do |plugin| + plugin_script_path = File.join Gem.plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}" + + File.open plugin_script_path, 'wb' do |file| + file.puts "require '#{plugin}'" + end + + verbose plugin_script_path + end + end + + def remove_plugins_for(spec) + FileUtils.rm_f Gem::Util.glob_files_in_dir("#{spec.name}#{Gem.plugin_suffix_pattern}", Gem.plugins_dir) + end + +end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 813ab9da33..b944a050a3 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -8,7 +8,8 @@ # Example using a Gem::Package # # Builds a .gem file given a Gem::Specification. A .gem file is a tarball -# which contains a data.tar.gz and metadata.gz, and possibly signatures. +# which contains a data.tar.gz, metadata.gz, checksums.yaml.gz and possibly +# signatures. # # require 'rubygems' # require 'rubygems/package' diff --git a/lib/rubygems/query_utils.rb b/lib/rubygems/query_utils.rb new file mode 100644 index 0000000000..3bc5ccfaa2 --- /dev/null +++ b/lib/rubygems/query_utils.rb @@ -0,0 +1,362 @@ +# frozen_string_literal: true + +require 'rubygems/local_remote_options' +require 'rubygems/spec_fetcher' +require 'rubygems/version_option' +require 'rubygems/text' + +module Gem::QueryUtils + + include Gem::Text + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def add_query_options + add_option('-i', '--[no-]installed', + 'Check for installed gem') do |value, options| + options[:installed] = value + end + + add_option('-I', 'Equivalent to --no-installed') do |value, options| + options[:installed] = false + end + + add_version_option command, "for use with --installed" + + add_option('-d', '--[no-]details', + 'Display detailed information of gem(s)') do |value, options| + options[:details] = value + end + + add_option('--[no-]versions', + 'Display only gem names') do |value, options| + options[:versions] = value + options[:details] = false unless value + end + + add_option('-a', '--all', + 'Display all gem versions') do |value, options| + options[:all] = value + end + + add_option('-e', '--exact', + 'Name of gem(s) to query on matches the', + 'provided STRING') do |value, options| + options[:exact] = value + end + + add_option('--[no-]prerelease', + 'Display prerelease versions') do |value, options| + options[:prerelease] = value + end + + add_local_remote_options + end + + def defaults_str # :nodoc: + "--local --name-matches // --no-details --versions --no-installed" + end + + def description # :nodoc: + <<-EOF +The query command is the basis for the list and search commands. + +You should really use the list and search commands instead. This command +is too hard to use. + EOF + end + + def execute + gem_names = Array(options[:name]) + + if !args.empty? + gem_names = options[:exact] ? args.map{|arg| /\A#{Regexp.escape(arg)}\Z/ } : args.map{|arg| /#{arg}/i } + end + + terminate_interaction(check_installed_gems(gem_names)) if check_installed_gems? + + gem_names.each { |n| show_gems(n) } + end + + private + + def check_installed_gems(gem_names) + exit_code = 0 + + if args.empty? && !gem_name? + alert_error "You must specify a gem name" + exit_code = 4 + elsif gem_names.count > 1 + alert_error "You must specify only ONE gem!" + exit_code = 4 + else + installed = installed?(gem_names.first, options[:version]) + installed = !installed unless options[:installed] + + say(installed) + exit_code = 1 if !installed + end + + exit_code + end + + def check_installed_gems? + !options[:installed].nil? + end + + def gem_name? + !options[:name].source.empty? + end + + def prerelease + options[:prerelease] + end + + def show_prereleases? + prerelease.nil? || prerelease + end + + def args + options[:args].to_a + end + + def display_header(type) + if (ui.outs.tty? and Gem.configuration.verbose) or both? + say + say "*** #{type} GEMS ***" + say + end + end + + #Guts of original execute + def show_gems(name) + show_local_gems(name) if local? + show_remote_gems(name) if remote? + end + + def show_local_gems(name, req = Gem::Requirement.default) + display_header("LOCAL") + + specs = Gem::Specification.find_all do |s| + s.name =~ name and req =~ s.version + end + + dep = Gem::Deprecate.skip_during { Gem::Dependency.new name, req } + specs.select! do |s| + dep.match?(s.name, s.version, show_prereleases?) + end + + spec_tuples = specs.map do |spec| + [spec.name_tuple, spec] + end + + output_query_results(spec_tuples) + end + + def show_remote_gems(name) + display_header("REMOTE") + + fetcher = Gem::SpecFetcher.fetcher + + spec_tuples = if name.respond_to?(:source) && name.source.empty? + fetcher.detect(specs_type) { true } + else + fetcher.detect(specs_type) do |name_tuple| + name === name_tuple.name + end + end + + output_query_results(spec_tuples) + end + + def specs_type + if options[:all] + if options[:prerelease] + :complete + else + :released + end + elsif options[:prerelease] + :prerelease + else + :latest + end + end + + ## + # Check if gem +name+ version +version+ is installed. + + def installed?(name, req = Gem::Requirement.default) + Gem::Specification.any? { |s| s.name =~ name and req =~ s.version } + end + + def output_query_results(spec_tuples) + output = [] + versions = Hash.new { |h,name| h[name] = [] } + + spec_tuples.each do |spec_tuple, source| + versions[spec_tuple.name] << [spec_tuple, source] + end + + versions = versions.sort_by do |(n,_),_| + n.downcase + end + + output_versions output, versions + + say output.join(options[:details] ? "\n\n" : "\n") + end + + def output_versions(output, versions) + versions.each do |gem_name, matching_tuples| + matching_tuples = matching_tuples.sort_by { |n,_| n.version }.reverse + + platforms = Hash.new { |h,version| h[version] = [] } + + matching_tuples.each do |n, _| + platforms[n.version] << n.platform if n.platform + end + + seen = {} + + matching_tuples.delete_if do |n,_| + if seen[n.version] + true + else + seen[n.version] = true + false + end + end + + output << clean_text(make_entry(matching_tuples, platforms)) + end + end + + def entry_details(entry, detail_tuple, specs, platforms) + return unless options[:details] + + name_tuple, spec = detail_tuple + + spec = spec.fetch_spec(name_tuple)if spec.respond_to?(:fetch_spec) + + entry << "\n" + + spec_platforms entry, platforms + spec_authors entry, spec + spec_homepage entry, spec + spec_license entry, spec + spec_loaded_from entry, spec, specs + spec_summary entry, spec + end + + def entry_versions(entry, name_tuples, platforms, specs) + return unless options[:versions] + + list = + if platforms.empty? or options[:details] + name_tuples.map { |n| n.version }.uniq + else + platforms.sort.reverse.map do |version, pls| + out = version.to_s + + if options[:domain] == :local + default = specs.any? do |s| + !s.is_a?(Gem::Source) && s.version == version && s.default_gem? + end + out = "default: #{out}" if default + end + + if pls != [Gem::Platform::RUBY] + platform_list = [pls.delete(Gem::Platform::RUBY), *pls.sort].compact + out = platform_list.unshift(out).join(' ') + end + + out + end + end + + entry << " (#{list.join ', '})" + end + + def make_entry(entry_tuples, platforms) + detail_tuple = entry_tuples.first + + name_tuples, specs = entry_tuples.flatten.partition do |item| + Gem::NameTuple === item + end + + entry = [name_tuples.first.name] + + entry_versions(entry, name_tuples, platforms, specs) + entry_details(entry, detail_tuple, specs, platforms) + + entry.join + end + + def spec_authors(entry, spec) + authors = "Author#{spec.authors.length > 1 ? 's' : ''}: ".dup + authors << spec.authors.join(', ') + entry << format_text(authors, 68, 4) + end + + def spec_homepage(entry, spec) + return if spec.homepage.nil? or spec.homepage.empty? + + entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4) + end + + def spec_license(entry, spec) + return if spec.license.nil? or spec.license.empty? + + licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: ".dup + licenses << spec.licenses.join(', ') + entry << "\n" << format_text(licenses, 68, 4) + end + + def spec_loaded_from(entry, spec, specs) + return unless spec.loaded_from + + if specs.length == 1 + default = spec.default_gem? ? ' (default)' : nil + entry << "\n" << " Installed at#{default}: #{spec.base_dir}" + else + label = 'Installed at' + specs.each do |s| + version = s.version.to_s + version << ', default' if s.default_gem? + entry << "\n" << " #{label} (#{version}): #{s.base_dir}" + label = ' ' * label.length + end + end + end + + def spec_platforms(entry, platforms) + non_ruby = platforms.any? do |_, pls| + pls.any? { |pl| pl != Gem::Platform::RUBY } + end + + return unless non_ruby + + if platforms.length == 1 + title = platforms.values.length == 1 ? 'Platform' : 'Platforms' + entry << " #{title}: #{platforms.values.sort.join(', ')}\n" + else + entry << " Platforms:\n" + + sorted_platforms = platforms.sort_by { |version,| version } + + sorted_platforms.each do |version, pls| + label = " #{version}: " + data = format_text pls.sort.join(', '), 68, label.length + data[0, label.length] = label + entry << data << "\n" + end + end + end + + def spec_summary(entry, spec) + summary = truncate_text(spec.summary, "the summary for #{spec.full_name}") + entry << "\n\n" << format_text(summary, 68, 4) + end + +end diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index 2ed619f1bc..b37ebc15fd 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -7,7 +7,6 @@ require 'rubygems/uri_formatter' require 'rubygems/uri_parsing' require 'rubygems/user_interaction' require 'resolv' -require 'rubygems/deprecate' ## # RemoteFetcher handles the details of fetching gems and gem information from @@ -16,8 +15,6 @@ require 'rubygems/deprecate' class Gem::RemoteFetcher include Gem::UserInteraction - extend Gem::Deprecate - include Gem::UriParsing ## @@ -309,17 +306,6 @@ class Gem::RemoteFetcher data end - ## - # Returns the size of +uri+ in bytes. - - def fetch_size(uri) - response = fetch_path(uri, nil, true) - - response['content-length'].to_i - end - - deprecate :fetch_size, :none, 2019, 12 - ## # Performs a Net::HTTP request of type +request_class+ on +uri+ returning # a Net::HTTP response object. request maintains a table of persistent diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb index b7a8ee6f4f..ef3f302ea8 100644 --- a/lib/rubygems/request_set/gem_dependency_api.rb +++ b/lib/rubygems/request_set/gem_dependency_api.rb @@ -235,7 +235,7 @@ class Gem::RequestSet::GemDependencyAPI return unless (groups & @without_groups).empty? dependencies.each do |dep| - @set.gem dep.name, *dep.requirement + @set.gem dep.name, *dep.requirement.as_list end end diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb index 6fd91e3b73..135f1b08aa 100644 --- a/lib/rubygems/resolver/api_set.rb +++ b/lib/rubygems/resolver/api_set.rb @@ -23,7 +23,7 @@ class Gem::Resolver::APISet < Gem::Resolver::Set ## # Creates a new APISet that will retrieve gems from +uri+ using the RubyGems # API URL +dep_uri+ which is described at - # http://guides.rubygems.org/rubygems-org-api + # https://guides.rubygems.org/rubygems-org-api def initialize(dep_uri = 'https://rubygems.org/api/v1/dependencies') super() diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb index 9bbc095788..4052846e99 100644 --- a/lib/rubygems/resolver/api_specification.rb +++ b/lib/rubygems/resolver/api_specification.rb @@ -11,7 +11,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification # Creates an APISpecification for the given +set+ from the rubygems.org # +api_data+. # - # See http://guides.rubygems.org/rubygems-org-api/#misc_methods for the + # See https://guides.rubygems.org/rubygems-org-api/#misc_methods for the # format of the +api_data+. def initialize(set, api_data) diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb index 7b0a0b3c6a..4529c08772 100644 --- a/lib/rubygems/security.rb +++ b/lib/rubygems/security.rb @@ -62,11 +62,11 @@ end # # $ tar tf your-gem-1.0.gem # metadata.gz -# metadata.gz.sum # metadata.gz.sig # metadata signature # data.tar.gz -# data.tar.gz.sum # data.tar.gz.sig # data signature +# checksums.yaml.gz +# checksums.yaml.gz.sig # checksums signature # # === Manually signing gems # @@ -161,6 +161,8 @@ end # -K, --private-key KEY Key for --sign or --build # -s, --sign CERT Signs CERT with the key from -K # and the certificate from -C +# -d, --days NUMBER_OF_DAYS Days before the certificate expires +# -R, --re-sign Re-signs the certificate from -C with the key from -K # # We've already covered the --build option, and the # --add, --list, and --remove commands @@ -265,7 +267,7 @@ end # 2. Grab the public key from the gemspec # # gem spec some_signed_gem-1.0.gem cert_chain | \ -# ruby -ryaml -e 'puts YAML.load_documents($stdin)' > public_key.crt +# ruby -ryaml -e 'puts YAML.load($stdin)' > public_key.crt # # 3. Generate a SHA1 hash of the data.tar.gz # diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb index 5e4ba6ebba..8fb1b1ddc1 100644 --- a/lib/rubygems/security/signer.rb +++ b/lib/rubygems/security/signer.rb @@ -39,7 +39,7 @@ class Gem::Security::Signer }.freeze ## - # Attemps to re-sign an expired cert with a given private key + # Attempts to re-sign an expired cert with a given private key def self.re_sign_cert(expired_cert, expired_cert_path, private_key) return unless expired_cert.not_after < Time.now diff --git a/lib/rubygems/server.rb b/lib/rubygems/server.rb index 97923ef698..83d7cf5abc 100644 --- a/lib/rubygems/server.rb +++ b/lib/rubygems/server.rb @@ -661,7 +661,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } "only_one_executable" => true, "full_name" => "rubygems-#{Gem::VERSION}", "has_deps" => false, - "homepage" => "http://guides.rubygems.org/", + "homepage" => "https://guides.rubygems.org/", "name" => 'rubygems', "ri_installed" => true, "summary" => "RubyGems itself", diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 5321edfcc3..ad43a63e80 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -384,6 +384,7 @@ class Gem::Specification < Gem::BasicSpecification # "mailing_list_uri" => "https://groups.example.com/bestgemever", # "source_code_uri" => "https://example.com/user/bestgemever", # "wiki_uri" => "https://example.com/user/bestgemever/wiki" + # "funding_uri" => "https://example.com/donate" # } # # These links will be used on your gem's page on rubygems.org and must pass @@ -1086,6 +1087,13 @@ class Gem::Specification < Gem::BasicSpecification _latest_specs Gem::Specification._all, prerelease end + ## + # Return the latest installed spec for gem +name+. + + def self.latest_spec_for(name) + latest_specs(true).find { |installed_spec| installed_spec.name == name } + end + def self._latest_specs(specs, prerelease = false) # :nodoc: result = Hash.new { |h,k| h[k] = {} } native = {} @@ -1752,10 +1760,11 @@ class Gem::Specification < Gem::BasicSpecification # # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]] - def dependent_gems + def dependent_gems(check_dev=true) out = [] Gem::Specification.each do |spec| - spec.dependencies.each do |dep| + deps = check_dev ? spec.dependencies : spec.runtime_dependencies + deps.each do |dep| if self.satisfies_requirement?(dep) sats = [] find_all_satisfiers(dep) do |sat| @@ -1847,29 +1856,23 @@ class Gem::Specification < Gem::BasicSpecification end ## - # Sets executables to +value+, ensuring it is an array. Don't - # use this, push onto the array instead. + # Sets executables to +value+, ensuring it is an array. def executables=(value) - # TODO: warn about setting instead of pushing @executables = Array(value) end ## - # Sets extensions to +extensions+, ensuring it is an array. Don't - # use this, push onto the array instead. + # Sets extensions to +extensions+, ensuring it is an array. def extensions=(extensions) - # TODO: warn about setting instead of pushing @extensions = Array extensions end ## - # Sets extra_rdoc_files to +files+, ensuring it is an array. Don't - # use this, push onto the array instead. + # Sets extra_rdoc_files to +files+, ensuring it is an array. def extra_rdoc_files=(files) - # TODO: warn about setting instead of pushing @extra_rdoc_files = Array files end @@ -2245,11 +2248,9 @@ class Gem::Specification < Gem::BasicSpecification end ## - # Sets rdoc_options to +value+, ensuring it is an array. Don't - # use this, push onto the array instead. + # Sets rdoc_options to +value+, ensuring it is an array. def rdoc_options=(options) - # TODO: warn about setting instead of pushing @rdoc_options = Array options end @@ -2268,11 +2269,9 @@ class Gem::Specification < Gem::BasicSpecification end ## - # Set requirements to +req+, ensuring it is an array. Don't - # use this, push onto the array instead. + # Set requirements to +req+, ensuring it is an array. def requirements=(req) - # TODO: warn about setting instead of pushing @requirements = Array req end diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index c3c496db9b..a50fafbc82 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -18,6 +18,7 @@ class Gem::SpecificationPolicy mailing_list_uri source_code_uri wiki_uri + funding_uri ].freeze # :nodoc: def initialize(specification) @@ -421,7 +422,7 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li end def help_text # :nodoc: - "See http://guides.rubygems.org/specification-reference/ for help" + "See https://guides.rubygems.org/specification-reference/ for help" end end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 206497c651..691985dcd2 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -169,20 +169,24 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni # original value when the block ends # def bindir(value) - bindir = RbConfig::CONFIG['bindir'] + with_clean_path_to_ruby do + bindir = RbConfig::CONFIG['bindir'] - if value - RbConfig::CONFIG['bindir'] = value - else - RbConfig::CONFIG.delete 'bindir' - end + if value + RbConfig::CONFIG['bindir'] = value + else + RbConfig::CONFIG.delete 'bindir' + end - yield - ensure - if bindir - RbConfig::CONFIG['bindir'] = bindir - else - RbConfig::CONFIG.delete 'bindir' + begin + yield + ensure + if bindir + RbConfig::CONFIG['bindir'] = bindir + else + RbConfig::CONFIG.delete 'bindir' + end + end end end @@ -321,6 +325,11 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni @tempdir.tap(&Gem::UNTAINT) end + @orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE + Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE + Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE, + File.join(@tempdir, 'system-gemrc') + @gemhome = File.join @tempdir, 'gemhome' @userhome = File.join @tempdir, 'userhome' ENV["GEM_SPEC_CACHE"] = File.join @tempdir, 'spec_cache' @@ -331,7 +340,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni ruby end - @git = ENV['GIT'] || 'git' + @git = ENV['GIT'] || (win_platform? ? 'git.exe' : 'git') Gem.ensure_gem_subdirectories @gemhome @@ -442,6 +451,10 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni ENV.replace(@orig_env) + Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE + Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE, + @orig_SYSTEM_WIDE_CONFIG_FILE + Gem.ruby = @orig_ruby if @orig_ruby if Gem.java_platform? @@ -562,7 +575,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni def install_gem(spec, options = {}) require 'rubygems/installer' - gem = File.join @tempdir, "gems", "#{spec.full_name}.gem" + gem = spec.cache_file unless File.exist? gem use_ui Gem::MockGemUi.new do @@ -571,7 +584,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni end end - gem = File.join(@tempdir, File.basename(spec.cache_file)).tap(&Gem::UNTAINT) + gem = File.join(@tempdir, File.basename(gem)).tap(&Gem::UNTAINT) end Gem::Installer.at(gem, options.merge({:wrappers => true})).install @@ -667,8 +680,6 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni yield(s) if block_given? end - Gem::Specification.map # HACK: force specs to (re-)load before we write - written_path = write_file spec.spec_file do |io| io.write spec.to_ruby_for_cache end @@ -833,9 +844,6 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni util_build_gem spec - cache_file = File.join @tempdir, 'gems', "#{spec.full_name}.gem" - FileUtils.mkdir_p File.dirname cache_file - FileUtils.mv spec.cache_file, cache_file FileUtils.rm spec.spec_file end @@ -1247,6 +1255,16 @@ Also, a list: end end + def with_clean_path_to_ruby + orig_ruby = Gem.ruby + + Gem.instance_variable_set :@ruby, nil + + yield + ensure + Gem.instance_variable_set :@ruby, orig_ruby + end + class << self # :nodoc: diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index 20b437d472..1766423429 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -7,6 +7,7 @@ require 'fileutils' require 'rubygems' +require 'rubygems/installer_uninstaller_utils' require 'rubygems/dependency_list' require 'rubygems/rdoc' require 'rubygems/user_interaction' @@ -23,6 +24,8 @@ class Gem::Uninstaller include Gem::UserInteraction + include Gem::InstallerUninstallerUtils + ## # The directory a gem's executables will be installed into @@ -158,8 +161,11 @@ class Gem::Uninstaller end remove_executables @spec + remove_plugins @spec remove @spec + regenerate_plugins + Gem.post_uninstall_hooks.each do |hook| hook.call self end @@ -168,11 +174,10 @@ class Gem::Uninstaller end ## - # Removes installed executables and batch files (windows only) for - # +gemspec+. + # Removes installed executables and batch files (windows only) for +spec+. def remove_executables(spec) - return if spec.nil? or spec.executables.empty? + return if spec.executables.empty? executables = spec.executables.clone @@ -231,10 +236,6 @@ class Gem::Uninstaller ## # spec:: the spec of the gem to be uninstalled - # list:: the list of all such gems - # - # Warning: this method modifies the +list+ parameter. Once it has - # uninstalled a gem, it is removed from that list. def remove(spec) unless path_ok?(@gem_home, spec) or @@ -274,6 +275,25 @@ class Gem::Uninstaller Gem::Specification.reset end + ## + # Remove any plugin wrappers for +spec+. + + def remove_plugins(spec) # :nodoc: + return if spec.plugins.empty? + + remove_plugins_for(spec) + end + + ## + # Regenerates plugin wrappers after removal. + + def regenerate_plugins + latest = Gem::Specification.latest_spec_for(@spec.name) + return if latest.nil? + + regenerate_plugins_for(latest) + end + ## # Is +spec+ in +gem_dir+? @@ -317,7 +337,7 @@ class Gem::Uninstaller s.name == spec.name && s.full_name != spec.full_name end - spec.dependent_gems.each do |dep_spec, dep, satlist| + spec.dependent_gems(@check_dev).each do |dep_spec, dep, satlist| unless siblings.any? { |s| s.satisfies_requirement? dep } msg << "#{dep_spec.name}-#{dep_spec.version} depends on #{dep}" end diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb index 93f528a763..f5bdd84150 100644 --- a/lib/rubygems/user_interaction.rb +++ b/lib/rubygems/user_interaction.rb @@ -358,14 +358,6 @@ class Gem::StreamUI ask(question) if question end - ## - # Display a debug message on the same location as error messages. - - def debug(statement) - @errs.puts statement - end - deprecate :debug, :none, 2018, 12 - ## # Terminate the application with exit code +status+, running any exit # handlers that might have been defined. diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 6524faf5c8..b1faedcda2 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -151,7 +151,7 @@ class Gem::Version - autoload :Requirement, 'rubygems/requirement' + autoload :Requirement, File.expand_path('requirement', __dir__) include Comparable diff --git a/test/rubygems/test_deprecate.rb b/test/rubygems/test_deprecate.rb index b92bd1c3da..f5cd83ee89 100644 --- a/test/rubygems/test_deprecate.rb +++ b/test/rubygems/test_deprecate.rb @@ -77,4 +77,22 @@ class TestDeprecate < Gem::TestCase assert_match(/on or after 2099-03-01/, err) end + def test_deprecate_command + require 'rubygems/command' + foo_command = Class.new(Gem::Command) do + extend Gem::Deprecate + + deprecate_command(2099, 4) + + def execute + puts "pew pew!" + end + end + + Gem::Commands.send(:const_set, :FooCommand, foo_command) + assert Gem::Commands::FooCommand.new("foo").deprecated? + ensure + Gem::Commands.send(:remove_const, :FooCommand) + end + end diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 6d223b7d69..2890e13dfb 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -11,12 +11,6 @@ if File.exist?(File.join(Dir.tmpdir, "Gemfile")) raise "rubygems/bundler tests do not work correctly if there is #{ File.join(Dir.tmpdir, "Gemfile") }" end -# TODO: push this up to test_case.rb once battle tested - -$LOAD_PATH.map! do |path| - path.dup.tap(&Gem::UNTAINT) -end - class TestGem < Gem::TestCase PLUGINS_LOADED = [] # rubocop:disable Style/MutableConstant @@ -161,10 +155,8 @@ class TestGem < Gem::TestCase def test_self_install_permissions_with_format_executable_and_non_standard_ruby_install_name Gem::Installer.exec_format = nil - with_clean_path_to_ruby do - ruby_install_name 'ruby27' do - assert_self_install_permissions(format_executable: true) - end + ruby_install_name 'ruby27' do + assert_self_install_permissions(format_executable: true) end ensure Gem::Installer.exec_format = nil @@ -1024,21 +1016,17 @@ class TestGem < Gem::TestCase end def test_self_ruby_escaping_spaces_in_path - with_clean_path_to_ruby do - with_bindir_and_exeext("C:/Ruby 1.8/bin", ".exe") do - ruby_install_name "ruby" do - assert_equal "\"C:/Ruby 1.8/bin/ruby.exe\"", Gem.ruby - end + with_bindir_and_exeext("C:/Ruby 1.8/bin", ".exe") do + ruby_install_name "ruby" do + assert_equal "\"C:/Ruby 1.8/bin/ruby.exe\"", Gem.ruby end end end def test_self_ruby_path_without_spaces - with_clean_path_to_ruby do - with_bindir_and_exeext("C:/Ruby18/bin", ".exe") do - ruby_install_name "ruby" do - assert_equal "C:/Ruby18/bin/ruby.exe", Gem.ruby - end + with_bindir_and_exeext("C:/Ruby18/bin", ".exe") do + ruby_install_name "ruby" do + assert_equal "C:/Ruby18/bin/ruby.exe", Gem.ruby end end end @@ -1090,7 +1078,7 @@ class TestGem < Gem::TestCase util_restore_RUBY_VERSION end - def test_self_ruby_version_with_prerelease + def test_self_ruby_version_with_svn_prerelease util_set_RUBY_VERSION '2.6.0', -1, 63539, 'ruby 2.6.0preview2 (2018-05-31 trunk 63539) [x86_64-linux]' assert_equal Gem::Version.new('2.6.0.preview2'), Gem.ruby_version @@ -1098,6 +1086,14 @@ class TestGem < Gem::TestCase util_restore_RUBY_VERSION end + def test_self_ruby_version_with_git_prerelease + util_set_RUBY_VERSION '2.7.0', -1, 'b563439274a402e33541f5695b1bfd4ac1085638', 'ruby 2.7.0preview3 (2019-11-23 master b563439274) [x86_64-linux]' + + assert_equal Gem::Version.new('2.7.0.preview3'), Gem.ruby_version + ensure + util_restore_RUBY_VERSION + end + def test_self_ruby_version_with_non_mri_implementations_with_mri_prerelase_compatibility util_set_RUBY_VERSION '2.6.0', -1, 63539, 'weirdjruby 9.2.0.0 (2.6.0preview2) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.171-b11 on 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11 [linux-x86_64]', 'weirdjruby', '9.2.0.0' @@ -1106,7 +1102,7 @@ class TestGem < Gem::TestCase util_restore_RUBY_VERSION end - def test_self_ruby_version_with_trunk + def test_self_ruby_version_with_svn_trunk util_set_RUBY_VERSION '1.9.2', -1, 23493, 'ruby 1.9.2dev (2009-05-20 trunk 23493) [x86_64-linux]' assert_equal Gem::Version.new('1.9.2.dev'), Gem.ruby_version @@ -1114,6 +1110,14 @@ class TestGem < Gem::TestCase util_restore_RUBY_VERSION end + def test_self_ruby_version_with_git_master + util_set_RUBY_VERSION '2.7.0', -1, '5de284ec78220e75643f89b454ce999da0c1c195', 'ruby 2.7.0dev (2019-12-23T01:37:30Z master 5de284ec78) [x86_64-linux]' + + assert_equal Gem::Version.new('2.7.0.dev'), Gem.ruby_version + ensure + util_restore_RUBY_VERSION + end + def test_self_rubygems_version assert_equal Gem::Version.new(Gem::VERSION), Gem.rubygems_version end @@ -1470,7 +1474,6 @@ class TestGem < Gem::TestCase install_gem foo2 end - Gem.searcher = nil Gem::Specification.reset gem 'foo' @@ -1904,15 +1907,19 @@ You may need to `gem install -g` to install missing gems end def ruby_install_name(name) - orig_RUBY_INSTALL_NAME = RbConfig::CONFIG['ruby_install_name'] - RbConfig::CONFIG['ruby_install_name'] = name + with_clean_path_to_ruby do + orig_RUBY_INSTALL_NAME = RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['ruby_install_name'] = name - yield - ensure - if orig_RUBY_INSTALL_NAME - RbConfig::CONFIG['ruby_install_name'] = orig_RUBY_INSTALL_NAME - else - RbConfig::CONFIG.delete 'ruby_install_name' + begin + yield + ensure + if orig_RUBY_INSTALL_NAME + RbConfig::CONFIG['ruby_install_name'] = orig_RUBY_INSTALL_NAME + else + RbConfig::CONFIG.delete 'ruby_install_name' + end + end end end @@ -1924,16 +1931,6 @@ You may need to `gem install -g` to install missing gems end end - def with_clean_path_to_ruby - orig_ruby = Gem.ruby - - Gem.instance_variable_set :@ruby, nil - - yield - ensure - Gem.instance_variable_set :@ruby, orig_ruby - end - def with_plugin(path) test_plugin_path = File.expand_path("test/rubygems/plugin/#{path}", PROJECT_DIR) diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb index 45be9f01be..c6aaff291a 100644 --- a/test/rubygems/test_gem_command_manager.rb +++ b/test/rubygems/test_gem_command_manager.rb @@ -224,26 +224,34 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[query] + Gem::Deprecate.skip_during do + @command_manager.process_args %w[query] + end assert_equal(//, check_options[:name]) assert_equal :local, check_options[:domain] assert_equal false, check_options[:details] #check settings check_options = nil - @command_manager.process_args %w[query --name foobar --local --details] + Gem::Deprecate.skip_during do + @command_manager.process_args %w[query --name foobar --local --details] + end assert_equal(/foobar/i, check_options[:name]) assert_equal :local, check_options[:domain] assert_equal true, check_options[:details] #remote domain check_options = nil - @command_manager.process_args %w[query --remote] + Gem::Deprecate.skip_during do + @command_manager.process_args %w[query --remote] + end assert_equal :remote, check_options[:domain] #both (local/remote) domains check_options = nil - @command_manager.process_args %w[query --both] + Gem::Deprecate.skip_during do + @command_manager.process_args %w[query --both] + end assert_equal :both, check_options[:domain] end @@ -268,4 +276,29 @@ class TestGemCommandManager < Gem::TestCase assert_equal Dir.pwd, check_options[:install_dir] end + def test_deprecated_command + require 'rubygems/command' + foo_command = Class.new(Gem::Command) do + extend Gem::Deprecate + + deprecate_command(2099, 4) + + def execute + say "pew pew!" + end + end + + Gem::Commands.send(:const_set, :FooCommand, foo_command) + @command_manager.register_command(:foo, foo_command.new("foo")) + + use_ui @ui do + @command_manager.process_args(%w[foo]) + end + + assert_equal "pew pew!\n", @ui.output + assert_equal("WARNING: foo command is deprecated. It will be removed on or after 2099-04-01.\n", @ui.error) + ensure + Gem::Commands.send(:remove_const, :FooCommand) + end + end diff --git a/test/rubygems/test_gem_commands_build_command.rb b/test/rubygems/test_gem_commands_build_command.rb index 50c447e2eb..a2e8f284eb 100644 --- a/test/rubygems/test_gem_commands_build_command.rb +++ b/test/rubygems/test_gem_commands_build_command.rb @@ -147,7 +147,7 @@ class TestGemCommandsBuildCommand < Gem::TestCase error = @ui.error.split "\n" assert_equal "WARNING: licenses is empty, but is recommended. Use a license identifier from", error.shift assert_equal "http://spdx.org/licenses or 'Nonstandard' for a nonstandard license.", error.shift - assert_equal "WARNING: See http://guides.rubygems.org/specification-reference/ for help", error.shift + assert_equal "WARNING: See https://guides.rubygems.org/specification-reference/ for help", error.shift assert_equal [], error gem_file = File.join @tempdir, File.basename(@gem.cache_file) diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb index e872a80957..4ebe1efecb 100644 --- a/test/rubygems/test_gem_commands_pristine_command.rb +++ b/test/rubygems/test_gem_commands_pristine_command.rb @@ -215,7 +215,6 @@ class TestGemCommandsPristineCommand < Gem::TestCase io.write "# extconf.rb\nrequire 'mkmf'; create_makefile 'a'" end - util_build_gem a install_gem a @cmd.options[:args] = %w[a] @@ -491,6 +490,42 @@ class TestGemCommandsPristineCommand < Gem::TestCase refute File.exist? gem_lib end + def test_execute_only_plugins + a = util_spec 'a' do |s| + s.executables = %w[foo] + s.files = %w[bin/foo lib/a.rb lib/rubygems_plugin.rb] + end + write_file File.join(@tempdir, 'lib', 'a.rb') do |fp| + fp.puts "puts __FILE__" + end + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |fp| + fp.puts "puts __FILE__" + end + write_file File.join(@tempdir, 'bin', 'foo') do |fp| + fp.puts "#!/usr/bin/ruby" + end + + install_gem a + + gem_lib = File.join @gemhome, 'gems', a.full_name, 'lib', 'a.rb' + gem_plugin = File.join @gemhome, 'plugins', 'a_plugin.rb' + gem_exec = File.join @gemhome, 'bin', 'foo' + + FileUtils.rm gem_exec + FileUtils.rm gem_plugin + FileUtils.rm gem_lib + + @cmd.handle_options %w[--all --only-plugins] + + use_ui @ui do + @cmd.execute + end + + refute File.exist? gem_exec + assert File.exist? gem_plugin + refute File.exist? gem_lib + end + def test_execute_bindir a = util_spec 'a' do |s| s.name = "test_gem" diff --git a/test/rubygems/test_gem_commands_query_command.rb b/test/rubygems/test_gem_commands_query_command.rb deleted file mode 100644 index 6183e592e9..0000000000 --- a/test/rubygems/test_gem_commands_query_command.rb +++ /dev/null @@ -1,857 +0,0 @@ -# frozen_string_literal: true -require 'rubygems/test_case' -require 'rubygems/commands/query_command' - -module TestGemCommandsQueryCommandSetup - def setup - super - - @cmd = Gem::Commands::QueryCommand.new - - @specs = add_gems_to_fetcher - @stub_ui = Gem::MockGemUi.new - @stub_fetcher = Gem::FakeFetcher.new - - @stub_fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do - raise Gem::RemoteFetcher::FetchError - end - end -end - -class TestGemCommandsQueryCommandWithInstalledGems < Gem::TestCase - - include TestGemCommandsQueryCommandSetup - - def test_execute - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_all - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r --all] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_all_prerelease - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r --all --prerelease] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_details - spec_fetcher do |fetcher| - fetcher.spec 'a', 2 do |s| - s.summary = 'This is a lot of text. ' * 4 - s.authors = ['Abraham Lincoln', 'Hirohito'] - s.homepage = 'http://a.example.com/' - end - - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r -d] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2) - Authors: Abraham Lincoln, Hirohito - Homepage: http://a.example.com/ - - This is a lot of text. This is a lot of text. This is a lot of text. - This is a lot of text. - -pl (1) - Platform: i386-linux - Author: A User - Homepage: http://example.com - - this is a summary - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_details_cleans_text - spec_fetcher do |fetcher| - fetcher.spec 'a', 2 do |s| - s.summary = 'This is a lot of text. ' * 4 - s.authors = ["Abraham Lincoln \x01", "\x02 Hirohito"] - s.homepage = "http://a.example.com/\x03" - end - - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r -d] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2) - Authors: Abraham Lincoln ., . Hirohito - Homepage: http://a.example.com/. - - This is a lot of text. This is a lot of text. This is a lot of text. - This is a lot of text. - -pl (1) - Platform: i386-linux - Author: A User - Homepage: http://example.com - - this is a summary - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_details_truncates_summary - spec_fetcher do |fetcher| - fetcher.spec 'a', 2 do |s| - s.summary = 'This is a lot of text. ' * 10_000 - s.authors = ["Abraham Lincoln \x01", "\x02 Hirohito"] - s.homepage = "http://a.example.com/\x03" - end - - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r -d] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2) - Authors: Abraham Lincoln ., . Hirohito - Homepage: http://a.example.com/. - - Truncating the summary for a-2 to 100,000 characters: -#{" This is a lot of text. This is a lot of text. This is a lot of text.\n" * 1449} This is a lot of te - -pl (1) - Platform: i386-linux - Author: A User - Homepage: http://example.com - - this is a summary - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_installed - @cmd.handle_options %w[-n a --installed] - - assert_raises Gem::MockGemUi::SystemExitException do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "true\n", @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_installed_inverse - @cmd.handle_options %w[-n a --no-installed] - - e = assert_raises Gem::MockGemUi::TermError do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "false\n", @stub_ui.output - assert_equal '', @stub_ui.error - - assert_equal 1, e.exit_code - end - - def test_execute_installed_inverse_not_installed - @cmd.handle_options %w[-n not_installed --no-installed] - - assert_raises Gem::MockGemUi::SystemExitException do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "true\n", @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_installed_no_name - @cmd.handle_options %w[--installed] - - e = assert_raises Gem::MockGemUi::TermError do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal '', @stub_ui.output - assert_equal "ERROR: You must specify a gem name\n", @stub_ui.error - - assert_equal 4, e.exit_code - end - - def test_execute_installed_not_installed - @cmd.handle_options %w[-n not_installed --installed] - - e = assert_raises Gem::MockGemUi::TermError do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "false\n", @stub_ui.output - assert_equal '', @stub_ui.error - - assert_equal 1, e.exit_code - end - - def test_execute_installed_version - @cmd.handle_options %w[-n a --installed --version 2] - - assert_raises Gem::MockGemUi::SystemExitException do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "true\n", @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_installed_version_not_installed - @cmd.handle_options %w[-n c --installed --version 2] - - e = assert_raises Gem::MockGemUi::TermError do - use_ui @stub_ui do - @cmd.execute - end - end - - assert_equal "false\n", @stub_ui.output - assert_equal '', @stub_ui.error - - assert_equal 1, e.exit_code - end - - def test_execute_local - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.options[:domain] = :local - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_local_notty - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[] - - @stub_ui.outs.tty = false - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_local_quiet - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.options[:domain] = :local - Gem.configuration.verbose = false - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_no_versions - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r --no-versions] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a -pl - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_notty - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-r] - - @stub_ui.outs.tty = false - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF -a (2) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_prerelease - @cmd.handle_options %w[-r --prerelease] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (3.a) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_prerelease_local - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-l --prerelease] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_no_prerelease_local - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[-l --no-prerelease] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_remote - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.options[:domain] = :remote - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_remote_notty - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[] - - @stub_ui.outs.tty = false - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF -a (3.a, 2, 1) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_remote_quiet - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.options[:domain] = :remote - Gem.configuration.verbose = false - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF -a (2) -pl (1 i386-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_make_entry - a_2_name = @specs['a-2'].original_name - - @stub_fetcher.data.delete \ - "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz" - - a2 = @specs['a-2'] - entry_tuples = [ - [Gem::NameTuple.new(a2.name, a2.version, a2.platform), - Gem.sources.first], - ] - - platforms = { a2.version => [a2.platform] } - - entry = @cmd.send :make_entry, entry_tuples, platforms - - assert_equal 'a (2)', entry - end - - # Test for multiple args handling! - def test_execute_multiple_args - spec_fetcher do |fetcher| - fetcher.legacy_platform - end - - @cmd.handle_options %w[a pl] - - use_ui @stub_ui do - @cmd.execute - end - - assert_match %r%^a %, @stub_ui.output - assert_match %r%^pl %, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_show_gems - @cmd.options[:name] = // - @cmd.options[:domain] = :remote - - use_ui @stub_ui do - @cmd.send :show_gems, /a/i - end - - assert_match %r%^a %, @stub_ui.output - refute_match %r%^pl %, @stub_ui.output - assert_empty @stub_ui.error - end - - private - - def add_gems_to_fetcher - spec_fetcher do |fetcher| - fetcher.spec 'a', 1 - fetcher.spec 'a', 2 - fetcher.spec 'a', '3.a' - end - end - -end - -class TestGemCommandsQueryCommandWithoutInstalledGems < Gem::TestCase - - include TestGemCommandsQueryCommandSetup - - def test_execute_platform - spec_fetcher do |fetcher| - fetcher.spec 'a', 1 - fetcher.spec 'a', 1 do |s| - s.platform = 'x86-linux' - end - - fetcher.spec 'a', 2 do |s| - s.platform = 'universal-darwin' - end - end - - @cmd.handle_options %w[-r -a] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -a (2 universal-darwin, 1 ruby x86-linux) - EOF - - assert_equal expected, @stub_ui.output - assert_equal '', @stub_ui.error - end - - def test_execute_show_default_gems - spec_fetcher { |fetcher| fetcher.spec 'a', 2 } - - a1 = new_default_spec 'a', 1 - install_default_specs a1 - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (2, default: 1) -EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_show_default_gems_with_platform - a1 = new_default_spec 'a', 1 - a1.platform = 'java' - install_default_specs a1 - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (default: 1 java) -EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_default_details - spec_fetcher do |fetcher| - fetcher.spec 'a', 2 - end - - a1 = new_default_spec 'a', 1 - install_default_specs a1 - - @cmd.handle_options %w[-l -d] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (2, 1) - Author: A User - Homepage: http://example.com - Installed at (2): #{@gemhome} - (1, default): #{a1.base_dir} - - this is a summary - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_local_details - spec_fetcher do |fetcher| - fetcher.spec 'a', 1 do |s| - s.platform = 'x86-linux' - end - - fetcher.spec 'a', 2 do |s| - s.summary = 'This is a lot of text. ' * 4 - s.authors = ['Abraham Lincoln', 'Hirohito'] - s.homepage = 'http://a.example.com/' - s.platform = 'universal-darwin' - end - - fetcher.legacy_platform - end - - @cmd.handle_options %w[-l -d] - - use_ui @stub_ui do - @cmd.execute - end - - str = @stub_ui.output - - str.gsub!(/\(\d\): [^\n]*/, "-") - str.gsub!(/at: [^\n]*/, "at: -") - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (2, 1) - Platforms: - 1: x86-linux - 2: universal-darwin - Authors: Abraham Lincoln, Hirohito - Homepage: http://a.example.com/ - Installed at - - - - - This is a lot of text. This is a lot of text. This is a lot of text. - This is a lot of text. - -pl (1) - Platform: i386-linux - Author: A User - Homepage: http://example.com - Installed at: - - - this is a summary - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_exact_remote - spec_fetcher do |fetcher| - fetcher.spec 'coolgem-omg', 3 - fetcher.spec 'coolgem', '4.2.1' - fetcher.spec 'wow_coolgem', 1 - end - - @cmd.handle_options %w[--remote --exact coolgem] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** REMOTE GEMS *** - -coolgem (4.2.1) - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_exact_local - spec_fetcher do |fetcher| - fetcher.spec 'coolgem-omg', 3 - fetcher.spec 'coolgem', '4.2.1' - fetcher.spec 'wow_coolgem', 1 - end - - @cmd.handle_options %w[--exact coolgem] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -coolgem (4.2.1) - EOF - - assert_equal expected, @stub_ui.output - end - - def test_execute_exact_multiple - spec_fetcher do |fetcher| - fetcher.spec 'coolgem-omg', 3 - fetcher.spec 'coolgem', '4.2.1' - fetcher.spec 'wow_coolgem', 1 - - fetcher.spec 'othergem-omg', 3 - fetcher.spec 'othergem', '1.2.3' - fetcher.spec 'wow_othergem', 1 - end - - @cmd.handle_options %w[--exact coolgem othergem] - - use_ui @stub_ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -coolgem (4.2.1) - -*** LOCAL GEMS *** - -othergem (1.2.3) - EOF - - assert_equal expected, @stub_ui.output - end - - private - - def add_gems_to_fetcher - spec_fetcher do |fetcher| - fetcher.download 'a', 1 - fetcher.download 'a', 2 - fetcher.download 'a', '3.a' - end - end - -end diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb index c63f7177c7..9dc88d582a 100644 --- a/test/rubygems/test_gem_commands_setup_command.rb +++ b/test/rubygems/test_gem_commands_setup_command.rb @@ -98,6 +98,18 @@ class TestGemCommandsSetupCommand < Gem::TestCase File.join @gemhome, 'bin', name end + def gem_install_with_plugin(name) + gem = util_spec name do |s| + s.files = %W[lib/rubygems_plugin.rb] + end + write_file File.join @tempdir, 'lib', 'rubygems_plugin.rb' do |f| + f.puts "require '#{gem.plugins.first}'" + end + install_gem gem + + File.join Gem.plugins_dir, "#{name}_plugin.rb" + end + def test_execute_regenerate_binstubs gem_bin_path = gem_install 'a' write_file gem_bin_path do |io| @@ -123,6 +135,31 @@ class TestGemCommandsSetupCommand < Gem::TestCase assert_equal "I changed it!\n", File.read(gem_bin_path) end + def test_execute_regenerate_plugins + gem_plugin_path = gem_install_with_plugin 'a' + write_file gem_plugin_path do |io| + io.puts 'I changed it!' + end + + @cmd.options[:document] = [] + @cmd.execute + + assert_match %r{\Arequire}, File.read(gem_plugin_path) + end + + def test_execute_no_regenerate_plugins + gem_plugin_path = gem_install_with_plugin 'a' + write_file gem_plugin_path do |io| + io.puts 'I changed it!' + end + + @cmd.options[:document] = [] + @cmd.options[:regenerate_plugins] = false + @cmd.execute + + assert_equal "I changed it!\n", File.read(gem_plugin_path) + end + def test_execute_informs_about_installed_executables use_ui @ui do @cmd.execute diff --git a/test/rubygems/test_gem_commands_sources_command.rb b/test/rubygems/test_gem_commands_sources_command.rb index b63fbce81f..3a0899245b 100644 --- a/test/rubygems/test_gem_commands_sources_command.rb +++ b/test/rubygems/test_gem_commands_sources_command.rb @@ -247,7 +247,7 @@ source http://gems.example.com/ already present in the cache end def test_execute_add_http_rubygems_org - http_rubygems_org = 'http://rubygems.org' + http_rubygems_org = 'http://rubygems.org/' spec_fetcher do |fetcher| fetcher.spec 'a', 1 @@ -284,6 +284,44 @@ source http://gems.example.com/ already present in the cache assert_empty @ui.error end + def test_execute_add_https_rubygems_org + https_rubygems_org = 'https://rubygems.org/' + + spec_fetcher do |fetcher| + fetcher.spec 'a', 1 + end + + specs = Gem::Specification.map do |spec| + [spec.name, spec.version, spec.original_platform] + end + + specs_dump_gz = StringIO.new + Zlib::GzipWriter.wrap specs_dump_gz do |io| + Marshal.dump specs, io + end + + @fetcher.data["#{https_rubygems_org}/specs.#{@marshal_version}.gz"] = + specs_dump_gz.string + + @cmd.handle_options %W[--add #{https_rubygems_org}] + + ui = Gem::MockGemUi.new "n" + + use_ui ui do + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end + end + + assert_equal [@gem_repo], Gem.sources + + expected = <<-EXPECTED + EXPECTED + + assert_equal expected, @ui.output + assert_empty @ui.error + end + def test_execute_add_bad_uri @cmd.handle_options %w[--add beta-gems.example.com] diff --git a/test/rubygems/test_gem_commands_update_command.rb b/test/rubygems/test_gem_commands_update_command.rb index 37f990ea1a..340c658b9d 100644 --- a/test/rubygems/test_gem_commands_update_command.rb +++ b/test/rubygems/test_gem_commands_update_command.rb @@ -159,6 +159,44 @@ class TestGemCommandsUpdateCommand < Gem::TestCase assert_empty out end + def test_execute_system_specific_older_than_3_2_removes_plugins_dir + spec_fetcher do |fetcher| + fetcher.download 'rubygems-update', 3.1 do |s| + s.files = %w[setup.rb] + end + end + + @cmd.options[:args] = [] + @cmd.options[:system] = "3.1" + + FileUtils.mkdir_p Gem.plugins_dir + write_file File.join(Gem.plugins_dir, 'a_plugin.rb') + + @cmd.execute + + refute_path_exists Gem.plugins_dir, "Plugins folder not removed when updating rubygems to pre-3.2" + end + + def test_execute_system_specific_newer_than_or_equal_to_3_2_leaves_plugins_dir_alone + spec_fetcher do |fetcher| + fetcher.download 'rubygems-update', 3.2 do |s| + s.files = %w[setup.rb] + end + end + + @cmd.options[:args] = [] + @cmd.options[:system] = "3.2" + + FileUtils.mkdir_p Gem.plugins_dir + plugin_file = File.join(Gem.plugins_dir, 'a_plugin.rb') + write_file plugin_file + + @cmd.execute + + assert_path_exists Gem.plugins_dir, "Plugin folder removed when updating rubygems to post-3.2" + assert_path_exists plugin_file, "Plugin removed when updating rubygems to post-3.2" + end + def test_execute_system_specifically_to_latest_version spec_fetcher do |fetcher| fetcher.download 'rubygems-update', 8 do |s| @@ -359,10 +397,10 @@ class TestGemCommandsUpdateCommand < Gem::TestCase end def test_execute_user_install - spec_fetcher do |fetcher| - fetcher.download 'a', 2 - fetcher.spec 'a', 1 - end + a = util_spec "a", 1 + b = util_spec "b", 1 + install_gem_user(a) + install_gem(b) @cmd.handle_options %w[--user-install] @@ -373,7 +411,13 @@ class TestGemCommandsUpdateCommand < Gem::TestCase installer = @cmd.installer user_install = installer.instance_variable_get :@user_install - assert user_install, 'user_install must be set on the installer' + assert user_install, "user_install must be set on the installer" + + out = @ui.output.split "\n" + assert_equal "Updating installed gems", out.shift + assert_equal "Updating a", out.shift + assert_equal "Gems updated: a", out.shift + assert_empty out end def test_fetch_remote_gems diff --git a/test/rubygems/test_gem_config_file.rb b/test/rubygems/test_gem_config_file.rb index 492a0c5a05..8ea8fa61e5 100644 --- a/test/rubygems/test_gem_config_file.rb +++ b/test/rubygems/test_gem_config_file.rb @@ -11,10 +11,6 @@ class TestGemConfigFile < Gem::TestCase @cfg_args = %W[--config-file #{@temp_conf}] - @orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE - Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE - Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE, - File.join(@tempdir, 'system-gemrc') Gem::ConfigFile::OPERATING_SYSTEM_DEFAULTS.clear Gem::ConfigFile::PLATFORM_DEFAULTS.clear @@ -27,9 +23,6 @@ class TestGemConfigFile < Gem::TestCase def teardown Gem::ConfigFile::OPERATING_SYSTEM_DEFAULTS.clear Gem::ConfigFile::PLATFORM_DEFAULTS.clear - Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE - Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE, - @orig_SYSTEM_WIDE_CONFIG_FILE ENV['GEMRC'] = @env_gemrc diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb index 22f3a9158f..487b8290bb 100644 --- a/test/rubygems/test_gem_dependency_installer.rb +++ b/test/rubygems/test_gem_dependency_installer.rb @@ -440,7 +440,7 @@ class TestGemDependencyInstaller < Gem::TestCase e1 = util_spec 'e', '1', nil, 'extconf.rb' do |s| s.extensions << 'extconf.rb' end - e1_gem = File.join @tempdir, 'gems', "#{e1.full_name}.gem" + e1_gem = e1.cache_file _, f1_gem = util_gem 'f', '1', 'e' => nil diff --git a/test/rubygems/test_gem_doctor.rb b/test/rubygems/test_gem_doctor.rb index a0e3a18d7f..75d406ac88 100644 --- a/test/rubygems/test_gem_doctor.rb +++ b/test/rubygems/test_gem_doctor.rb @@ -153,6 +153,34 @@ This directory does not appear to be a RubyGems repository, skipping assert true # count end + def test_doctor_badly_named_plugins + gem 'a' + + Gem.use_paths @gemhome.to_s + + FileUtils.mkdir_p Gem.plugins_dir + bad_plugin = File.join(Gem.plugins_dir, "a_badly_named_file.rb") + write_file bad_plugin + + doctor = Gem::Doctor.new @gemhome + + capture_io do + use_ui @ui do + doctor.doctor + end + end + + # refute_path_exists bad_plugin + + expected = <<-OUTPUT +Checking #{@gemhome} +Removed file plugins/a_badly_named_file.rb + + OUTPUT + + assert_equal expected, @ui.output + end + def test_gem_repository_eh doctor = Gem::Doctor.new @gemhome diff --git a/test/rubygems/test_gem_gem_runner.rb b/test/rubygems/test_gem_gem_runner.rb index efde71dce6..71b792c957 100644 --- a/test/rubygems/test_gem_gem_runner.rb +++ b/test/rubygems/test_gem_gem_runner.rb @@ -67,4 +67,34 @@ class TestGemGemRunner < Gem::TestCase assert_equal %w[--foo], args end + def test_info_succeeds + args = %w[info] + + use_ui @ui do + assert_nil @runner.run(args) + end + + assert_empty @ui.error + end + + def test_list_succeeds + args = %w[list] + + use_ui @ui do + assert_nil @runner.run(args) + end + + assert_empty @ui.error + end + + def test_search_succeeds + args = %w[search] + + use_ui @ui do + assert_nil @runner.run(args) + end + + assert_empty @ui.error + end + end diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 731a1ac01d..eaeff4a8fc 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -744,6 +744,70 @@ gem 'other', version assert_match(/#{default_shebang}/, shebang_line) end + def test_generate_plugins + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |io| + io.write "puts __FILE__" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + build_rake_in do + installer.install + end + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + + FileUtils.rm plugin_path + + installer.generate_plugins + + assert File.exist?(plugin_path), 'plugin not written' + end + + def test_keeps_plugins_up_to_date + # NOTE: version a-2 is already installed by setup hooks + + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |io| + io.write "puts __FILE__" + end + + build_rake_in do + util_setup_installer do |spec| + spec.version = '1' + spec.files += %w[lib/rubygems_plugin.rb] + end.install + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + refute File.exist?(plugin_path), 'old version installed while newer version without plugin also installed, but plugin written' + + util_setup_installer do |spec| + spec.version = '2' + spec.files += %w[lib/rubygems_plugin.rb] + end.install + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + assert File.exist?(plugin_path), 'latest version reinstalled, but plugin not written' + assert_match %r{\Arequire.*a-2/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'written plugin has incorrect content' + + util_setup_installer do |spec| + spec.version = '3' + spec.files += %w[lib/rubygems_plugin.rb] + end.install + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + assert File.exist?(plugin_path), 'latest version installed, but plugin removed' + assert_match %r{\Arequire.*a-3/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'written plugin has incorrect content' + + util_setup_installer do |spec| + spec.version = '4' + end.install + + refute File.exist?(plugin_path), 'new version installed without a plugin while older version with a plugin installed, but plugin not removed' + end + end + def test_initialize spec = util_spec 'a' do |s| s.platform = Gem::Platform.new 'mswin32' @@ -940,7 +1004,13 @@ gem 'other', version end def test_install_creates_binstub_that_prefers_user_installed_gem_to_default - install_default_gems new_default_spec('default', '2') + default_spec = new_default_spec('default', '2', nil, 'exe/executable') + default_spec.executables = 'executable' + install_default_gems default_spec + + exe = File.join @gemhome, 'bin', 'executable' + + assert_path_exists exe, "default gem's executable not installed" installer = util_setup_installer do |spec| spec.name = 'default' @@ -958,8 +1028,6 @@ gem 'other', version end end - exe = File.join @gemhome, 'bin', 'executable' - e = assert_raises RuntimeError do instance_eval File.read(exe) end diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index 76a66af867..7f773febbc 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -153,20 +153,18 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== assert_equal proxy_uri, fetcher.instance_variable_get(:@proxy).to_s end - def test_fetch_size_bad_uri + def test_fetch_path_bad_uri fetcher = Gem::RemoteFetcher.new nil @fetcher = fetcher e = assert_raises ArgumentError do - Gem::Deprecate.skip_during do - fetcher.fetch_size 'gems.example.com/yaml' - end + @fetcher.fetch_path("gems.example.com/yaml", nil, true) end assert_equal 'uri scheme is invalid: nil', e.message end - def test_fetch_size_socket_error + def test_fetch_path_socket_error fetcher = Gem::RemoteFetcher.new nil @fetcher = fetcher def fetcher.request(uri, request_class, last_modified = nil) @@ -175,9 +173,7 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== uri = 'http://gems.example.com/yaml' e = assert_raises Gem::RemoteFetcher::FetchError do - Gem::Deprecate.skip_during do - fetcher.fetch_size uri - end + @fetcher.fetch_path(uri, nil, true) end assert_equal "SocketError: oops (#{uri})", e.message @@ -186,9 +182,8 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== def test_no_proxy use_ui @stub_ui do assert_data_from_server @fetcher.fetch_path(@server_uri) - Gem::Deprecate.skip_during do - assert_equal SERVER_DATA.size, @fetcher.fetch_size(@server_uri) - end + response = @fetcher.fetch_path(@server_uri, nil, true) + assert_equal SERVER_DATA.size, response['content-length'].to_i end end @@ -917,7 +912,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== end def test_ssl_client_cert_auth_connection - skip 'openssl is missing' unless defined?(OpenSSL::SSL) skip 'openssl in jruby fails' if java_platform? ssl_server = self.class.start_ssl_server({ @@ -935,8 +929,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== end def test_do_not_allow_invalid_client_cert_auth_connection - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - ssl_server = self.class.start_ssl_server({ :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT}) @@ -1083,9 +1075,6 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== DIR = File.expand_path(File.dirname(__FILE__)) def start_ssl_server(config = {}) - raise MiniTest::Skip, 'openssl not installed' unless - defined?(OpenSSL::SSL) - null_logger = NilLog.new server = WEBrick::HTTPServer.new({ :Port => 0, @@ -1109,8 +1098,8 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg== begin server.start rescue Exception => ex - abort ex.message puts "ERROR during server thread: #{ex.message}" + raise ensure server.shutdown end diff --git a/test/rubygems/test_gem_request_set.rb b/test/rubygems/test_gem_request_set.rb index ac344015e7..fb71829471 100644 --- a/test/rubygems/test_gem_request_set.rb +++ b/test/rubygems/test_gem_request_set.rb @@ -183,6 +183,58 @@ DEPENDENCIES assert_path_exists File.join @gemhome, 'specifications', 'b-1.gemspec' end + def test_install_from_gemdeps_complex_dependencies + quick_gem("z", 1) + quick_gem("z", "1.0.1") + quick_gem("z", "1.0.2") + quick_gem("z", "1.0.3") + quick_gem("z", 2) + + spec_fetcher do |fetcher| + fetcher.download "z", 1 + end + + rs = Gem::RequestSet.new + installed = [] + + File.open 'Gemfile.lock', 'w' do |io| + io.puts <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + z (1) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + z (~> 1.0, >= 1.0.1) + LOCKFILE + end + + File.open 'testo.gemspec', 'w' do |io| + io.puts <<-LOCKFILE +Gem::Specification.new do |spec| + spec.name = 'testo' + spec.version = '1.0.0' + spec.add_dependency('z', '~> 1.0', '>= 1.0.1') +end + LOCKFILE + end + + File.open 'Gemfile', 'w' do |io| + io.puts("gemspec") + end + + rs.install_from_gemdeps :gemdeps => 'Gemfile' do |req, installer| + installed << req.full_name + end + + assert_includes installed, 'z-1.0.3' + + assert_path_exists File.join @gemhome, 'specifications', 'z-1.0.3.gemspec' + end + def test_install_from_gemdeps_version_mismatch spec_fetcher do |fetcher| fetcher.gem 'a', 2 diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index dbd45a31fd..b7df8b71fd 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -2784,7 +2784,7 @@ end add_runtime_dependency 'l', '~> 1.2', '> 1.2.3' #{w}: open-ended dependency on o (>= 0) is not recommended use a bounded requirement, such as '~> x.y' -#{w}: See http://guides.rubygems.org/specification-reference/ for help +#{w}: See https://guides.rubygems.org/specification-reference/ for help EXPECTED assert_equal expected, @ui.error, 'warning' @@ -2816,7 +2816,7 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end assert_equal <<-EXPECTED, @ui.error -#{w}: See http://guides.rubygems.org/specification-reference/ for help +#{w}: See https://guides.rubygems.org/specification-reference/ for help EXPECTED end end @@ -2927,7 +2927,7 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end end - assert_match 'See http://guides.rubygems.org/specification-reference/ for help', @ui.error + assert_match 'See https://guides.rubygems.org/specification-reference/ for help', @ui.error end def test_validate_executables @@ -3100,7 +3100,7 @@ Please report a bug if this causes problems. assert_equal '"ftp://rubygems.org" is not a valid HTTP URI', e.message - @a1.homepage = 'http://rubygems.org' + @a1.homepage = 'https://rubygems.org/' assert_equal true, @a1.validate @a1.homepage = 'https://rubygems.org' @@ -3430,7 +3430,7 @@ Did you mean 'Ruby'? @a1.validate end - assert_match 'See http://guides.rubygems.org/specification-reference/ for help', @ui.error + assert_match 'See https://guides.rubygems.org/specification-reference/ for help', @ui.error end def test_version @@ -3532,7 +3532,8 @@ Did you mean 'Ruby'? s.metadata = { "one" => "two", "home" => "three", - "homepage_uri" => "https://example.com/user/repo" + "homepage_uri" => "https://example.com/user/repo", + "funding_uri" => "https://example.com/donate" } end diff --git a/test/rubygems/test_gem_uninstaller.rb b/test/rubygems/test_gem_uninstaller.rb index bf5ef5b4a2..df8dfd9a95 100644 --- a/test/rubygems/test_gem_uninstaller.rb +++ b/test/rubygems/test_gem_uninstaller.rb @@ -169,6 +169,41 @@ class TestGemUninstaller < Gem::InstallerTestCase end end + def test_remove_plugins + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |io| + io.write "puts __FILE__" + end + + @spec.files += %w[lib/rubygems_plugin.rb] + + Gem::Installer.at(Gem::Package.build(@spec)).install + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + assert File.exist?(plugin_path), 'plugin not written' + + Gem::Uninstaller.new(nil).remove_plugins @spec + + refute File.exist?(plugin_path), 'plugin not removed' + end + + def test_regenerate_plugins_for + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |io| + io.write "puts __FILE__" + end + + @spec.files += %w[lib/rubygems_plugin.rb] + + Gem::Installer.at(Gem::Package.build(@spec)).install + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + assert File.exist?(plugin_path), 'plugin not written' + + FileUtils.rm plugin_path + Gem::Uninstaller.new(nil).regenerate_plugins_for @spec + + assert File.exist?(plugin_path), 'plugin not regenerated' + end + def test_path_ok_eh uninstaller = Gem::Uninstaller.new nil @@ -524,6 +559,35 @@ create_makefile '#{@spec.name}' assert_match %r!Successfully uninstalled q-1!, lines.last end + def test_uninstall_prompt_only_lists_the_dependents_that_prevented_uninstallation + quick_gem 'r', '1' do |s| + s.add_development_dependency 'q', '= 1' + end + + quick_gem 's', '1' do |s| + s.add_dependency 'q', '= 1' + end + + quick_gem 'q', '1' + + un = Gem::Uninstaller.new('q', :check_dev => false) + ui = Gem::MockGemUi.new("y\n") + + use_ui ui do + un.uninstall + end + + lines = ui.output.split("\n") + lines.shift + + assert_match %r!You have requested to uninstall the gem:!, lines.shift + lines.shift + lines.shift + + assert_match %r!s-1 depends on q \(= 1\)!, lines.shift + assert_match %r!Successfully uninstalled q-1!, lines.last + end + def test_uninstall_no_permission uninstaller = Gem::Uninstaller.new @spec.name, :executables => true @@ -542,4 +606,44 @@ create_makefile '#{@spec.name}' end end + def test_uninstall_keeps_plugins_up_to_date + write_file File.join(@tempdir, 'lib', 'rubygems_plugin.rb') do |io| + io.write "puts __FILE__" + end + + plugin_path = File.join Gem.plugins_dir, 'a_plugin.rb' + + @spec.version = '1' + Gem::Installer.at(Gem::Package.build(@spec)).install + + refute File.exist?(plugin_path), 'version without plugin installed, but plugin written' + + @spec.files += %w[lib/rubygems_plugin.rb] + @spec.version = '2' + Gem::Installer.at(Gem::Package.build(@spec)).install + + assert File.exist?(plugin_path), 'version with plugin installed, but plugin not written' + assert_match %r{\Arequire.*a-2/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'written plugin has incorrect content' + + @spec.version = '3' + Gem::Installer.at(Gem::Package.build(@spec)).install + + assert File.exist?(plugin_path), 'version with plugin installed, but plugin removed' + assert_match %r{\Arequire.*a-3/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'old version installed, but plugin updated' + + Gem::Uninstaller.new('a', :version => '1', :executables => true).uninstall + + assert File.exist?(plugin_path), 'plugin removed when old version uninstalled' + assert_match %r{\Arequire.*a-3/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'old version uninstalled, but plugin updated' + + Gem::Uninstaller.new('a', version: '3', :executables => true).uninstall + + assert File.exist?(plugin_path), 'plugin removed when old version uninstalled and another version with plugin still present' + assert_match %r{\Arequire.*a-2/lib/rubygems_plugin\.rb}, File.read(plugin_path), 'latest version uninstalled, but plugin not updated to previous version' + + Gem::Uninstaller.new('a', version: '2', :executables => true).uninstall + + refute File.exist?(plugin_path), 'last version uninstalled, but plugin still present' + end + end diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb index 1deecc0eed..30b9376e30 100644 --- a/test/rubygems/test_gem_version.rb +++ b/test/rubygems/test_gem_version.rb @@ -236,7 +236,7 @@ class TestGemVersion < Gem::TestCase assert_equal expected, v(version).approximate_recommendation end - # Assert that the "approximate" recommendation for +version+ satifies +version+. + # Assert that the "approximate" recommendation for +version+ satisfies +version+. def assert_approximate_satisfies_itself(version) gem_version = v(version) -- cgit v1.2.3