From 4c2304f0004e9f1784540f3d36976aad9eab1f68 Mon Sep 17 00:00:00 2001 From: drbrain Date: Mon, 22 Jul 2013 22:46:50 +0000 Subject: * lib/rubygems: Import RubyGems from master as of commit b165260 * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42124 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rubygems.rb | 54 ++++++-- lib/rubygems/command_manager.rb | 77 ++++++----- lib/rubygems/commands/cert_command.rb | 85 +++++++----- lib/rubygems/commands/contents_command.rb | 159 ++++++++++++++--------- lib/rubygems/commands/dependency_command.rb | 147 +++++++++++++-------- lib/rubygems/commands/environment_command.rb | 116 +++++++++-------- lib/rubygems/commands/help_command.rb | 122 ++++++++++-------- lib/rubygems/commands/install_command.rb | 125 +++++++++++------- lib/rubygems/commands/query_command.rb | 17 ++- lib/rubygems/commands/search_command.rb | 2 + lib/rubygems/commands/sources_command.rb | 155 ++++++++++++---------- lib/rubygems/commands/uninstall_command.rb | 28 +++- lib/rubygems/commands/update_command.rb | 186 ++++++++++++++++----------- lib/rubygems/exceptions.rb | 8 +- lib/rubygems/ext/builder.rb | 4 +- lib/rubygems/ext/ext_conf_builder.rb | 7 +- lib/rubygems/path_support.rb | 2 + lib/rubygems/remote_fetcher.rb | 6 +- lib/rubygems/request.rb | 9 +- lib/rubygems/spec_fetcher.rb | 14 +- lib/rubygems/specification.rb | 11 +- lib/rubygems/stub_specification.rb | 9 +- 22 files changed, 827 insertions(+), 516 deletions(-) (limited to 'lib') diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 4cc2e6ea50..0c9dc759b4 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -446,16 +446,12 @@ module Gem # $LOAD_PATH for files as well as gems. # # Note that find_files will return all files even if they are from different - # versions of the same gem. + # versions of the same gem. See also find_latest_files def self.find_files(glob, check_load_path=true) files = [] - if check_load_path - files = $LOAD_PATH.map { |load_path| - Dir["#{File.expand_path glob, load_path}#{Gem.suffix_pattern}"] - }.flatten.select { |file| File.file? file.untaint } - end + files = find_files_from_load_path glob if check_load_path files.concat Gem::Specification.map { |spec| spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}") @@ -468,6 +464,40 @@ module Gem return files end + def self.find_files_from_load_path glob # :nodoc: + $LOAD_PATH.map { |load_path| + Dir["#{File.expand_path glob, load_path}#{Gem.suffix_pattern}"] + }.flatten.select { |file| File.file? file.untaint } + end + + ## + # Returns a list of paths matching +glob+ from the latest gems that can be + # used by a gem to pick up features from other gems. For example: + # + # Gem.find_latest_files('rdoc/discover').each do |path| load path end + # + # if +check_load_path+ is true (the default), then find_latest_files also + # searches $LOAD_PATH for files as well as gems. + # + # Unlike find_files, find_latest_files will return only files from the + # latest version of a gem. + + def self.find_latest_files(glob, check_load_path=true) + files = [] + + files = find_files_from_load_path glob if check_load_path + + files.concat Gem::Specification.latest_specs(true).map { |spec| + spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}") + }.flatten + + # $LOAD_PATH might contain duplicate entries or reference + # the spec dirs directly, so we prune. + files.uniq! if check_load_path + + return files + end + ## # Finds the user's home directory. #-- @@ -947,7 +977,7 @@ module Gem ## # Load +plugins+ as Ruby files - def self.load_plugin_files(plugins) + def self.load_plugin_files plugins # :nodoc: plugins.each do |plugin| # Skip older versions of the GemCutter plugin: Its commands are in @@ -965,10 +995,16 @@ module Gem end ## - # Find all 'rubygems_plugin' files in installed gems and load them + # Find the 'rubygems_plugin' files in the latest installed gems and load + # them def self.load_plugins - load_plugin_files find_files('rubygems_plugin', false) + # 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 end ## diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 2af582177d..fdee064fed 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -33,6 +33,39 @@ class Gem::CommandManager include Gem::UserInteraction + BUILTIN_COMMANDS = [ # :nodoc: + :build, + :cert, + :check, + :cleanup, + :contents, + :dependency, + :environment, + :fetch, + :generate_index, + :help, + :install, + :list, + :lock, + :mirror, + :outdated, + :owner, + :pristine, + :push, + :query, + :rdoc, + :search, + :server, + :sources, + :specification, + :stale, + :uninstall, + :unpack, + :update, + :which, + :yank, + ] + ## # Return the authoritative instance of the command manager. @@ -61,36 +94,10 @@ class Gem::CommandManager def initialize require 'timeout' @commands = {} - register_command :build - register_command :cert - register_command :check - register_command :cleanup - register_command :contents - register_command :dependency - register_command :environment - register_command :fetch - register_command :generate_index - register_command :help - register_command :install - register_command :list - register_command :lock - register_command :mirror - register_command :outdated - register_command :owner - register_command :pristine - register_command :push - register_command :query - register_command :rdoc - register_command :search - register_command :server - register_command :sources - register_command :specification - register_command :stale - register_command :uninstall - register_command :unpack - register_command :update - register_command :which - register_command :yank + + BUILTIN_COMMANDS.each do |name| + register_command name + end end ## @@ -132,14 +139,6 @@ class Gem::CommandManager alert_error "While executing gem ... (#{ex.class})\n #{ex.to_s}" ui.backtrace ex - if Gem.configuration.really_verbose and \ - ex.kind_of?(Gem::Exception) and ex.source_exception - e = ex.source_exception - - ui.errs.puts "Because of: (#{e.class})\n #{e.to_s}" - ui.backtrace e - end - terminate_interaction(1) rescue Interrupt alert_error "Interrupted" @@ -147,8 +146,6 @@ class Gem::CommandManager end def process_args(args, build_args=nil) - args = args.to_str.split(/\s+/) if args.respond_to?(:to_str) - if args.empty? then say Gem::Command::HELP terminate_interaction 1 diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb index 99e9690755..e417193bca 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -85,44 +85,52 @@ class Gem::Commands::CertCommand < Gem::Command end end + def add_certificate certificate # :nodoc: + Gem::Security.trust_dir.trust_cert certificate + + say "Added '#{certificate.subject}'" + end + def execute options[:add].each do |certificate| - Gem::Security.trust_dir.trust_cert certificate - - say "Added '#{certificate.subject}'" + add_certificate certificate end options[:remove].each do |filter| - certificates_matching filter do |certificate, path| - FileUtils.rm path - say "Removed '#{certificate.subject}'" - end + remove_certificates_matching filter end options[:list].each do |filter| - certificates_matching filter do |certificate, _| - # this could probably be formatted more gracefully - say certificate.subject.to_s - end + list_certificates_matching filter end options[:build].each do |name| build name end - unless options[:sign].empty? then - load_default_cert unless options[:issuer_cert] - load_default_key unless options[:key] - end + sign_certificates unless options[:sign].empty? + end - options[:sign].each do |cert_file| - sign cert_file + def build name + key, key_path = build_key + cert_path = build_cert name, key + + say "Certificate: #{cert_path}" + + if key_path + say "Private Key: #{key_path}" + say "Don't forget to move the key file to somewhere private!" end end - def build name - if options[:key] - key = options[:key] + def build_cert name, key # :nodoc: + cert = Gem::Security.create_cert_email name, key + Gem::Security.write cert, "gem-public_cert.pem" + end + + def build_key # :nodoc: + if options[:key] then + options[:key] else passphrase = ask_for_password 'Passphrase for your Private Key:' say "\n" @@ -135,16 +143,8 @@ class Gem::Commands::CertCommand < Gem::Command key = Gem::Security.create_key key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase - end - cert = Gem::Security.create_cert_email name, key - cert_path = Gem::Security.write cert, "gem-public_cert.pem" - - say "Certificate: #{cert_path}" - - if key_path - say "Private Key: #{key_path}" - say "Don't forget to move the key file to somewhere private!" + return key, key_path end end @@ -200,6 +200,13 @@ For further reading on signing gems see `ri Gem::Security`. EOF end + def list_certificates_matching filter # :nodoc: + certificates_matching filter do |certificate, _| + # this could probably be formatted more gracefully + say certificate.subject.to_s + end + end + def load_default_cert cert_file = File.join Gem.default_cert_path cert = File.read cert_file @@ -233,6 +240,18 @@ For further reading on signing gems see `ri Gem::Security`. terminate_interaction 1 end + def load_defaults # :nodoc: + load_default_cert unless options[:issuer_cert] + load_default_key unless options[:key] + end + + def remove_certificates_matching filter # :nodoc: + certificates_matching filter do |certificate, path| + FileUtils.rm path + say "Removed '#{certificate.subject}'" + end + end + def sign cert_file cert = File.read cert_file cert = OpenSSL::X509::Certificate.new cert @@ -247,5 +266,13 @@ For further reading on signing gems see `ri Gem::Security`. Gem::Security.write cert, cert_file, permissions end + def sign_certificates # :nodoc: + load_defaults unless options[:sign].empty? + + options[:sign].each do |cert_file| + sign cert_file + end + end + end if defined?(OpenSSL::SSL) diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb index 42c7fabd86..9ba24895dc 100644 --- a/lib/rubygems/commands/contents_command.rb +++ b/lib/rubygems/commands/contents_command.rb @@ -31,6 +31,10 @@ class Gem::Commands::ContentsCommand < Gem::Command "Don't include installed path prefix") do |prefix, options| options[:prefix] = prefix end + + @path_kind = nil + @spec_dirs = nil + @version = nil end def arguments # :nodoc: @@ -46,74 +50,113 @@ class Gem::Commands::ContentsCommand < Gem::Command end def execute - version = options[:version] || Gem::Requirement.default + @version = options[:version] || Gem::Requirement.default + @spec_dirs = specification_directories + @path_kind = path_description @spec_dirs - spec_dirs = options[:specdirs].map do |i| - [i, File.join(i, "specifications")] - end.flatten + names = gem_names - path_kind = if spec_dirs.empty? then - spec_dirs = Gem::Specification.dirs - "default gem paths" - else - "specified path" - end - - gem_names = if options[:all] then - Gem::Specification.map(&:name) - else - get_all_gem_names - end - - gem_names.each do |name| - # HACK: find_by_name fails for some reason... ARGH - # How many places must we embed our resolve logic? - spec = Gem::Specification.find_all_by_name(name, version).last - - unless spec then - say "Unable to find gem '#{name}' in #{path_kind}" - - if Gem.configuration.verbose then - say "\nDirectories searched:" - spec_dirs.sort.each { |dir| say dir } - end - - terminate_interaction 1 if gem_names.length == 1 - end + names.each do |name| + found = gem_contents name + + terminate_interaction 1 unless found or names.length > 1 + end + end + + def files_in spec + if spec.default_gem? then + files_in_default_gem spec + else + files_in_gem spec + end + end - if spec.default_gem? - files = spec.files.sort.map do |file| - case file - when /\A#{spec.bindir}\// - [Gem::ConfigMap[:bindir], $POSTMATCH] - when /\.so\z/ - [Gem::ConfigMap[:archdir], file] - else - [Gem::ConfigMap[:rubylibdir], file] - end - end + def files_in_gem spec + gem_path = spec.full_gem_path + extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only] + glob = "#{gem_path}#{extra}/**/*" + prefix_re = /#{Regexp.escape(gem_path)}\// + + Dir[glob].map do |file| + [gem_path, file.sub(prefix_re, "")] + end + end + + def files_in_default_gem spec + spec.files.sort.map do |file| + case file + when /\A#{spec.bindir}\// + [Gem::ConfigMap[:bindir], $POSTMATCH] + when /\.so\z/ + [Gem::ConfigMap[:archdir], file] else - gem_path = spec.full_gem_path - extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only] - glob = "#{gem_path}#{extra}/**/*" - prefix_re = /#{Regexp.escape(gem_path)}\// - files = Dir[glob].map do |file| - [gem_path, file.sub(prefix_re, "")] - end + [Gem::ConfigMap[:rubylibdir], file] end + end + end + + def gem_contents name + spec = spec_for name + + return false unless spec + + files = files_in spec + + show_files files - files.sort.each do |prefix, basename| - absolute_path = File.join(prefix, basename) - next if File.directory? absolute_path + true + end + + def gem_names # :nodoc: + if options[:all] then + Gem::Specification.map(&:name) + else + get_all_gem_names + end + end + + def path_description spec_dirs # :nodoc: + if spec_dirs.empty? then + spec_dirs = Gem::Specification.dirs + "default gem paths" + else + "specified path" + end + end + + def show_files files + files.sort.each do |prefix, basename| + absolute_path = File.join(prefix, basename) + next if File.directory? absolute_path - if options[:prefix] - say absolute_path - else - say basename - end + if options[:prefix] then + say absolute_path + else + say basename end end end + def spec_for name + spec = Gem::Specification.find_all_by_name(name, @version).last + + return spec if spec + + say "Unable to find gem '#{name}' in #{@path_kind}" + + if Gem.configuration.verbose then + say "\nDirectories searched:" + @spec_dirs.sort.each { |dir| say dir } + end + + return nil + end + + def specification_directories # :nodoc: + options[:specdirs].map do |i| + [i, File.join(i, "specifications")] + end.flatten + end + end diff --git a/lib/rubygems/commands/dependency_command.rb b/lib/rubygems/commands/dependency_command.rb index 4690b13a94..f444841ccb 100644 --- a/lib/rubygems/commands/dependency_command.rb +++ b/lib/rubygems/commands/dependency_command.rb @@ -42,85 +42,106 @@ class Gem::Commands::DependencyCommand < Gem::Command "#{program_name} GEMNAME" end - def execute - if options[:reverse_dependencies] and remote? and not local? then - alert_error 'Only reverse dependencies for local gems are supported.' - terminate_interaction 1 - end + def fetch_remote_specs dependency # :nodoc: + fetcher = Gem::SpecFetcher.fetcher + + ss, = fetcher.spec_for_dependency dependency + + ss.map { |spec, _| spec } + end + + def fetch_specs dependency # :nodoc: + specs = [] + + specs.concat dependency.matching_specs if local? + specs.concat fetch_remote_specs dependency if remote? + + ensure_specs specs + + specs.uniq.sort + end - options[:args] << '' if options[:args].empty? + def gem_dependency args, version, prerelease # :nodoc: + args << '' if args.empty? - pattern = if options[:args].length == 1 and - options[:args].first =~ /\A\/(.*)\/(i)?\z/m then + pattern = if args.length == 1 and args.first =~ /\A\/(.*)\/(i)?\z/m then flags = $2 ? Regexp::IGNORECASE : nil Regexp.new $1, flags else - /\A#{Regexp.union(*options[:args])}/ + /\A#{Regexp.union(*args)}/ end - # TODO: deprecate for real damnit dependency = Gem::Deprecate.skip_during { - Gem::Dependency.new pattern, options[:version] + Gem::Dependency.new pattern, version } - dependency.prerelease = options[:prerelease] - specs = [] + dependency.prerelease = prerelease - specs.concat dependency.matching_specs if local? + dependency + end - if remote? and not options[:reverse_dependencies] then - fetcher = Gem::SpecFetcher.fetcher + def display_pipe specs # :nodoc: + specs.each do |spec| + unless spec.dependencies.empty? then + spec.dependencies.sort_by { |dep| dep.name }.each do |dep| + say "#{dep.name} --version '#{dep.requirement}'" + end + end + end + end - ss, _ = fetcher.spec_for_dependency dependency + def display_readable specs, reverse # :nodoc: + response = '' - ss.each { |s,o| specs << s } + specs.each do |spec| + response << print_dependencies(spec) + unless reverse[spec.full_name].empty? then + response << " Used by\n" + reverse[spec.full_name].each do |sp, dep| + response << " #{sp} (#{dep})\n" + end + end + response << "\n" end - if specs.empty? then - patterns = options[:args].join ',' - say "No gems found matching #{patterns} (#{options[:version]})" if - Gem.configuration.verbose + say response + end - terminate_interaction 1 - end + def execute + ensure_local_only_reverse_dependencies - specs = specs.uniq.sort + dependency = + gem_dependency options[:args], options[:version], options[:prerelease] - reverse = Hash.new { |h, k| h[k] = [] } + specs = fetch_specs dependency - if options[:reverse_dependencies] then - specs.each do |spec| - reverse[spec.full_name] = find_reverse_dependencies spec - end - end + reverse = reverse_dependencies specs if options[:pipe_format] then - specs.each do |spec| - unless spec.dependencies.empty? - spec.dependencies.sort_by { |dep| dep.name }.each do |dep| - say "#{dep.name} --version '#{dep.requirement}'" - end - end - end + display_pipe specs else - response = '' - - specs.each do |spec| - response << print_dependencies(spec) - unless reverse[spec.full_name].empty? then - response << " Used by\n" - reverse[spec.full_name].each do |sp, dep| - response << " #{sp} (#{dep})\n" - end - end - response << "\n" - end + display_readable specs, reverse + end + end - say response + def ensure_local_only_reverse_dependencies # :nodoc: + if options[:reverse_dependencies] and remote? and not local? then + alert_error 'Only reverse dependencies for local gems are supported.' + terminate_interaction 1 end end - def print_dependencies(spec, level = 0) + def ensure_specs specs # :nodoc: + return unless specs.empty? + + patterns = options[:args].join ',' + say "No gems found matching #{patterns} (#{options[:version]})" if + Gem.configuration.verbose + + terminate_interaction 1 + end + + def print_dependencies(spec, level = 0) # :nodoc: response = '' response << ' ' * level + "Gem #{spec.full_name}\n" unless spec.dependencies.empty? then @@ -131,10 +152,30 @@ class Gem::Commands::DependencyCommand < Gem::Command response end + def remote_specs dependency # :nodoc: + fetcher = Gem::SpecFetcher.fetcher + + ss, _ = fetcher.spec_for_dependency dependency + + ss.map { |s,o| s } + end + + def reverse_dependencies specs # :nodoc: + reverse = Hash.new { |h, k| h[k] = [] } + + return reverse unless options[:reverse_dependencies] + + specs.each do |spec| + reverse[spec.full_name] = find_reverse_dependencies spec + end + + reverse + end + ## # Returns an Array of [specification, dep] that are satisfied by +spec+. - def find_reverse_dependencies(spec) + def find_reverse_dependencies spec # :nodoc: result = [] Gem::Specification.each do |sp| diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb index 39d52e7f01..034f2ccb49 100644 --- a/lib/rubygems/commands/environment_command.rb +++ b/lib/rubygems/commands/environment_command.rb @@ -69,77 +69,83 @@ lib/rubygems/defaults/operating_system.rb def execute out = '' arg = options[:args][0] - case arg - when /^packageversion/ then - out << Gem::RubyGemsPackageVersion - when /^version/ then - out << Gem::VERSION - when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then - out << Gem.dir - when /^gempath/, /^path/, /^GEM_PATH/ then - out << Gem.path.join(File::PATH_SEPARATOR) - when /^remotesources/ then - out << Gem.sources.to_a.join("\n") - when /^platform/ then - out << Gem.platforms.join(File::PATH_SEPARATOR) - when nil then - out = "RubyGems Environment:\n" - - out << " - RUBYGEMS VERSION: #{Gem::VERSION}\n" - - out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}" - out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - out << ") [#{RUBY_PLATFORM}]\n" + out << + case arg + when /^packageversion/ then + Gem::RubyGemsPackageVersion + when /^version/ then + Gem::VERSION + when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then + Gem.dir + when /^gempath/, /^path/, /^GEM_PATH/ then + Gem.path.join(File::PATH_SEPARATOR) + when /^remotesources/ then + Gem.sources.to_a.join("\n") + when /^platform/ then + Gem.platforms.join(File::PATH_SEPARATOR) + when nil then + show_environment + else + raise Gem::CommandLineError, "Unknown environment option [#{arg}]" + end + say out + true + end - out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n" + def add_path out, path + path.each do |component| + out << " - #{component}\n" + end + end - out << " - RUBYGEMS PREFIX: #{Gem.prefix}\n" unless Gem.prefix.nil? + def show_environment # :nodoc: + out = "RubyGems Environment:\n" - out << " - RUBY EXECUTABLE: #{Gem.ruby}\n" + out << " - RUBYGEMS VERSION: #{Gem::VERSION}\n" - out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n" + out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}" + out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL + out << ") [#{RUBY_PLATFORM}]\n" - out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n" + out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n" - out << " - RUBYGEMS PLATFORMS:\n" - Gem.platforms.each do |platform| - out << " - #{platform}\n" - end + out << " - RUBYGEMS PREFIX: #{Gem.prefix}\n" unless Gem.prefix.nil? - out << " - GEM PATHS:\n" - out << " - #{Gem.dir}\n" + out << " - RUBY EXECUTABLE: #{Gem.ruby}\n" - gem_path = Gem.path.dup - gem_path.delete Gem.dir - add_path out, gem_path + out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n" - out << " - GEM CONFIGURATION:\n" - Gem.configuration.each do |name, value| - value = value.gsub(/./, '*') if name == 'gemcutter_key' - out << " - #{name.inspect} => #{value.inspect}\n" - end + out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n" - out << " - REMOTE SOURCES:\n" - Gem.sources.each do |s| - out << " - #{s}\n" - end + out << " - RUBYGEMS PLATFORMS:\n" + Gem.platforms.each do |platform| + out << " - #{platform}\n" + end - out << " - SHELL PATH:\n" + out << " - GEM PATHS:\n" + out << " - #{Gem.dir}\n" - shell_path = ENV['PATH'].split(File::PATH_SEPARATOR) - add_path out, shell_path + gem_path = Gem.path.dup + gem_path.delete Gem.dir + add_path out, gem_path - else - raise Gem::CommandLineError, "Unknown environment option [#{arg}]" + out << " - GEM CONFIGURATION:\n" + Gem.configuration.each do |name, value| + value = value.gsub(/./, '*') if name == 'gemcutter_key' + out << " - #{name.inspect} => #{value.inspect}\n" end - say out - true - end - def add_path out, path - path.each do |component| - out << " - #{component}\n" + out << " - REMOTE SOURCES:\n" + Gem.sources.each do |s| + out << " - #{s}\n" end + + out << " - SHELL PATH:\n" + + shell_path = ENV['PATH'].split(File::PATH_SEPARATOR) + add_path out, shell_path + + out end end diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb index 4cbb8dadee..ed7be903ac 100644 --- a/lib/rubygems/commands/help_command.rb +++ b/lib/rubygems/commands/help_command.rb @@ -94,6 +94,8 @@ platform. def initialize super 'help', "Provide help on the 'gem' command" + + @command_manager = Gem::CommandManager.instance end def arguments # :nodoc: @@ -110,46 +112,10 @@ platform. end def execute - command_manager = Gem::CommandManager.instance arg = options[:args][0] if begins? "commands", arg then - out = [] - out << "GEM commands are:" - out << nil - - margin_width = 4 - - desc_width = command_manager.command_names.map { |n| n.size }.max + 4 - - summary_width = 80 - margin_width - desc_width - wrap_indent = ' ' * (margin_width + desc_width) - format = "#{' ' * margin_width}%-#{desc_width}s%s" - - command_manager.command_names.each do |cmd_name| - command = command_manager[cmd_name] - - summary = - if command then - command.summary - else - "[No command found for #{cmd_name}]" - end - - summary = wrap(summary, summary_width).split "\n" - out << sprintf(format, cmd_name, summary.shift) - until summary.empty? do - out << "#{wrap_indent}#{summary.shift}" - end - end - - out << nil - out << "For help on a particular command, use 'gem help COMMAND'." - out << nil - out << "Commands may be abbreviated, so long as they are unambiguous." - out << "e.g. 'gem i rake' is short for 'gem install rake'." - - say out.join("\n") + show_commands elsif begins? "options", arg then say Gem::Command::HELP @@ -161,29 +127,79 @@ platform. say PLATFORMS elsif options[:help] then - command = command_manager[options[:help]] - if command - # help with provided command - command.invoke("--help") - else - alert_error "Unknown command #{options[:help]}. Try 'gem help commands'" - end + show_help elsif arg then - possibilities = command_manager.find_command_possibilities(arg.downcase) - if possibilities.size == 1 - command = command_manager[possibilities.first] - command.invoke("--help") - elsif possibilities.size > 1 - alert_warning "Ambiguous command #{arg} (#{possibilities.join(', ')})" - else - alert_warning "Unknown command #{arg}. Try gem help commands" - end + show_command_help arg else say Gem::Command::HELP end end + def show_commands # :nodoc: + out = [] + out << "GEM commands are:" + out << nil + + margin_width = 4 + + desc_width = @command_manager.command_names.map { |n| n.size }.max + 4 + + summary_width = 80 - margin_width - desc_width + wrap_indent = ' ' * (margin_width + desc_width) + format = "#{' ' * margin_width}%-#{desc_width}s%s" + + @command_manager.command_names.each do |cmd_name| + command = @command_manager[cmd_name] + + summary = + if command then + command.summary + else + "[No command found for #{cmd_name}]" + end + + summary = wrap(summary, summary_width).split "\n" + out << sprintf(format, cmd_name, summary.shift) + until summary.empty? do + out << "#{wrap_indent}#{summary.shift}" + end + end + + out << nil + out << "For help on a particular command, use 'gem help COMMAND'." + out << nil + out << "Commands may be abbreviated, so long as they are unambiguous." + out << "e.g. 'gem i rake' is short for 'gem install rake'." + + say out.join("\n") + end + + def show_command_help command_name # :nodoc: + command_name = command_name.downcase + + possibilities = @command_manager.find_command_possibilities command_name + + if possibilities.size == 1 then + command = @command_manager[possibilities.first] + command.invoke("--help") + elsif possibilities.size > 1 then + alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})" + else + alert_warning "Unknown command #{command_name}. Try: gem help commands" + end + end + + def show_help # :nodoc: + command = @command_manager[options[:help]] + if command then + # help with provided command + command.invoke("--help") + else + alert_error "Unknown command #{options[:help]}. Try 'gem help commands'" + end + end + end diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index 5e2ffcdff3..f02b12906d 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -113,7 +113,44 @@ to write the specification by hand. For example: "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags" end - def install_from_gemdeps(gf) + def check_install_dir # :nodoc: + if options[:install_dir] and options[:user_install] then + alert_error "Use --install-dir or --user-install but not both" + terminate_interaction 1 + end + end + + def check_version # :nodoc: + if options[:version] != Gem::Requirement.default and + get_all_gem_names.size > 1 then + alert_error "Can't use --version w/ multiple gems. Use name:ver instead." + terminate_interaction 1 + end + end + + def execute + if gf = options[:gemdeps] then + install_from_gemdeps gf + return + end + + @installed_specs = [] + + ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9' + + check_install_dir + check_version + + load_hooks + + exit_code = install_gems + + show_installed + + raise Gem::SystemExitException, exit_code + end + + def install_from_gemdeps gf # :nodoc: require 'rubygems/request_set' rs = Gem::RequestSet.new rs.load_gemdeps gf @@ -135,58 +172,26 @@ to write the specification by hand. For example: raise Gem::SystemExitException, 0 end - def execute - if gf = options[:gemdeps] then - install_from_gemdeps gf - return - end + def install_gem name, version # :nodoc: + return if options[:conservative] and + not Gem::Dependency.new(name, version).matching_specs.empty? - @installed_specs = [] + inst = Gem::DependencyInstaller.new options + inst.install name, Gem::Requirement.create(version) - ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9' + @installed_specs.push(*inst.installed_gems) - if options[:install_dir] and options[:user_install] - alert_error "Use --install-dir or --user-install but not both" - terminate_interaction 1 - end + show_install_errors inst.errors + end + def install_gems # :nodoc: exit_code = 0 - if options[:version] != Gem::Requirement.default && - get_all_gem_names.size > 1 then - alert_error "Can't use --version w/ multiple gems. Use name:ver instead." - terminate_interaction 1 - end - - # load post-install hooks appropriate to options - if options[:install_as_default] - require 'rubygems/install_default_message' - else - require 'rubygems/install_message' - end - require 'rubygems/rdoc' - get_all_gem_names_and_versions.each do |gem_name, gem_version| gem_version ||= options[:version] begin - next if options[:conservative] and - not Gem::Dependency.new(gem_name, gem_version).matching_specs.empty? - - inst = Gem::DependencyInstaller.new options - inst.install gem_name, Gem::Requirement.create(gem_version) - - @installed_specs.push(*inst.installed_gems) - - next unless errs = inst.errors - - errs.each do |x| - next unless Gem::SourceFetchProblem === x - - msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}" - - alert_warning msg - end + install_gem gem_name, gem_version rescue Gem::InstallError => e alert_error "Error installing #{gem_name}:\n\t#{e.message}" exit_code |= 1 @@ -197,12 +202,38 @@ to write the specification by hand. For example: end end - unless @installed_specs.empty? then - gems = @installed_specs.length == 1 ? 'gem' : 'gems' - say "#{@installed_specs.length} #{gems} installed" + exit_code + end + + ## + # Loads post-install hooks + + def load_hooks # :nodoc: + if options[:install_as_default] + require 'rubygems/install_default_message' + else + require 'rubygems/install_message' + end + require 'rubygems/rdoc' + end + + def show_install_errors errors # :nodoc: + return unless errors + + errors.each do |x| + return unless Gem::SourceFetchProblem === x + + msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}" + + alert_warning msg end + end - raise Gem::SystemExitException, exit_code + def show_installed # :nodoc: + return if @installed_specs.empty? + + gems = @installed_specs.length == 1 ? 'gem' : 'gems' + say "#{@installed_specs.length} #{gems} installed" end end diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb index 7bda7383e2..05b214bb63 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -14,7 +14,7 @@ class Gem::Commands::QueryCommand < Gem::Command summary = 'Query gem information in local or remote repositories') super name, summary, :name => //, :domain => :local, :details => false, :versions => true, - :installed => false, :version => Gem::Requirement.default + :installed => nil, :version => Gem::Requirement.default add_option('-i', '--[no-]installed', 'Check for installed gem') do |value, options| @@ -67,15 +67,20 @@ class Gem::Commands::QueryCommand < Gem::Command name = options[:name] prerelease = options[:prerelease] - if options[:installed] then + unless options[:installed].nil? then if name.source.empty? then alert_error "You must specify a gem name" exit_code |= 4 - elsif installed? name, options[:version] then - say "true" else - say "false" - exit_code |= 1 + installed = installed? name, options[:version] + installed = !installed unless options[:installed] + + if installed then + say "true" + else + say "false" + exit_code |= 1 + end end terminate_interaction exit_code diff --git a/lib/rubygems/commands/search_command.rb b/lib/rubygems/commands/search_command.rb index 7810c85b36..c125715fe2 100644 --- a/lib/rubygems/commands/search_command.rb +++ b/lib/rubygems/commands/search_command.rb @@ -7,6 +7,8 @@ class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand super 'search', 'Display all gems whose name contains STRING' remove_option '--name-matches' + + defaults[:domain] = :remote end def arguments # :nodoc: diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb index 82bb1f62eb..810b45d7c0 100644 --- a/lib/rubygems/commands/sources_command.rb +++ b/lib/rubygems/commands/sources_command.rb @@ -37,103 +37,118 @@ class Gem::Commands::SourcesCommand < Gem::Command add_proxy_option end - def defaults_str - '--list' - end + def add_source source_uri # :nodoc: + check_rubygems_https source_uri - def execute - options[:list] = !(options[:add] || - options[:clear_all] || - options[:remove] || - options[:update]) + source = Gem::Source.new source_uri - if options[:clear_all] then - path = Gem.spec_cache_dir - FileUtils.rm_rf path - - unless File.exist? path then - say "*** Removed specs cache ***" + begin + if Gem.sources.include? source_uri then + say "source #{source_uri} already present in the cache" else - unless File.writable? path then - say "*** Unable to remove source cache (write protected) ***" - else - say "*** Unable to remove source cache ***" - end + source.load_specs :released + Gem.sources << source + Gem.configuration.write - terminate_interaction 1 + say "#{source_uri} added to sources" end + rescue URI::Error, ArgumentError + say "#{source_uri} is not a URI" + terminate_interaction 1 + rescue Gem::RemoteFetcher::FetchError => e + say "Error fetching #{source_uri}:\n\t#{e.message}" + terminate_interaction 1 end + end - if source_uri = options[:add] then - uri = URI source_uri + def check_rubygems_https source_uri # :nodoc: + uri = URI source_uri - if uri.scheme and uri.scheme.downcase == 'http' and - uri.host.downcase == 'rubygems.org' then - question = <<-QUESTION.chomp + if uri.scheme and uri.scheme.downcase == 'http' and + uri.host.downcase == 'rubygems.org' then + question = <<-QUESTION.chomp https://rubygems.org is recommended for security over #{uri} Do you want to add this insecure source? - QUESTION - - terminate_interaction 1 unless ask_yes_no question - end + QUESTION - source = Gem::Source.new source_uri - - begin - if Gem.sources.include? source_uri then - say "source #{source_uri} already present in the cache" - else - source.load_specs :released - Gem.sources << source - Gem.configuration.write - - say "#{source_uri} added to sources" - end - rescue URI::Error, ArgumentError - say "#{source_uri} is not a URI" - terminate_interaction 1 - rescue Gem::RemoteFetcher::FetchError => e - say "Error fetching #{source_uri}:\n\t#{e.message}" - terminate_interaction 1 - end + terminate_interaction 1 unless ask_yes_no question end + end - if options[:remove] then - source_uri = options[:remove] + def clear_all # :nodoc: + path = Gem.spec_cache_dir + FileUtils.rm_rf path - unless Gem.sources.include? source_uri then - say "source #{source_uri} not present in cache" + unless File.exist? path then + say "*** Removed specs cache ***" + else + unless File.writable? path then + say "*** Unable to remove source cache (write protected) ***" else - Gem.sources.delete source_uri - Gem.configuration.write - - say "#{source_uri} removed from sources" + say "*** Unable to remove source cache ***" end + + terminate_interaction 1 end + end - if options[:update] then - Gem.sources.each_source do |src| - src.load_specs :released - src.load_specs :latest - end + def defaults_str # :nodoc: + '--list' + end + + def list # :nodoc: + say "*** CURRENT SOURCES ***" + say - say "source cache successfully updated" + Gem.sources.each do |src| + say src end + end - if options[:list] then - say "*** CURRENT SOURCES ***" - say + def list? # :nodoc: + !(options[:list] || + options[:add] || + options[:clear_all] || + options[:remove] || + options[:update]) + end - Gem.sources.each do |src| - say src - end + def execute + clear_all if options[:clear_all] + + source_uri = options[:add] + add_source source_uri if source_uri + + source_uri = options[:remove] + remove_source source_uri if source_uri + + update if options[:update] + + list if list? + end + + def remove_source source_uri # :nodoc: + unless Gem.sources.include? source_uri then + say "source #{source_uri} not present in cache" + else + Gem.sources.delete source_uri + Gem.configuration.write + + say "#{source_uri} removed from sources" end end - private + def update # :nodoc: + Gem.sources.each_source do |src| + src.load_specs :released + src.load_specs :latest + end + + say "source cache successfully updated" + end - def remove_cache_file(desc, path) + def remove_cache_file desc, path # :nodoc: FileUtils.rm_rf path if not File.exist?(path) then diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb index 68d170acb1..5db8a1ff22 100644 --- a/lib/rubygems/commands/uninstall_command.rb +++ b/lib/rubygems/commands/uninstall_command.rb @@ -1,6 +1,7 @@ require 'rubygems/command' require 'rubygems/version_option' require 'rubygems/uninstaller' +require 'fileutils' ## # Gem uninstaller command line tool @@ -14,7 +15,7 @@ class Gem::Commands::UninstallCommand < Gem::Command def initialize super 'uninstall', 'Uninstall gems from the local repository', :version => Gem::Requirement.default, :user_install => true, - :check_dev => false + :install_dir => Gem.dir, :check_dev => false add_option('-a', '--[no-]all', 'Uninstall all matching versions' @@ -92,8 +93,31 @@ class Gem::Commands::UninstallCommand < Gem::Command end def execute - # REFACTOR: stolen from cleanup_command + if options[:all] and not options[:args].empty? then + alert_error 'Gem names and --all may not be used together' + terminate_interaction 1 + elsif options[:all] then + uninstall_all + else + uninstall_specific + end + end + + def uninstall_all + install_dir = options[:install_dir] + + dirs_to_be_emptied = Dir[File.join(install_dir, '*')] + dirs_to_be_emptied.delete_if { |dir| dir.end_with? 'build_info' } + + dirs_to_be_emptied.each do |dir| + FileUtils.rm_rf Dir[File.join(dir, '*')] + end + alert("Successfully uninstalled all gems in #{install_dir}") + end + + def uninstall_specific deplist = Gem::DependencyList.new + get_all_gem_names.uniq.each do |name| Gem::Specification.find_all_by_name(name).each do |spec| deplist.add spec diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index a31de0071a..3a167361cf 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -56,23 +56,33 @@ class Gem::Commands::UpdateCommand < Gem::Command "#{program_name} GEMNAME [GEMNAME ...]" end + def check_latest_rubygems version # :nodoc: + if Gem.rubygems_version == version then + say "Latest version currently installed. Aborting." + terminate_interaction + end + + options[:user_install] = false + end + + def check_update_arguments # :nodoc: + unless options[:args].empty? then + alert_error "Gem names are not allowed with the --system option" + terminate_interaction 1 + end + end + def execute hig = {} if options[:system] then update_rubygems return - else - say "Updating installed gems" + end - hig = {} # highest installed gems + say "Updating installed gems" - Gem::Specification.each do |spec| - if hig[spec.name].nil? or hig[spec.name].version < spec.version then - hig[spec.name] = spec - end - end - end + hig = highest_installed_gems gems_to_update = which_to_update hig, options[:args].uniq @@ -85,51 +95,65 @@ class Gem::Commands::UpdateCommand < Gem::Command end end - def update_gem name, version = Gem::Requirement.default - return if @updated.any? { |spec| spec.name == name } + def fetch_remote_gems spec # :nodoc: + dependency = Gem::Dependency.new spec.name, "> #{spec.version}" + dependency.prerelease = options[:prerelease] - @installer ||= Gem::DependencyInstaller.new options + fetcher = Gem::SpecFetcher.fetcher - success = false + spec_tuples, _ = fetcher.search_for_dependency dependency - say "Updating #{name}" - begin - @installer.install name, Gem::Requirement.new(version) - success = true - rescue Gem::InstallError => e - alert_error "Error installing #{name}:\n\t#{e.message}" - success = false - end + spec_tuples + end - @installer.installed_gems.each do |spec| - @updated << spec + def highest_installed_gems # :nodoc: + hig = {} # highest installed gems + + Gem::Specification.each do |spec| + if hig[spec.name].nil? or hig[spec.name].version < spec.version then + hig[spec.name] = spec + end end + + hig end - def update_gems gems_to_update - gems_to_update.uniq.sort.each do |(name, version)| - update_gem name, version + def highest_remote_version spec # :nodoc: + spec_tuples = fetch_remote_gems spec + + matching_gems = spec_tuples.select do |g,_| + g.name == spec.name and g.match_platform? end - @updated + highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last + + highest_remote_gem ||= [Gem::NameTuple.null] + + highest_remote_gem.first.version end - ## - # Update RubyGems software to the latest version. + def install_rubygems version # :nodoc: + args = update_rubygems_arguments - def update_rubygems - unless options[:args].empty? then - alert_error "Gem names are not allowed with the --system option" - terminate_interaction 1 - end + update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" - options[:user_install] = false + Dir.chdir update_dir do + say "Installing RubyGems #{version}" - # TODO: rename version and other variable name conflicts - # TODO: get rid of all this indirection on name and other BS + # Make sure old rubygems isn't loaded + old = ENV["RUBYOPT"] + ENV.delete("RUBYOPT") if old + installed = system Gem.ruby, 'setup.rb', *args + say "RubyGems system software updated" if installed + ENV["RUBYOPT"] = old if old + end + end + def rubygems_target_version version = options[:system] - if version == true then + update_latest = version == true + + if update_latest then version = Gem::Version.new Gem::VERSION requirement = Gem::Requirement.new ">= #{Gem::VERSION}" else @@ -146,46 +170,72 @@ class Gem::Commands::UpdateCommand < Gem::Command } gems_to_update = which_to_update hig, options[:args], :system - name, up_ver = gems_to_update.first - current_ver = Gem.rubygems_version + _, up_ver = gems_to_update.first - target = if options[:system] == true then + target = if update_latest then up_ver else version end - if current_ver == target then - # if options[:system] != true and version == current_ver then - say "Latest version currently installed. Aborting." - terminate_interaction + return target, requirement + end + + def update_gem name, version = Gem::Requirement.default + return if @updated.any? { |spec| spec.name == name } + + @installer ||= Gem::DependencyInstaller.new options + + success = false + + say "Updating #{name}" + begin + @installer.install name, Gem::Requirement.new(version) + success = true + rescue Gem::InstallError => e + alert_error "Error installing #{name}:\n\t#{e.message}" + success = false end - update_gem name, target + @installer.installed_gems.each do |spec| + @updated << spec + end + end + + def update_gems gems_to_update + gems_to_update.uniq.sort.each do |(name, version)| + update_gem name, version + end + + @updated + end + + ## + # Update RubyGems software to the latest version. + + def update_rubygems + check_update_arguments + + version, requirement = rubygems_target_version + + check_latest_rubygems version + + update_gem 'rubygems-update', version installed_gems = Gem::Specification.find_all_by_name 'rubygems-update', requirement version = installed_gems.last.version + install_rubygems version + end + + def update_rubygems_arguments # :nodoc: args = [] args << '--prefix' << Gem.prefix if Gem.prefix # TODO use --document for >= 1.9 , --no-rdoc --no-ri < 1.9 args << '--no-rdoc' unless options[:document].include? 'rdoc' args << '--no-ri' unless options[:document].include? 'ri' args << '--no-format-executable' if options[:no_format_executable] - - update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" - - Dir.chdir update_dir do - say "Installing RubyGems #{version}" - setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}" - - # Make sure old rubygems isn't loaded - old = ENV["RUBYOPT"] - ENV.delete("RUBYOPT") if old - installed = system setup_cmd - say "RubyGems system software updated" if installed - ENV["RUBYOPT"] = old if old - end + args end def which_to_update highest_installed_gems, gem_names, system = false @@ -195,21 +245,7 @@ class Gem::Commands::UpdateCommand < Gem::Command next if not gem_names.empty? and gem_names.all? { |name| /#{name}/ !~ l_spec.name } - dependency = Gem::Dependency.new l_spec.name, "> #{l_spec.version}" - dependency.prerelease = options[:prerelease] - - fetcher = Gem::SpecFetcher.fetcher - - spec_tuples, _ = fetcher.search_for_dependency dependency - - matching_gems = spec_tuples.select do |g,_| - g.name == l_name and g.match_platform? - end - - highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last - - highest_remote_gem ||= [Gem::NameTuple.null] - highest_remote_ver = highest_remote_gem.first.version + highest_remote_ver = highest_remote_version l_spec if system or (l_spec.version < highest_remote_ver) then result << [l_spec.name, [l_spec.version, highest_remote_ver].max] diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 13cb5c7f6e..4a988f9edf 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -7,7 +7,13 @@ # Base exception class for RubyGems. All exception raised by RubyGems are a # subclass of this one. class Gem::Exception < RuntimeError - attr_accessor :source_exception + + ## + #-- + # TODO: remove in RubyGems 3, nobody sets this + + attr_accessor :source_exception # :nodoc: + end class Gem::CommandLineError < Gem::Exception; end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 74689bb5e2..ee390578ae 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -23,11 +23,13 @@ class Gem::Ext::Builder make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make' end + destdir = '"DESTDIR=%s"' % ENV['DESTDIR'] if RUBY_VERSION > '2.0' + ['', 'install'].each do |target| # Pass DESTDIR via command line to override what's in MAKEFLAGS cmd = [ make_program, - '"DESTDIR=%s"' % ENV['DESTDIR'], + destdir, target ].join(' ').rstrip run(cmd, results, "make #{target}".rstrip) diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index f53661c733..5112eb8e2f 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -39,6 +39,7 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder run cmd, results ENV["DESTDIR"] = nil + ENV["RUBYOPT"] = rubyopt siteconf.unlink make dest_path, results @@ -49,14 +50,14 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder destent.exist? or File.rename(ent.path, destent.path) end end - - results ensure ENV["RUBYOPT"] = rubyopt ENV["DESTDIR"] = destdir end end - t.unlink if t + t.unlink if t and t.path + + results ensure FileUtils.rm_rf tmp_dest if tmp_dest end diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb index 5a16d7a6df..2af303eecf 100644 --- a/lib/rubygems/path_support.rb +++ b/lib/rubygems/path_support.rb @@ -36,6 +36,8 @@ class Gem::PathSupport @spec_cache_dir = env["GEM_SPEC_CACHE"] || ENV["GEM_SPEC_CACHE"] || Gem.default_spec_cache_dir + + @spec_cache_dir = @spec_cache_dir.dup.untaint end private diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index c10f9ebae8..f00555a1e2 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -324,7 +324,11 @@ class Gem::RemoteFetcher # connections to reduce connect overhead. def request(uri, request_class, last_modified = nil) - Gem::Request.new(uri, request_class, last_modified, @proxy).fetch + request = Gem::Request.new uri, request_class, last_modified, @proxy + + request.fetch do |req| + yield req if block_given? + end end def https?(uri) diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb index 60e31838f9..b2e9dbc679 100644 --- a/lib/rubygems/request.rb +++ b/lib/rubygems/request.rb @@ -1,4 +1,5 @@ require 'net/http' +require 'thread' require 'time' require 'rubygems/user_interaction' @@ -14,6 +15,7 @@ class Gem::Request @last_modified = last_modified @requests = Hash.new 0 @connections = {} + @connections_mutex = Mutex.new @user_agent = user_agent @proxy_uri = @@ -82,8 +84,11 @@ class Gem::Request end connection_id = [Thread.current.object_id, *net_http_args].join ':' - @connections[connection_id] ||= Net::HTTP.new(*net_http_args) - connection = @connections[connection_id] + + connection = @connections_mutex.synchronize do + @connections[connection_id] ||= Net::HTTP.new(*net_http_args) + @connections[connection_id] + end if https?(uri) and not connection.started? then configure_connection_for_https(connection) diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 967ab4492a..53ff8d1f45 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -74,6 +74,12 @@ class Gem::SpecFetcher list, errors = available_specs(type) list.each do |source, specs| + if dependency.name.is_a?(String) && specs.respond_to?(:bsearch) + start_index = (0 ... specs.length).bsearch{ |i| specs[i].name >= dependency.name } + end_index = (0 ... specs.length).bsearch{ |i| specs[i].name > dependency.name } + specs = specs[start_index ... end_index] if start_index && end_index + end + found[source] = specs.select do |tup| if dependency.match?(tup) if matching_platform and !Gem::Platform.match(tup.platform) @@ -214,15 +220,15 @@ class Gem::SpecFetcher def tuples_for(source, type, gracefully_ignore=false) cache = @caches[type] - if gracefully_ignore + tuples = begin cache[source.uri] ||= source.load_specs(type) rescue Gem::RemoteFetcher::FetchError + raise unless gracefully_ignore [] end - else - cache[source.uri] ||= source.load_specs(type) - end + + tuples.sort_by { |tup| tup.name } end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index fd3e90253d..78f62c7a89 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -954,7 +954,7 @@ class Gem::Specification < Gem::BasicSpecification result.map(&:last).map(&:values).flatten.reject { |spec| minimum = native[spec.name] minimum && spec.version < minimum - } + }.sort_by{ |tup| tup.name } end ## @@ -1853,11 +1853,6 @@ class Gem::Specification < Gem::BasicSpecification end end - # Prevent ruby hitting spec.method_missing when [[spec]].flatten is called - def to_ary # :nodoc: - nil - end - ## # Normalize the list of files so that: # * All file lists have redundancies removed. @@ -2008,6 +2003,10 @@ class Gem::Specification < Gem::BasicSpecification @requirements = Array req end + def respond_to_missing? m, include_private = false # :nodoc: + false + end + ## # Returns the full path to this spec's ri directory. diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb index 0a6e70bb15..c2910c1bba 100644 --- a/lib/rubygems/stub_specification.rb +++ b/lib/rubygems/stub_specification.rb @@ -6,6 +6,13 @@ module Gem # :nodoc: PREFIX = "# stub: " + OPEN_MODE = # :nodoc: + if Object.const_defined? :Encoding then + 'r:UTF-8:-' + else + 'r' + end + # :nodoc: class StubLine attr_reader :parts @@ -96,7 +103,7 @@ module Gem def data unless @data - File.open(filename, "r:UTF-8:-") do |file| + open filename, OPEN_MODE do |file| begin file.readline # discard encoding line stubline = file.readline.chomp -- cgit v1.2.3