diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-09-14 08:59:02 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-09-14 08:59:02 +0000 |
commit | 269503b544247b5b3e30dbe60a0bab4f2ca00e4e (patch) | |
tree | a6d0a3a9b34017c4c84d997152a3aaf3086e1ce1 /lib/rubygems/commands | |
parent | 2614d9ba2fb5ad171200cccc88f42fa659b527c6 (diff) | |
download | ruby-269503b544247b5b3e30dbe60a0bab4f2ca00e4e.tar.gz |
Revert r42938 "* lib/rubygems: Update to RubyGems 2.1.3"
It breaks build.
http://u64.rubyci.org/~chkbuild/ruby-trunk/log/20130913T200302Z.diff.html.gz
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42941 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems/commands')
27 files changed, 1044 insertions, 471 deletions
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb index 64563ed3db..d975429fe8 100644 --- a/lib/rubygems/commands/build_command.rb +++ b/lib/rubygems/commands/build_command.rb @@ -15,6 +15,25 @@ class Gem::Commands::BuildCommand < Gem::Command "GEMSPEC_FILE gemspec file name to build a gem for" end + def description # :nodoc: + <<-EOF +The build command allows you to create a gem from a ruby gemspec. + +The best way to build a gem is to use a Rakefile and the Gem::PackageTask +which ships with RubyGems. + +The gemspec can either be created by hand or extracted from an existing gem +with gem spec: + + $ gem unpack my_gem-1.0.gem + Unpacked gem: '.../my_gem-1.0' + $ gem spec my_gem-1.0.gem --ruby > my_gem-1.0/my_gem-1.0.gemspec + $ cd my_gem-1.0 + [edit gem contents] + $ gem build my_gem-1.0.gemspec + EOF + end + def usage # :nodoc: "#{program_name} GEMSPEC_FILE" end diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb index 5a9320f9c4..e417193bca 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -1,6 +1,11 @@ require 'rubygems/command' require 'rubygems/security' -require 'openssl' +begin + require 'openssl' +rescue LoadError => e + raise unless (e.respond_to?(:path) && e.path == 'openssl') || + e.message =~ / -- openssl$/ +end class Gem::Commands::CertCommand < Gem::Command @@ -21,7 +26,8 @@ class Gem::Commands::CertCommand < Gem::Command OptionParser.accept OpenSSL::PKey::RSA do |key_file| begin - key = OpenSSL::PKey::RSA.new File.read key_file + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase rescue Errno::ENOENT raise OptionParser::InvalidArgument, "#{key_file}: does not exist" rescue OpenSSL::PKey::RSAError @@ -79,52 +85,67 @@ 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 - - options[:sign].each do |cert_file| - sign cert_file - end + sign_certificates unless options[:sign].empty? end def build name - key = options[:key] || Gem::Security.create_key + 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_cert name, key # :nodoc: cert = Gem::Security.create_cert_email name, key + Gem::Security.write cert, "gem-public_cert.pem" + end - key_path = Gem::Security.write key, "gem-private_key.pem" - cert_path = Gem::Security.write cert, "gem-public_cert.pem" + def build_key # :nodoc: + if options[:key] then + options[:key] + else + passphrase = ask_for_password 'Passphrase for your Private Key:' + say "\n" - say "Certificate: #{cert_path}" - say "Private Key: #{key_path}" - say "Don't forget to move the key file to somewhere private!" + passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:' + say "\n" + + raise Gem::CommandLineError, + "Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation + + key = Gem::Security.create_key + key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase + + return key, key_path + end end def certificates_matching filter @@ -179,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 @@ -198,7 +226,8 @@ For further reading on signing gems see `ri Gem::Security`. def load_default_key key_file = File.join Gem.default_key_path key = File.read key_file - options[:key] = OpenSSL::PKey::RSA.new key + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + options[:key] = OpenSSL::PKey::RSA.new key, passphrase rescue Errno::ENOENT alert_error \ "--private-key not specified and ~/.gem/gem-private_key.pem does not exist" @@ -211,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 @@ -225,5 +266,13 @@ For further reading on signing gems see `ri Gem::Security`. Gem::Security.write cert, cert_file, permissions end -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/check_command.rb b/lib/rubygems/commands/check_command.rb index d7677d47a1..8893b9c3b2 100644 --- a/lib/rubygems/commands/check_command.rb +++ b/lib/rubygems/commands/check_command.rb @@ -79,6 +79,13 @@ class Gem::Commands::CheckCommand < Gem::Command '--gems --alien' end + def description # :nodoc: + <<-EOF +The check command can list and repair problems with installed gems and +specifications and will clean up gems that have been partially uninstalled. + EOF + end + def usage # :nodoc: "#{program_name} [OPTIONS] [GEMNAME ...]" end diff --git a/lib/rubygems/commands/cleanup_command.rb b/lib/rubygems/commands/cleanup_command.rb index 61f189e449..c8f0082bfb 100644 --- a/lib/rubygems/commands/cleanup_command.rb +++ b/lib/rubygems/commands/cleanup_command.rb @@ -6,10 +6,11 @@ class Gem::Commands::CleanupCommand < Gem::Command def initialize super 'cleanup', - 'Clean up old versions of installed gems in the local repository', + 'Clean up old versions of installed gems', :force => false, :install_dir => Gem.dir - add_option('-d', '--dryrun', "") do |value, options| + add_option('-n', '-d', '--dryrun', + 'Do not uninstall gems') do |value, options| options[:dryrun] = true end @@ -32,11 +33,11 @@ class Gem::Commands::CleanupCommand < Gem::Command def description # :nodoc: <<-EOF -The cleanup command removes old gems from GEM_HOME. If an older version is -installed elsewhere in GEM_PATH the cleanup command won't touch it. +The cleanup command removes old versions of gems from GEM_HOME that are not +required to meet a dependency. If a gem is installed elsewhere in GEM_PATH +the cleanup command won't delete it. -Older gems that are required to satisify the dependencies of gems -are not removed. +If no gems are named all gems in GEM_HOME are cleaned. EOF end @@ -162,4 +163,3 @@ are not removed. end end - diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb index 42c7fabd86..97218848ed 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: @@ -41,79 +45,126 @@ class Gem::Commands::ContentsCommand < Gem::Command "--no-lib-only --prefix" end + def description # :nodoc: + <<-EOF +The contents command lists the files in an installed gem. The listing can +be given as full file names, file names without the installed directory +prefix or only the files that are requireable. + EOF + end + def usage # :nodoc: "#{program_name} GEMNAME [GEMNAME ...]" 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 - 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 + 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 + + 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 - files.sort.each do |prefix, basename| - absolute_path = File.join(prefix, basename) - next if File.directory? absolute_path + show_files files - if options[:prefix] - say absolute_path - else - say basename - end + 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] 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..c5d6dd7d70 100644 --- a/lib/rubygems/commands/dependency_command.rb +++ b/lib/rubygems/commands/dependency_command.rb @@ -38,89 +38,121 @@ class Gem::Commands::DependencyCommand < Gem::Command "--local --version '#{Gem::Requirement.default}' --no-reverse-dependencies" end + def description # :nodoc: + <<-EOF +The dependency commands lists which other gems a given gem depends on. For +local gems only the reverse dependencies can be shown (which gems depend on +the named gem). + +The dependency list can be displayed in a format suitable for piping for +use with other commands. + EOF + end + def usage # :nodoc: "#{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 - options[:args] << '' if options[:args].empty? + specs.uniq.sort + end + + 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 +163,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 40e71cf094..d32d12b757 100644 --- a/lib/rubygems/commands/environment_command.rb +++ b/lib/rubygems/commands/environment_command.rb @@ -21,6 +21,9 @@ class Gem::Commands::EnvironmentCommand < Gem::Command def description # :nodoc: <<-EOF +The environment command lets you query rubygems for its configuration for +use in shell scripts or as a debugging aid. + The RubyGems environment can be controlled through command line arguments, gemrc files, environment variables and built-in defaults. @@ -69,66 +72,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 << " - INSTALLATION DIRECTORY: #{Gem.dir}\n" - - out << " - RUBYGEMS PREFIX: #{Gem.prefix}\n" unless Gem.prefix.nil? - - out << " - RUBY EXECUTABLE: #{Gem.ruby}\n" - - out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n" - - out << " - RUBYGEMS PLATFORMS:\n" - Gem.platforms.each do |platform| - out << " - #{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 << " - GEM PATHS:\n" - out << " - #{Gem.dir}\n" + def add_path out, path + path.each do |component| + out << " - #{component}\n" + end + end - path = Gem.path.dup - path.delete Gem.dir - path.each do |p| - out << " - #{p}\n" - end + def show_environment # :nodoc: + out = "RubyGems Environment:\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 << " - RUBYGEMS VERSION: #{Gem::VERSION}\n" - out << " - REMOTE SOURCES:\n" - Gem.sources.each do |s| - out << " - #{s}\n" - end + out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}" + out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL + out << ") [#{RUBY_PLATFORM}]\n" + + out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n" + + out << " - RUBYGEMS PREFIX: #{Gem.prefix}\n" unless Gem.prefix.nil? + + out << " - RUBY EXECUTABLE: #{Gem.ruby}\n" + + out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n" - else - raise Gem::CommandLineError, "Unknown environment option [#{arg}]" + out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n" + + out << " - RUBYGEMS PLATFORMS:\n" + Gem.platforms.each do |platform| + out << " - #{platform}\n" end - say out - true + + out << " - GEM PATHS:\n" + out << " - #{Gem.dir}\n" + + gem_path = Gem.path.dup + gem_path.delete Gem.dir + add_path out, gem_path + + 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 << " - 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/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb index ec021359b6..c57ab0089a 100644 --- a/lib/rubygems/commands/fetch_command.rb +++ b/lib/rubygems/commands/fetch_command.rb @@ -28,6 +28,16 @@ class Gem::Commands::FetchCommand < Gem::Command "--version '#{Gem::Requirement.default}'" end + def description # :nodoc: + <<-EOF +The fetch command fetches gem files that can be stored for later use or +unpacked to examine their contents. + +See the build command help for an example of unpacking a gem, modifying it, +then repackaging it. + EOF + end + def usage # :nodoc: "#{program_name} GEMNAME [GEMNAME ...]" end @@ -42,13 +52,15 @@ class Gem::Commands::FetchCommand < Gem::Command dep = Gem::Dependency.new gem_name, version dep.prerelease = options[:prerelease] - specs_and_sources, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep + specs_and_sources, errors = + Gem::SpecFetcher.fetcher.spec_for_dependency dep + if platform then filtered = specs_and_sources.select { |s,| s.platform == platform } specs_and_sources = filtered unless filtered.empty? end - spec, source = specs_and_sources.sort_by { |s,| s.version }.first + spec, source = specs_and_sources.max_by { |s,| s.version } if spec.nil? then show_lookup_failure gem_name, version, errors, options[:domain] diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb index 7f1fb486e0..ed7be903ac 100644 --- a/lib/rubygems/commands/help_command.rb +++ b/lib/rubygems/commands/help_command.rb @@ -46,6 +46,10 @@ Some examples of 'gem' usage. * Update all gems on your system: gem update + +* Update your local version of RubyGems + + gem update --system EOF PLATFORMS = <<-'EOF' @@ -55,8 +59,9 @@ your current platform by running `gem environment`. RubyGems matches platforms as follows: - * The CPU must match exactly, unless one of the platforms has - "universal" as the CPU. + * The CPU must match exactly unless one of the platforms has + "universal" as the CPU or the local CPU starts with "arm" and the gem's + CPU is exactly "arm" (for gems that support generic ARM architecture). * The OS must match exactly. * The versions must match exactly unless one of the versions is nil. @@ -66,11 +71,20 @@ you pass must match "#{cpu}-#{os}" or "#{cpu}-#{os}-#{version}". On mswin platforms, the version is the compiler version, not the OS version. (Ruby compiled with VC6 uses "60" as the compiler version, VC8 uses "80".) +For the ARM architecture, gems with a platform of "arm-linux" should run on a +reasonable set of ARM CPUs and not depend on instructions present on a limited +subset of the architecture. For example, the binary should run on platforms +armv5, armv6hf, armv6l, armv7, etc. If you use the "arm-linux" platform +please test your gem on a variety of ARM hardware before release to ensure it +functions correctly. + Example platforms: x86-freebsd # Any FreeBSD version on an x86 CPU universal-darwin-8 # Darwin 8 only gems that run on any CPU x86-mswin32-80 # Windows gems compiled with VC8 + armv7-linux # Gem complied for an ARMv7 CPU running linux + arm-linux # Gem compiled for any ARM CPU running linux When building platform gems, set the platform in the gem specification to Gem::Platform::CURRENT. This will correctly mark the gem with your ruby's @@ -80,6 +94,8 @@ platform. def initialize super 'help', "Provide help on the 'gem' command" + + @command_manager = Gem::CommandManager.instance end def arguments # :nodoc: @@ -96,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}, bug?]" - 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 @@ -147,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 0b58fa665e..f02b12906d 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -4,8 +4,6 @@ require 'rubygems/dependency_installer' require 'rubygems/local_remote_options' require 'rubygems/validator' require 'rubygems/version_option' -require 'rubygems/install_message' # must come before rdoc for messaging -require 'rubygems/rdoc' ## # Gem installer command line tool @@ -40,6 +38,12 @@ class Gem::Commands::InstallCommand < Gem::Command o[:gemdeps] = v end + add_option(:"Install/Update", '--default', + 'Add the gem\'s full specification to', + 'specifications/default and extract only its bin') do |v,o| + o[:install_as_default] = v + end + @installed_specs = nil end @@ -109,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 @@ -131,51 +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 - - 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 @@ -186,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 - raise Gem::SystemExitException, exit_code + 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 + + 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/list_command.rb b/lib/rubygems/commands/list_command.rb index f3e5da9551..0d15950475 100644 --- a/lib/rubygems/commands/list_command.rb +++ b/lib/rubygems/commands/list_command.rb @@ -8,7 +8,7 @@ require 'rubygems/commands/query_command' class Gem::Commands::ListCommand < Gem::Commands::QueryCommand def initialize - super 'list', 'Display gems whose name starts with STRING' + super 'list', 'Display local gems whose name starts with STRING' remove_option('--name-matches') end @@ -21,6 +21,17 @@ class Gem::Commands::ListCommand < Gem::Commands::QueryCommand "--local --no-details" end + def description # :nodoc: + <<-EOF +The list command is used to view the gems you have installed locally. + +The --details option displays additional details including the summary, the +homepage, the author, the locations of different versions of the gem. + +To search for remote gems use the search command. + EOF + end + def usage # :nodoc: "#{program_name} [STRING]" end diff --git a/lib/rubygems/commands/mirror_command.rb b/lib/rubygems/commands/mirror_command.rb index 0f98077cbd..75419c857a 100644 --- a/lib/rubygems/commands/mirror_command.rb +++ b/lib/rubygems/commands/mirror_command.rb @@ -10,6 +10,12 @@ class Gem::Commands::MirrorCommand < Gem::Command end end + def description # :nodoc: + <<-EOF +The mirror command has been moved to the rubygems-mirror gem. + EOF + end + def execute alert_error "Install the rubygems-mirror gem for the mirror command" end diff --git a/lib/rubygems/commands/outdated_command.rb b/lib/rubygems/commands/outdated_command.rb index 887faab0a2..f51bc5e93f 100644 --- a/lib/rubygems/commands/outdated_command.rb +++ b/lib/rubygems/commands/outdated_command.rb @@ -15,19 +15,18 @@ class Gem::Commands::OutdatedCommand < Gem::Command add_platform_option end - def execute - Gem::Specification.outdated.sort.each do |name| - local = Gem::Specification.find_all_by_name(name).max - dep = Gem::Dependency.new local.name, ">= #{local.version}" - remotes, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep - - next if remotes.empty? - - remotes.sort! { |a,b| a[0].version <=> b[0].version } + def description # :nodoc: + <<-EOF +The outdated command lists gems you way wish to upgrade to a newer version. - highest = remotes.last.first +You can check for dependency mismatches using the dependency command and +update the gems with the update or install commands. + EOF + end - say "#{local.name} (#{local.version} < #{highest.version})" + def execute + Gem::Specification.outdated_and_latest_version.each do |spec, remote_version| + say "#{spec.name} (#{spec.version} < #{remote_version})" end end end diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb index 11e6e026fd..13b8793021 100644 --- a/lib/rubygems/commands/owner_command.rb +++ b/lib/rubygems/commands/owner_command.rb @@ -7,7 +7,14 @@ class Gem::Commands::OwnerCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - 'Manage gem owners on RubyGems.org.' + <<-EOF +The owner command lets you add and remove owners of a gem on a push +server (the default is https://rubygems.org). + +The owner of a gem has the permission to push new versions, yank existing +versions or edit the HTML page of the gem. Be careful of who you give push +permission to. + EOF end def arguments # :nodoc: @@ -19,7 +26,7 @@ class Gem::Commands::OwnerCommand < Gem::Command end def initialize - super 'owner', description + super 'owner', 'Manage gem owners of a gem on the push server' add_proxy_option add_key_option defaults.merge! :add => [], :remove => [] @@ -31,9 +38,15 @@ class Gem::Commands::OwnerCommand < Gem::Command add_option '-r', '--remove EMAIL', 'Remove an owner' do |value, options| options[:remove] << value end + + add_option '-h', '--host HOST', 'Use another gemcutter-compatible host' do |value, options| + options[:host] = value + end end def execute + @host = options[:host] + sign_in name = get_one_gem_name diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index 8d479211ac..3f3bca45be 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -31,6 +31,12 @@ class Gem::Commands::PristineCommand < Gem::Command options[:only_executables] = value end + add_option('-E', '--[no-]env-shebang', + 'Rewrite executables with a shebang', + 'of /usr/bin/env') do |value, options| + options[:env_shebang] = value + end + add_version_option('restore to', 'pristine condition') end @@ -105,16 +111,21 @@ with an extension. Gem::RemoteFetcher.fetcher.download_to_cache dep end - # TODO use installer options - install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install'] - installer_env_shebang = install_defaults.to_s['--env-shebang'] + env_shebang = + if options.include? :env_shebang then + options[:env_shebang] + else + install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install'] + install_defaults.to_s['--env-shebang'] + end installer = Gem::Installer.new(gem, :wrappers => true, :force => true, :install_dir => spec.base_dir, - :env_shebang => installer_env_shebang, + :env_shebang => env_shebang, :build_args => spec.build_args) + if options[:only_executables] then installer.generate_bin else diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb index fccad206fa..b90be7bd10 100644 --- a/lib/rubygems/commands/push_command.rb +++ b/lib/rubygems/commands/push_command.rb @@ -8,7 +8,13 @@ class Gem::Commands::PushCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - 'Push a gem up to RubyGems.org' + <<-EOF +The push command uploads a gem to the push server (the default is +https://rubygems.org) and adds it to the index. + +The gem can be removed from the index (but only the index) using the yank +command. For further discussion see the help for the yank command. + EOF end def arguments # :nodoc: @@ -20,7 +26,7 @@ class Gem::Commands::PushCommand < Gem::Command end def initialize - super 'push', description, :host => self.host + super 'push', 'Push a gem up to the gem server', :host => self.host add_proxy_option add_key_option diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb index 05b214bb63..c9c3014975 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -61,6 +61,15 @@ class Gem::Commands::QueryCommand < Gem::Command "--local --name-matches // --no-details --versions --no-installed" end + def description # :nodoc: + <<-EOF +The query command is the basis for the list and search commands. + +You should really use the list and search commands instead. This command +is too hard to use. + EOF + end + def execute exit_code = 0 diff --git a/lib/rubygems/commands/rdoc_command.rb b/lib/rubygems/commands/rdoc_command.rb index df00f3a5df..86597f99a6 100644 --- a/lib/rubygems/commands/rdoc_command.rb +++ b/lib/rubygems/commands/rdoc_command.rb @@ -45,8 +45,12 @@ class Gem::Commands::RdocCommand < Gem::Command def description # :nodoc: <<-DESC -The rdoc command builds RDoc and RI documentation for installed gems. Use ---overwrite to force rebuilding of documentation. +The rdoc command builds documentation for installed gems. By default +only documentation is built using rdoc, but additional types of +documentation may be built through rubygems plugins and the +Gem.post_installs hook. + +Use --overwrite to force rebuilding of documentation. DESC end diff --git a/lib/rubygems/commands/search_command.rb b/lib/rubygems/commands/search_command.rb index c125715fe2..5bc9650672 100644 --- a/lib/rubygems/commands/search_command.rb +++ b/lib/rubygems/commands/search_command.rb @@ -4,7 +4,7 @@ require 'rubygems/commands/query_command' class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand def initialize - super 'search', 'Display all gems whose name contains STRING' + super 'search', 'Display remote gems whose name contains STRING' remove_option '--name-matches' @@ -19,6 +19,19 @@ class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand "--remote --no-details" end + def description # :nodoc: + <<-EOF +The search command displays remote gems whose name contains the given +string. + +The --details option displays additional details from the gem but will +take a little longer to complete as it must download the information +individually from the index. + +To list local gems use the list command. + EOF + end + def usage # :nodoc: "#{program_name} [STRING]" end diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb index f4cc3e57ae..60d96c5828 100644 --- a/lib/rubygems/commands/sources_command.rb +++ b/lib/rubygems/commands/sources_command.rb @@ -37,103 +37,165 @@ class Gem::Commands::SourcesCommand < Gem::Command add_proxy_option end - def defaults_str - '--list' - end - - def execute - options[:list] = !(options[:add] || - options[:clear_all] || - options[:remove] || - options[:update]) + def add_source source_uri # :nodoc: + check_rubygems_https source_uri - if options[:clear_all] then - path = File.join Gem.user_home, '.gem', 'specs' - FileUtils.rm_rf path + source = Gem::Source.new source_uri - 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 + QUESTION - terminate_interaction 1 unless ask_yes_no question - end - - 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 description # :nodoc: + <<-EOF +RubyGems fetches gems from the sources you have configured (stored in your +~/.gemrc). + +The default source is https://rubygems.org, but you may have older sources +configured. This guide will help you update your sources or configure +yourself to use your own gem server. + +Without any arguments the sources lists your currently configured sources: + + $ gem sources + *** CURRENT SOURCES *** + + https://rubygems.org + +This may list multiple sources or non-rubygems sources. You probably +configured them before or have an old `~/.gemrc`. If you have sources you +do not recognize you should remove them. + +RubyGems has been configured to serve gems via the following URLs through +its history: - say "source cache successfully updated" +* http://gems.rubyforge.org (RubyGems 1.3.6 and earlier) +* http://rubygems.org (RubyGems 1.3.7 through 1.8.25) +* https://rubygems.org (RubyGems 2.0.1 and newer) + +Since all of these sources point to the same set of gems you only need one +of them in your list. https://rubygems.org is recommended as it brings the +protections of an SSL connection to gem downloads. + +To add a source use the --add argument: + + $ gem sources --add https://rubygems.org + https://rubygems.org added to sources + +RubyGems will check to see if gems can be installed from the source given +before it is added. + +To remove a source use the --remove argument: + + $ gem sources --remove http://rubygems.org + http://rubygems.org removed from sources + + EOF + end + + def list # :nodoc: + say "*** CURRENT SOURCES ***" + say + + 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/specification_command.rb b/lib/rubygems/commands/specification_command.rb index b40dfd5f3c..d96c8b8627 100644 --- a/lib/rubygems/commands/specification_command.rb +++ b/lib/rubygems/commands/specification_command.rb @@ -50,6 +50,22 @@ FIELD name of gemspec field to show "--local --version '#{Gem::Requirement.default}' --yaml" end + def description # :nodoc: + <<-EOF +The specification command allows you to extract the specification from +a gem for examination. + +The specification can be output in YAML, ruby or Marshal formats. + +Specific fields in the specification can be extracted in YAML format: + + $ gem spec rake summary + --- Ruby based make-like utility. + ... + + EOF + end + def usage # :nodoc: "#{program_name} [GEMFILE] [FIELD]" end diff --git a/lib/rubygems/commands/stale_command.rb b/lib/rubygems/commands/stale_command.rb index 36c517e27c..0ef0755960 100644 --- a/lib/rubygems/commands/stale_command.rb +++ b/lib/rubygems/commands/stale_command.rb @@ -5,6 +5,16 @@ class Gem::Commands::StaleCommand < Gem::Command super('stale', 'List gems along with access times') end + def description # :nodoc: + <<-EOF +The stale command lists the latest access time for all the files in your +installed gems. + +You can use this command to discover gems and gem versions you are no +longer using. + EOF + end + def usage # :nodoc: "#{program_name}" end diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb index 56aa8ee57f..8e6af2ba65 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' @@ -67,6 +68,12 @@ class Gem::Commands::UninstallCommand < Gem::Command options[:force] = value end + add_option('--[no-]abort-on-dependent', + 'Prevent uninstalling gems that are', + 'depended on by other gems.') do |value, options| + options[:abort_on_dependent] = value + end + add_version_option add_platform_option end @@ -81,13 +88,49 @@ class Gem::Commands::UninstallCommand < Gem::Command "--user-install" end + def description # :nodoc: + <<-EOF +The uninstall command removes a previously installed gem. + +RubyGems will ask for confirmation if you are attempting to uninstall a gem +that is a dependency of an existing gem. You can use the +--ignore-dependencies option to skip this check. + EOF + end + def usage # :nodoc: "#{program_name} GEMNAME [GEMNAME ...]" 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 + _, specs = Gem::Specification.partition { |spec| spec.default_gem? } + + specs.each do |spec| + options[:version] = spec.version + + begin + Gem::Uninstaller.new(spec.name, options).uninstall + rescue Gem::InstallError + end + end + + alert "Uninstalled all gems in #{options[: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/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb index 7eefd32a6e..e60e7d90fd 100644 --- a/lib/rubygems/commands/unpack_command.rb +++ b/lib/rubygems/commands/unpack_command.rb @@ -34,6 +34,24 @@ class Gem::Commands::UnpackCommand < Gem::Command "--version '#{Gem::Requirement.default}'" end + def description + <<-EOF +The unpack command allows you to examine the contents of a gem or modify +them to help diagnose a bug. + +You can add the contents of the unpacked gem to the load path using the +RUBYLIB environment variable or -I: + + $ gem unpack my_gem + Unpacked gem: '.../my_gem-1.0' + [edit my_gem-1.0/lib/my_gem.rb] + $ ruby -Imy_gem-1.0/lib -S other_program + +You can repackage an unpacked gem using the build command. See the build +command help for an example. + EOF + end + def usage # :nodoc: "#{program_name} GEMNAME" end diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index a31de0071a..77bf5edb45 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -52,27 +52,46 @@ class Gem::Commands::UpdateCommand < Gem::Command "--document --no-force --install-dir #{Gem.dir}" end + def description # :nodoc: + <<-EOF +The update command will update your gems to the latest version. + +The update comamnd does not remove the previous version. Use the cleanup +command to remove old versions. + EOF + end + def usage # :nodoc: "#{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 +104,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 +179,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 +254,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/commands/which_command.rb b/lib/rubygems/commands/which_command.rb index 6495278a87..99b9085b2b 100644 --- a/lib/rubygems/commands/which_command.rb +++ b/lib/rubygems/commands/which_command.rb @@ -23,6 +23,17 @@ class Gem::Commands::WhichCommand < Gem::Command "--no-gems-first --no-all" end + def description # :nodoc: + <<-EOF +The which command is like the shell which command and shows you where +the file you wish to require lives. + +You can use the which command to help determine why you are requiring a +version you did not expect or to look at the content of a file you are +requiring to see why it does not behave as you expect. + EOF + end + def execute found = false diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb index df4142d395..2285bb4017 100644 --- a/lib/rubygems/commands/yank_command.rb +++ b/lib/rubygems/commands/yank_command.rb @@ -9,7 +9,21 @@ class Gem::Commands::YankCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - 'Remove a specific gem version release from RubyGems.org' + <<-EOF +The yank command removes a gem you pushed to a server from the server's +index. + +Note that if you push a gem to rubygems.org the yank command does not +prevent other people from downloading the gem via the download link. + +Once you have pushed a gem several downloads will happen automatically +via the webhooks. If you accidentally pushed passwords or other sensitive +data you will need to change them immediately and yank your gem. + +If you are yanking a gem due to intellectual property reasons contact +http://help.rubygems.org for permanant removal. Be sure to mention this +as the reason for the removal request. + EOF end def arguments # :nodoc: @@ -21,7 +35,7 @@ class Gem::Commands::YankCommand < Gem::Command end def initialize - super 'yank', description + super 'yank', 'Remove a pushed gem from the index' add_version_option("remove") add_platform_option("remove") |