summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-22 22:46:50 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-22 22:46:50 +0000
commit4c2304f0004e9f1784540f3d36976aad9eab1f68 (patch)
treefe5d7f52b7e01644d0a57316aab03299ed0ee5c8 /lib
parent66cc0fa4abde68ae360ba2d2cdf4e44bc833e33a (diff)
* 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
Diffstat (limited to 'lib')
-rw-r--r--lib/rubygems.rb54
-rw-r--r--lib/rubygems/command_manager.rb77
-rw-r--r--lib/rubygems/commands/cert_command.rb85
-rw-r--r--lib/rubygems/commands/contents_command.rb159
-rw-r--r--lib/rubygems/commands/dependency_command.rb147
-rw-r--r--lib/rubygems/commands/environment_command.rb116
-rw-r--r--lib/rubygems/commands/help_command.rb122
-rw-r--r--lib/rubygems/commands/install_command.rb125
-rw-r--r--lib/rubygems/commands/query_command.rb17
-rw-r--r--lib/rubygems/commands/search_command.rb2
-rw-r--r--lib/rubygems/commands/sources_command.rb155
-rw-r--r--lib/rubygems/commands/uninstall_command.rb28
-rw-r--r--lib/rubygems/commands/update_command.rb186
-rw-r--r--lib/rubygems/exceptions.rb8
-rw-r--r--lib/rubygems/ext/builder.rb4
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb7
-rw-r--r--lib/rubygems/path_support.rb2
-rw-r--r--lib/rubygems/remote_fetcher.rb6
-rw-r--r--lib/rubygems/request.rb9
-rw-r--r--lib/rubygems/spec_fetcher.rb14
-rw-r--r--lib/rubygems/specification.rb11
-rw-r--r--lib/rubygems/stub_specification.rb9
22 files changed, 827 insertions, 516 deletions
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