From 69934aeb8d7948c4ca590b7092504c41d8bce6ac Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 28 Sep 2016 00:57:53 +0000 Subject: rubygems 2.6.7 * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems to 2.6.7. Release note of 2.6.7: https://github.com/rubygems/rubygems/commit/60f35bd1d2359fc30301d2d4cd72bc6833e8d12a git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56277 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rubygems.rb | 53 +++---- lib/rubygems/commands/owner_command.rb | 4 +- lib/rubygems/commands/push_command.rb | 3 +- lib/rubygems/commands/query_command.rb | 27 ++-- lib/rubygems/commands/setup_command.rb | 159 ++++++++++++--------- lib/rubygems/commands/yank_command.rb | 3 +- lib/rubygems/config_file.rb | 6 +- lib/rubygems/core_ext/kernel_require.rb | 12 +- lib/rubygems/exceptions.rb | 6 + lib/rubygems/installer.rb | 16 ++- lib/rubygems/remote_fetcher.rb | 3 + lib/rubygems/request_set.rb | 23 ++- lib/rubygems/resolver.rb | 25 +++- .../molinillo/lib/molinillo/gem_metadata.rb | 2 +- .../resolver/molinillo/lib/molinillo/resolution.rb | 10 +- lib/rubygems/source.rb | 6 +- lib/rubygems/spec_fetcher.rb | 10 +- lib/rubygems/test_case.rb | 14 +- lib/rubygems/user_interaction.rb | 28 ++-- lib/rubygems/version.rb | 18 ++- 20 files changed, 280 insertions(+), 148 deletions(-) (limited to 'lib') diff --git a/lib/rubygems.rb b/lib/rubygems.rb index ce9dc6a66a..487d7de2ff 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -10,7 +10,7 @@ require 'rbconfig' require 'thread' module Gem - VERSION = '2.6.6' + VERSION = '2.6.7' end # Must be first since it unloads the prelude from 1.9.2 @@ -296,7 +296,10 @@ module Gem def self.activate_bin_path name, exec_name, requirement # :nodoc: spec = find_spec_for_exe name, exec_name, [requirement] - Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate } + Gem::LOADED_SPECS_MUTEX.synchronize do + spec.activate + finish_resolve + end spec.bin_file exec_name end @@ -593,7 +596,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Zlib::GzipReader wrapper that unzips +data+. def self.gunzip(data) - require 'rubygems/util' Gem::Util.gunzip data end @@ -601,7 +603,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Zlib::GzipWriter wrapper that zips +data+. def self.gzip(data) - require 'rubygems/util' Gem::Util.gzip data end @@ -609,7 +610,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # A Zlib::Inflate#inflate wrapper def self.inflate(data) - require 'rubygems/util' Gem::Util.inflate data end @@ -971,7 +971,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # default_sources if the sources list is empty. def self.sources - @sources ||= Gem::SourceList.from(default_sources) + source_list = configuration.sources || default_sources + @sources ||= Gem::SourceList.from(source_list) end ## @@ -1146,8 +1147,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} path = path.dup if path == "-" then - require 'rubygems/util' - Gem::Util.traverse_parents Dir.pwd do |directory| dep_file = GEM_DEP_FILES.find { |f| File.file?(f) } @@ -1166,18 +1165,24 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} raise ArgumentError, "Unable to find gem dependencies file at #{path}" end - rs = Gem::RequestSet.new - @gemdeps = rs.load_gemdeps path - - rs.resolve_current.map do |s| - sp = s.full_spec - sp.activate - sp + ENV["BUNDLE_GEMFILE"] ||= File.expand_path(path) + require 'rubygems/user_interaction' + Gem::DefaultUserInteraction.use_ui(ui) do + require "bundler/postit_trampoline" unless ENV["BUNDLE_DISABLE_POSTIT"] + require "bundler" + @gemdeps = Bundler.setup + Bundler.ui = nil + @gemdeps.requested_specs.map(&:to_spec).sort_by(&:name) + end + rescue => e + case e + when Gem::LoadError, Gem::UnsatisfiableDependencyError, (defined?(Bundler::GemNotFound) ? Bundler::GemNotFound : Gem::LoadError) + warn e.message + warn "You may need to `gem install -g` to install missing gems" + warn "" + else + raise end - rescue Gem::LoadError, Gem::UnsatisfiableDependencyError => e - warn e.message - warn "You may need to `gem install -g` to install missing gems" - warn "" end class << self @@ -1223,6 +1228,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} prefix_pattern = /^(#{prefix_group})/ end + suffix_pattern = /#{Regexp.union(Gem.suffixes)}\z/ + spec.files.each do |file| if new_format file = file.sub(prefix_pattern, "") @@ -1230,6 +1237,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} end @path_to_default_spec_map[file] = spec + @path_to_default_spec_map[file.sub(suffix_pattern, "")] = spec end end @@ -1237,11 +1245,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Find a Gem::Specification of default gem from +path+ def find_unresolved_default_spec(path) - Gem.suffixes.each do |suffix| - spec = @path_to_default_spec_map["#{path}#{suffix}"] - return spec if spec - end - nil + @path_to_default_spec_map[path] end ## @@ -1327,6 +1331,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} autoload :SourceList, 'rubygems/source_list' autoload :SpecFetcher, 'rubygems/spec_fetcher' autoload :Specification, 'rubygems/specification' + autoload :Util, 'rubygems/util' autoload :Version, 'rubygems/version' require "rubygems/specification" diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb index 4b99434e87..8e2271657a 100644 --- a/lib/rubygems/commands/owner_command.rb +++ b/lib/rubygems/commands/owner_command.rb @@ -40,7 +40,9 @@ permission to. options[:remove] << value end - add_option '-h', '--host HOST', 'Use another gemcutter-compatible host' do |value, options| + add_option '-h', '--host HOST', + 'Use another gemcutter-compatible host', + ' (e.g. https://rubygems.org)' do |value, options| options[:host] = value end end diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb index 6adeff6b30..d294cbc8df 100644 --- a/lib/rubygems/commands/push_command.rb +++ b/lib/rubygems/commands/push_command.rb @@ -33,7 +33,8 @@ command. For further discussion see the help for the yank command. add_key_option add_option('--host HOST', - 'Push to another gemcutter-compatible host') do |value, options| + 'Push to another gemcutter-compatible host', + ' (e.g. https://rubygems.org)') do |value, options| options[:host] = value end diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb index f25d120b88..813154fa23 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -255,22 +255,21 @@ is too hard to use. name_tuples.map { |n| n.version }.uniq else platforms.sort.reverse.map do |version, pls| - if pls == [Gem::Platform::RUBY] then - if options[:domain] == :remote || specs.all? { |spec| spec.is_a? Gem::Source } - version - else - spec = specs.select { |s| s.version == version } - if spec.first.default_gem? - "default: #{version}" - else - version - end + 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 - else - ruby = pls.delete Gem::Platform::RUBY - platform_list = [ruby, *pls.sort].compact - "#{version} #{platform_list.join ' '}" + out = "default: #{out}" if default + end + + if pls != [Gem::Platform::RUBY] then + platform_list = [pls.delete(Gem::Platform::RUBY), *pls.sort].compact + out = platform_list.unshift(out).join(' ') end + + out end end diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index ebb08d24d7..1fff2a7dcb 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -142,6 +142,8 @@ By default, this RubyGems will install gem as: remove_old_lib_files lib_dir + install_default_gemspec + say "RubyGems #{Gem::VERSION} installed" uninstall_old_gemcutter @@ -202,59 +204,65 @@ By default, this RubyGems will install gem as: end end - def install_executables(bin_dir) - say "Installing gem executable" if @verbose + def install_executables(bin_dir) @bin_file_names = [] - Dir.chdir 'bin' do - bin_files = Dir['*'] - - bin_files.delete 'update_rubygems' - - bin_files.each do |bin_file| - bin_file_formatted = if options[:format_executable] then - Gem.default_exec_format % bin_file - else - bin_file - end + { + 'gem' => 'bin', + 'bundler' => 'bundler/exe', + }.each do |tool, path| + say "Installing #{tool} executable" if @verbose - dest_file = File.join bin_dir, bin_file_formatted - bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}" + Dir.chdir path do + bin_files = Dir['*'] - begin - bin = File.readlines bin_file - bin[0] = "#!#{Gem.ruby}\n" + bin_files -= %w[update_rubygems bundler bundle_ruby] - File.open bin_tmp_file, 'w' do |fp| - fp.puts bin.join - end + bin_files.each do |bin_file| + bin_file_formatted = if options[:format_executable] then + Gem.default_exec_format % bin_file + else + bin_file + end - install bin_tmp_file, dest_file, :mode => 0755 - @bin_file_names << dest_file - ensure - rm bin_tmp_file - end + dest_file = File.join bin_dir, bin_file_formatted + bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}" - next unless Gem.win_platform? + begin + bin = File.readlines bin_file + bin[0] = "#!#{Gem.ruby}\n" - begin - bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat" + File.open bin_tmp_file, 'w' do |fp| + fp.puts bin.join + end - File.open bin_cmd_file, 'w' do |file| - file.puts <<-TEXT -@ECHO OFF -IF NOT "%~f0" == "~f0" GOTO :WinNT -@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9 -GOTO :EOF -:WinNT -@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %* -TEXT + install bin_tmp_file, dest_file, :mode => 0755 + @bin_file_names << dest_file + ensure + rm bin_tmp_file end - install bin_cmd_file, "#{dest_file}.bat", :mode => 0755 - ensure - rm bin_cmd_file + next unless Gem.win_platform? + + begin + bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat" + + File.open bin_cmd_file, 'w' do |file| + file.puts <<-TEXT + @ECHO OFF + IF NOT "%~f0" == "~f0" GOTO :WinNT + @"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9 + GOTO :EOF + :WinNT + @"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %* + TEXT + end + + install bin_cmd_file, "#{dest_file}.bat", :mode => 0755 + ensure + rm bin_cmd_file + end end end end @@ -269,18 +277,23 @@ TEXT end def install_lib(lib_dir) - say "Installing RubyGems" if @verbose - - lib_files = rb_files_in 'lib' - pem_files = pem_files_in 'lib' - - Dir.chdir 'lib' do - lib_files.each do |lib_file| - install_file lib_file, lib_dir - end + { + 'RubyGems' => 'lib', + 'Bundler' => 'bundler/lib' + }.each do |tool, path| + say "Installing #{tool}" if @verbose + + lib_files = rb_files_in path + pem_files = pem_files_in path + + Dir.chdir path do + lib_files.each do |lib_file| + install_file lib_file, lib_dir + end - pem_files.each do |pem_file| - install_file pem_file, lib_dir + pem_files.each do |pem_file| + install_file pem_file, lib_dir + end end end end @@ -326,6 +339,19 @@ TEXT return false end + def install_default_gemspec + Dir.chdir("bundler") do + bundler_spec = Gem::Specification.load("bundler.gemspec") + bundler_spec.files = Dir["{*.md,{lib,exe,man}/**/*}"] + bundler_spec.executables -= %w[bundler bundle_ruby] + Dir.entries(Gem::Specification.default_specifications_dir). + select {|gs| gs.start_with?("bundler-") }. + each {|gs| File.delete(File.join(Gem::Specification.default_specifications_dir, gs)) } + default_spec_path = File.join(Gem::Specification.default_specifications_dir, "#{bundler_spec.full_name}.gemspec") + Gem.write_binary(default_spec_path, bundler_spec.to_ruby) + end + end + def make_destination_dirs(install_destdir) lib_dir, bin_dir = Gem.default_rubygems_dirs @@ -416,23 +442,27 @@ abort "#{deprecation_message}" end def remove_old_lib_files lib_dir - rubygems_dir = File.join lib_dir, 'rubygems' - lib_files = rb_files_in 'lib/rubygems' + { + File.join(lib_dir, 'rubygems') => 'lib/rubygems', + File.join(lib_dir, 'bundler') => 'bundler/lib/bundler', + }.each do |old_lib_dir, new_lib_dir| + lib_files = rb_files_in(new_lib_dir) - old_lib_files = rb_files_in rubygems_dir + old_lib_files = rb_files_in(old_lib_dir) - to_remove = old_lib_files - lib_files + to_remove = old_lib_files - lib_files - to_remove.delete_if do |file| - file.start_with? 'defaults' - end + to_remove.delete_if do |file| + file.start_with? 'defaults' + end - Dir.chdir rubygems_dir do - to_remove.each do |file| - FileUtils.rm_f file + Dir.chdir old_lib_dir do + to_remove.each do |file| + FileUtils.rm_f file - warn "unable to remove old file #{file} please remove it by hand" if - File.exist? file + warn "unable to remove old file #{file} please remove it by hand" if + File.exist? file + end end end end @@ -481,4 +511,3 @@ abort "#{deprecation_message}" end end - diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb index 0d6575b272..36809cbd57 100644 --- a/lib/rubygems/commands/yank_command.rb +++ b/lib/rubygems/commands/yank_command.rb @@ -42,7 +42,8 @@ as the reason for the removal request. add_platform_option("remove") add_option('--host HOST', - 'Yank from another gemcutter-compatible host') do |value, options| + 'Yank from another gemcutter-compatible host', + ' (e.g. https://rubygems.org)') do |value, options| options[:host] = value end diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 3a5e7718df..c95d7dd1f1 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -143,6 +143,10 @@ class Gem::ConfigFile attr_accessor :ssl_ca_cert + ## + # sources to look for gems + attr_accessor :sources + ## # Path name of directory or file of openssl client certificate, used for remote https connection with client authentication @@ -216,6 +220,7 @@ class Gem::ConfigFile @update_sources = @hash[:update_sources] if @hash.key? :update_sources @verbose = @hash[:verbose] if @hash.key? :verbose @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server + @sources = @hash[:sources] if @hash.key? :sources @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert @@ -224,7 +229,6 @@ class Gem::ConfigFile @api_keys = nil @rubygems_api_key = nil - Gem.sources = @hash[:sources] if @hash.key? :sources handle_arguments arg_list end diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index aa56ab5ec4..d23a6fe90a 100755 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -41,8 +41,7 @@ module Kernel path = path.to_path if path.respond_to? :to_path - spec = Gem.find_unresolved_default_spec(path) - if spec + if spec = Gem.find_unresolved_default_spec(path) Gem.remove_unresolved_default_spec(spec) gem(spec.name) end @@ -61,12 +60,10 @@ module Kernel #-- # TODO request access to the C implementation of this to speed up RubyGems - spec = Gem::Specification.find_active_stub_by_path path - - begin + if Gem::Specification.find_active_stub_by_path(path) RUBYGEMS_ACTIVATION_MONITOR.exit return gem_original_require(path) - end if spec + end # Attempt to find +path+ in any unresolved gems... @@ -104,7 +101,7 @@ module Kernel # Ok, now find a gem that has no conflicts, starting # at the highest version. - valid = found_specs.reject { |s| s.has_conflicts? }.first + valid = found_specs.find { |s| !s.has_conflicts? } unless valid then le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate" @@ -138,4 +135,3 @@ module Kernel private :require end - diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 9089eae4d5..b7528761fc 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -154,6 +154,12 @@ class Gem::ImpossibleDependenciesError < Gem::Exception end class Gem::InstallError < Gem::Exception; end +class Gem::RuntimeRequirementNotMetError < Gem::InstallError + attr_accessor :suggestion + def message + [suggestion, super].compact.join("\n\t") + end +end ## # Potentially raised when a specification is validated. diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 6e77185547..bd2eed19de 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -282,18 +282,23 @@ class Gem::Installer run_pre_install_hooks + # Set loaded_from to ensure extension_dir is correct + if @options[:install_as_default] then + spec.loaded_from = default_spec_file + else + spec.loaded_from = spec_file + end + # Completely remove any previous gem files FileUtils.rm_rf gem_dir FileUtils.rm_rf spec.extension_dir FileUtils.mkdir_p gem_dir - if @options[:install_as_default] - spec.loaded_from = default_spec_file + if @options[:install_as_default] then extract_bin write_default_spec else - spec.loaded_from = spec_file extract_files build_extensions @@ -603,7 +608,8 @@ class Gem::Installer def ensure_required_ruby_version_met # :nodoc: if rrv = spec.required_ruby_version then unless rrv.satisfied_by? Gem.ruby_version then - raise Gem::InstallError, "#{spec.name} requires Ruby version #{rrv}." + raise Gem::RuntimeRequirementNotMetError, + "#{spec.name} requires Ruby version #{rrv}." end end end @@ -611,7 +617,7 @@ class Gem::Installer def ensure_required_rubygems_version_met # :nodoc: if rrgv = spec.required_rubygems_version then unless rrgv.satisfied_by? Gem.rubygems_version then - raise Gem::InstallError, + raise Gem::RuntimeRequirementNotMetError, "#{spec.name} requires RubyGems version #{rrgv}. " + "Try 'gem update --system' to update RubyGems itself." end diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index da4db724a1..e6a13d4b8c 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -260,6 +260,9 @@ class Gem::RemoteFetcher Net::HTTPTemporaryRedirect then raise FetchError.new('too many redirects', uri) if depth > 10 + unless location = response['Location'] + raise FetchError.new("redirecting but no redirect location was given", uri) + end location = URI.parse response['Location'] if https?(uri) && !https?(location) diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 5541e64b88..49e56ae6fb 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -163,9 +163,26 @@ class Gem::RequestSet end end - spec = req.spec.install options do |installer| - yield req, installer if block_given? - end + spec = + begin + req.spec.install options do |installer| + yield req, installer if block_given? + end + rescue Gem::RuntimeRequirementNotMetError => e + recent_match = req.spec.set.find_all(req.request).sort_by(&:version).reverse_each.find do |s| + s = s.spec + s.required_ruby_version.satisfied_by?(Gem.ruby_version) && s.required_rubygems_version.satisfied_by?(Gem.rubygems_version) + end + if recent_match + suggestion = "The last version of #{req.request} to support your ruby & rubygems was #{recent_match.version}. Try installing it with `gem install #{recent_match.name} -v #{recent_match.version}`" + suggestion += " and then running the current command again" unless @always_install.any? { |spec| spec == req.spec.spec } + else + suggestion = "There are no versions of #{req.request} compatible with your ruby & rubygems" + suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.any? { |spec| spec == req.spec.spec } + end + e.suggestion = suggestion + raise + end requests << spec end diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb index 50a547e1be..0a3276daab 100644 --- a/lib/rubygems/resolver.rb +++ b/lib/rubygems/resolver.rb @@ -233,8 +233,29 @@ class Gem::Resolver exc.errors = @set.errors raise exc end - possibles.sort_by { |s| [s.source, s.version, Gem::Platform.local =~ s.platform ? 1 : 0] }. - map { |s| ActivationRequest.new s, dependency, [] } + + sources = [] + + groups = Hash.new { |hash, key| hash[key] = [] } + + possibles.each do |spec| + source = spec.source + + sources << source unless sources.include? source + + groups[source] << spec + end + + activation_requests = [] + + sources.sort.each do |source| + groups[source]. + sort_by { |spec| [spec.version, Gem::Platform.local =~ spec.platform ? 1 : 0] }. + map { |spec| ActivationRequest.new spec, dependency, [] }. + each { |activation_request| activation_requests << activation_request } + end + + activation_requests end def dependencies_for(specification) diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb index 1a82da0e7a..4170b00af0 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # The version of Gem::Resolver::Molinillo. - VERSION = '0.5.0'.freeze + VERSION = '0.5.1'.freeze end diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb index 1fb7a1e921..e6565119ef 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb @@ -184,6 +184,8 @@ module Gem::Resolver::Molinillo raise VersionConflict.new(c) unless state activated.rewind_to(sliced_states.first || :initial_state) if sliced_states state.conflicts = c + index = states.size - 1 + @parent_of.reject! { |_, i| i >= index } end end @@ -209,7 +211,10 @@ module Gem::Resolver::Molinillo # @return [Object] the requirement that led to `requirement` being added # to the list of requirements. def parent_of(requirement) - @parent_of[requirement] + return unless requirement + return unless index = @parent_of[requirement] + return unless parent_state = @states[index] + parent_state.requirement end # @return [Object] the requirement that led to a version of a possibility @@ -418,7 +423,8 @@ module Gem::Resolver::Molinillo debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each do |d| activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d) - @parent_of[d] = requirement + parent_index = states.size - 1 + @parent_of[d] ||= parent_index end push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?) diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index 85f5268fa3..4f07beb1f4 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -67,7 +67,11 @@ class Gem::Source return -1 if !other.uri - @uri.to_s <=> other.uri.to_s + # Returning 1 here ensures that when sorting a list of sources, the + # original ordering of sources supplied by the user is preserved. + return 1 unless @uri.to_s == other.uri.to_s + + 0 else nil end diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 755d4be1eb..919276e113 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -184,10 +184,10 @@ class Gem::SpecFetcher # Suggests gems based on the supplied +gem_name+. Returns an array of # alternative gem names. - def suggest_gems_from_name gem_name + def suggest_gems_from_name(gem_name, type = :latest) gem_name = gem_name.downcase.tr('_-', '') max = gem_name.size / 2 - names = available_specs(:latest).first.values.flatten(1) + names = available_specs(type).first.values.flatten(1) matches = names.map { |n| next unless n.match_platform? @@ -201,7 +201,11 @@ class Gem::SpecFetcher [n.name, distance] }.compact - matches = matches.uniq.sort_by { |name, dist| dist } + matches = if matches.empty? && type != :prerelease + suggest_gems_from_name gem_name, :prerelease + else + matches.uniq.sort_by { |name, dist| dist } + end matches.first(5).map { |name, dist| name } end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index f7ae97cd8d..3e1924ac63 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -25,6 +25,7 @@ unless Gem::Dependency.new('rdoc', '>= 3.10').matching_specs.empty? gem 'json' end +require 'bundler' require 'minitest/autorun' require 'rubygems/deprecate' @@ -222,17 +223,25 @@ class Gem::TestCase < MiniTest::Unit::TestCase @orig_gem_vendor = ENV['GEM_VENDOR'] @orig_gem_spec_cache = ENV['GEM_SPEC_CACHE'] @orig_rubygems_gemdeps = ENV['RUBYGEMS_GEMDEPS'] + @orig_bundle_gemfile = ENV['BUNDLE_GEMFILE'] @orig_rubygems_host = ENV['RUBYGEMS_HOST'] + @orig_bundle_disable_postit = ENV['BUNDLE_DISABLE_POSTIT'] ENV.keys.find_all { |k| k.start_with?('GEM_REQUIREMENT_') }.each do |k| ENV.delete k end @orig_gem_env_requirements = ENV.to_hash ENV['GEM_VENDOR'] = nil + ENV['BUNDLE_DISABLE_POSTIT'] = 'true' @current_dir = Dir.pwd @fetcher = nil - @ui = Gem::MockGemUi.new + + Bundler.ui = Bundler::UI::Silent.new + @ui = Gem::MockGemUi.new + # This needs to be a new instance since we call use_ui(@ui) when we want to + # capture output + Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new tmpdir = File.expand_path Dir.tmpdir tmpdir.untaint @@ -323,6 +332,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem.loaded_specs.clear Gem.clear_default_specs Gem::Specification.unresolved_deps.clear + Bundler.reset! Gem.configuration.verbose = true Gem.configuration.update_sources = true @@ -394,7 +404,9 @@ class Gem::TestCase < MiniTest::Unit::TestCase ENV['GEM_VENDOR'] = @orig_gem_vendor ENV['GEM_SPEC_CACHE'] = @orig_gem_spec_cache ENV['RUBYGEMS_GEMDEPS'] = @orig_rubygems_gemdeps + ENV['BUNDLE_GEMFILE'] = @orig_bundle_gemfile ENV['RUBYGEMS_HOST'] = @orig_rubygems_host + ENV['BUNDLE_DISABLE_POSTIT'] = @orig_bundle_disable_postit Gem.ruby = @orig_ruby if @orig_ruby diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb index 390d0f2aea..cacd782e08 100644 --- a/lib/rubygems/user_interaction.rb +++ b/lib/rubygems/user_interaction.rb @@ -7,11 +7,6 @@ require 'rubygems/util' -begin - require 'io/console' -rescue LoadError -end - ## # Module that defines the default UserInteraction. Any class including this # module will have access to the +ui+ method that returns the default UI. @@ -314,12 +309,21 @@ class Gem::StreamUI password end - if IO.method_defined?(:noecho) then - def _gets_noecho - @ins.noecho {@ins.gets} + def require_io_console + @require_io_console ||= begin + begin + require 'io/console' + rescue LoadError + end + true end - elsif Gem.win_platform? - def _gets_noecho + end + + def _gets_noecho + require_io_console + if IO.method_defined?(:noecho) then + @ins.noecho {@ins.gets} + elsif Gem.win_platform? require "Win32API" password = '' @@ -332,9 +336,7 @@ class Gem::StreamUI end end password - end - else - def _gets_noecho + else system "stty -echo" begin @ins.gets diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 2f6cfae6ed..6eeaafdcc5 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -237,7 +237,7 @@ class Gem::Version end def hash # :nodoc: - @version.hash + canonical_segments.hash end def init_with coder # :nodoc: @@ -331,7 +331,7 @@ class Gem::Version def <=> other return unless Gem::Version === other - return 0 if @version == other._version + return 0 if @version == other._version || canonical_segments == other.canonical_segments lhsegments = _segments rhsegments = other._segments @@ -356,6 +356,13 @@ class Gem::Version return 0 end + def canonical_segments + @canonical_segments ||= + _split_segments.map! do |segments| + segments.reverse_each.drop_while {|s| s == 0 }.reverse + end.reduce(&:concat) + end + protected def _version @@ -371,4 +378,11 @@ class Gem::Version /^\d+$/ =~ s ? s.to_i : s end.freeze end + + def _split_segments + string_start = _segments.index {|s| s.is_a?(String) } + string_segments = segments + numeric_segments = string_segments.slice!(0, string_start || string_segments.size) + return numeric_segments, string_segments + end end -- cgit v1.2.3