diff options
110 files changed, 3351 insertions, 4800 deletions
@@ -1,10 +1,4 @@ -Thu Sep 12 14:58:58 2013 NARUSE, Yui <naruse@ruby-lang.org> - - * lib/uri/generic.rb (URI::Generic.find_proxy): return nil if - http_proxy environment variable is empty string. - [ruby-core:57140] [Bug #8898] - -Fri Sep 13 10:40:28 2013 Eric Hodel <drbrain@segment7.net> +Sat Sep 14 04:57:51 2013 Eric Hodel <drbrain@segment7.net> * lib/rubygems: Update to RubyGems 2.1.3 @@ -22,6 +16,13 @@ Fri Sep 13 10:40:28 2013 Eric Hodel <drbrain@segment7.net> * NEWS: Updated for RubyGems 2.1.3 + +Thu Sep 12 14:58:58 2013 NARUSE, Yui <naruse@ruby-lang.org> + + * lib/uri/generic.rb (URI::Generic.find_proxy): return nil if + http_proxy environment variable is empty string. + [ruby-core:57140] [Bug #8898] + Thu Sep 12 22:40:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> * configure.in (RUBY_CHECK_SIGNEDNESS): macro to check signedness of a diff --git a/lib/rubygems.rb b/lib/rubygems.rb index fac38e4143..78bdc4867d 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = '2.1.3' + VERSION = '2.0.8' end # Must be first since it unloads the prelude from 1.9.2 @@ -115,7 +115,7 @@ module Gem RUBYGEMS_DIR = File.dirname File.expand_path(__FILE__) ## - # An Array of Regexps that match windows Ruby platforms. + # An Array of Regexps that match windows ruby platforms. WIN_PATTERNS = [ /bccwin/i, @@ -143,14 +143,6 @@ module Gem specifications ] - ## - # Subdirectories in a gem repository for default gems - - REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES = %w[ - gems - specifications/default - ] - @@win_platform = nil @configuration = nil @@ -387,10 +379,6 @@ module Gem paths.path end - def self.spec_cache_dir - paths.spec_cache_dir - end - ## # Quietly ensure the Gem directory +dir+ contains all the proper # subdirectories. If we can't create a directory due to a permission @@ -401,23 +389,6 @@ module Gem # World-writable directories will never be created. def self.ensure_gem_subdirectories dir = Gem.dir, mode = nil - ensure_subdirectories(dir, mode, REPOSITORY_SUBDIRECTORIES) - end - - ## - # Quietly ensure the Gem directory +dir+ contains all the proper - # subdirectories for handling default gems. If we can't create a - # directory due to a permission problem, then we will silently continue. - # - # If +mode+ is given, missing directories are created with this mode. - # - # World-writable directories will never be created. - - def self.ensure_default_gem_subdirectories dir = Gem.dir, mode = nil - ensure_subdirectories(dir, mode, REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES) - end - - def self.ensure_subdirectories dir, mode, subdirs # :nodoc: old_umask = File.umask File.umask old_umask | 002 @@ -427,7 +398,7 @@ module Gem options[:mode] = mode if mode - subdirs.each do |name| + REPOSITORY_SUBDIRECTORIES.each do |name| subdir = File.join dir, name next if File.exist? subdir FileUtils.mkdir_p subdir, options rescue nil @@ -446,12 +417,16 @@ 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. See also find_latest_files + # versions of the same gem. def self.find_files(glob, check_load_path=true) files = [] - files = find_files_from_load_path glob if check_load_path + 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.concat Gem::Specification.map { |spec| spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}") @@ -464,40 +439,6 @@ 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. #-- @@ -852,7 +793,7 @@ module Gem end ## - # A Gem::Version for the currently running Ruby. + # A Gem::Version for the currently running ruby. def self.ruby_version return @ruby_version if defined? @ruby_version @@ -975,9 +916,9 @@ module Gem end ## - # Load +plugins+ as Ruby files + # Load +plugins+ as ruby files - def self.load_plugin_files plugins # :nodoc: + def self.load_plugin_files(plugins) plugins.each do |plugin| # Skip older versions of the GemCutter plugin: Its commands are in @@ -995,16 +936,10 @@ module Gem end ## - # Find the 'rubygems_plugin' files in the latest installed gems and load - # them + # Find all 'rubygems_plugin' files in installed gems and load them def self.load_plugins - # Remove this env var by at least 3.0 - if ENV['RUBYGEMS_LOAD_ALL_PLUGINS'] - load_plugin_files find_files('rubygems_plugin', false) - else - load_plugin_files find_latest_files('rubygems_plugin', false) - end + load_plugin_files find_files('rubygems_plugin', false) end ## @@ -1036,31 +971,10 @@ module Gem attr_reader :loaded_specs ## - # Register a Gem::Specification for default gem. - # - # Two formats for the specification are supported: - # - # * MRI 2.0 style, where spec.files contains unprefixed require names. - # The spec's filenames will be registered as-is. - # * New style, where spec.files contains files prefixed with paths - # from spec.require_paths. The prefixes are stripped before - # registering the spec's filenames. Unprefixed files are omitted. - # + # Register a Gem::Specification for default gem def register_default_spec(spec) - new_format = Gem.default_gems_use_full_paths? || spec.require_paths.any? {|path| spec.files.any? {|f| f.start_with? path } } - - if new_format - prefix_group = spec.require_paths.map {|f| f + "/"}.join("|") - prefix_pattern = /^(#{prefix_group})/ - end - spec.files.each do |file| - if new_format - file = file.sub(prefix_pattern, "") - next unless $~ - end - @path_to_default_spec_map[file] = spec end end @@ -1177,7 +1091,7 @@ unless gem_preluded then # TODO: remove guard after 1.9.2 dropped if defined?(RUBY_ENGINE) then begin ## - # Defaults the Ruby implementation wants to provide for RubyGems + # Defaults the ruby implementation wants to provide for RubyGems require "rubygems/defaults/#{RUBY_ENGINE}" rescue LoadError diff --git a/lib/rubygems/available_set.rb b/lib/rubygems/available_set.rb index bb0b3a3abe..80539feee9 100644 --- a/lib/rubygems/available_set.rb +++ b/lib/rubygems/available_set.rb @@ -1,7 +1,4 @@ class Gem::AvailableSet - - include Enumerable - Tuple = Struct.new(:spec, :source) def initialize @@ -39,28 +36,6 @@ class Gem::AvailableSet self end - ## - # Yields each Tuple in this AvailableSet - - def each - return enum_for __method__ unless block_given? - - @set.each do |tuple| - yield tuple - end - end - - ## - # Yields the Gem::Specification for each Tuple in this AvailableSet - - def each_spec - return enum_for __method__ unless block_given? - - each do |tuple| - yield tuple.spec - end - end - def empty? @set.empty? end @@ -91,49 +66,6 @@ class Gem::AvailableSet f.source end - ## - # Converts this AvailableSet into a RequestSet that can be used to install - # gems. - # - # If +development+ is :none then no development dependencies are installed. - # Other options are :shallow for only direct development dependencies of the - # gems in this set or :all for all development dependencies. - - def to_request_set development = :none - request_set = Gem::RequestSet.new - request_set.development = :all == development - - each_spec do |spec| - request_set.always_install << spec - - request_set.gem spec.name, spec.version - request_set.import spec.development_dependencies if - :shallow == development - end - - request_set - end - - ## - # - # Used by the DependencyResolver, the protocol to use a AvailableSet as a - # search Set. - - def find_all(req) - dep = req.dependency - - match = @set.find_all do |t| - dep.matches_spec? t.spec - end - - match.map do |t| - Gem::DependencyResolver::InstalledSpecification.new(self, t.spec, t.source) - end - end - - def prefetch(reqs) - end - def pick_best! return self if empty? diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index fdee064fed..2af582177d 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -33,39 +33,6 @@ 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. @@ -94,10 +61,36 @@ class Gem::CommandManager def initialize require 'timeout' @commands = {} - - BUILTIN_COMMANDS.each do |name| - register_command name - end + 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 end ## @@ -139,6 +132,14 @@ 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" @@ -146,6 +147,8 @@ 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/build_command.rb b/lib/rubygems/commands/build_command.rb index d975429fe8..64563ed3db 100644 --- a/lib/rubygems/commands/build_command.rb +++ b/lib/rubygems/commands/build_command.rb @@ -15,25 +15,6 @@ 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 e417193bca..5a9320f9c4 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -1,11 +1,6 @@ require 'rubygems/command' require 'rubygems/security' -begin - require 'openssl' -rescue LoadError => e - raise unless (e.respond_to?(:path) && e.path == 'openssl') || - e.message =~ / -- openssl$/ -end +require 'openssl' class Gem::Commands::CertCommand < Gem::Command @@ -26,8 +21,7 @@ class Gem::Commands::CertCommand < Gem::Command OptionParser.accept OpenSSL::PKey::RSA do |key_file| begin - passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] - key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase + key = OpenSSL::PKey::RSA.new File.read key_file rescue Errno::ENOENT raise OptionParser::InvalidArgument, "#{key_file}: does not exist" rescue OpenSSL::PKey::RSAError @@ -85,67 +79,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| - add_certificate certificate + Gem::Security.trust_dir.trust_cert certificate + + say "Added '#{certificate.subject}'" end options[:remove].each do |filter| - remove_certificates_matching filter + certificates_matching filter do |certificate, path| + FileUtils.rm path + say "Removed '#{certificate.subject}'" + end end options[:list].each do |filter| - list_certificates_matching filter + certificates_matching filter do |certificate, _| + # this could probably be formatted more gracefully + say certificate.subject.to_s + end end options[:build].each do |name| build name end - sign_certificates unless options[:sign].empty? - end - - 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!" + unless options[:sign].empty? then + load_default_cert unless options[:issuer_cert] + load_default_key unless options[:key] end - end - def build_cert name, key # :nodoc: - cert = Gem::Security.create_cert_email name, key - Gem::Security.write cert, "gem-public_cert.pem" + options[:sign].each do |cert_file| + sign cert_file + end end - def build_key # :nodoc: - if options[:key] then - options[:key] - else - passphrase = ask_for_password 'Passphrase for your Private Key:' - say "\n" - - passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:' - say "\n" + def build name + key = options[:key] || Gem::Security.create_key - raise Gem::CommandLineError, - "Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation + cert = Gem::Security.create_cert_email name, key - key = Gem::Security.create_key - key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase + key_path = Gem::Security.write key, "gem-private_key.pem" + cert_path = Gem::Security.write cert, "gem-public_cert.pem" - return key, key_path - end + say "Certificate: #{cert_path}" + say "Private Key: #{key_path}" + say "Don't forget to move the key file to somewhere private!" end def certificates_matching filter @@ -200,13 +179,6 @@ 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 @@ -226,8 +198,7 @@ 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 - passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] - options[:key] = OpenSSL::PKey::RSA.new key, passphrase + options[:key] = OpenSSL::PKey::RSA.new key rescue Errno::ENOENT alert_error \ "--private-key not specified and ~/.gem/gem-private_key.pem does not exist" @@ -240,18 +211,6 @@ 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 @@ -266,13 +225,5 @@ 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) +end diff --git a/lib/rubygems/commands/check_command.rb b/lib/rubygems/commands/check_command.rb index 8893b9c3b2..d7677d47a1 100644 --- a/lib/rubygems/commands/check_command.rb +++ b/lib/rubygems/commands/check_command.rb @@ -79,13 +79,6 @@ 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 c8f0082bfb..61f189e449 100644 --- a/lib/rubygems/commands/cleanup_command.rb +++ b/lib/rubygems/commands/cleanup_command.rb @@ -6,11 +6,10 @@ class Gem::Commands::CleanupCommand < Gem::Command def initialize super 'cleanup', - 'Clean up old versions of installed gems', + 'Clean up old versions of installed gems in the local repository', :force => false, :install_dir => Gem.dir - add_option('-n', '-d', '--dryrun', - 'Do not uninstall gems') do |value, options| + add_option('-d', '--dryrun', "") do |value, options| options[:dryrun] = true end @@ -33,11 +32,11 @@ class Gem::Commands::CleanupCommand < Gem::Command def description # :nodoc: <<-EOF -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. +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. -If no gems are named all gems in GEM_HOME are cleaned. +Older gems that are required to satisify the dependencies of gems +are not removed. EOF end @@ -163,3 +162,4 @@ If no gems are named all gems in GEM_HOME are cleaned. end end + diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb index 97218848ed..42c7fabd86 100644 --- a/lib/rubygems/commands/contents_command.rb +++ b/lib/rubygems/commands/contents_command.rb @@ -31,10 +31,6 @@ 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: @@ -45,125 +41,78 @@ 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 - @spec_dirs = specification_directories - @path_kind = path_description @spec_dirs - - names = gem_names - - 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 + version = options[:version] || Gem::Requirement.default - 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 + spec_dirs = options[:specdirs].map do |i| + [i, File.join(i, "specifications")] + end.flatten - 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::ConfigMap[:rubylibdir], file] + 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 - end - end - - def gem_contents name - spec = spec_for name - - return false unless spec - files = files_in spec - - show_files files - - 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 + 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 else - say basename + 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 end - end - end - - def spec_for name - spec = Gem::Specification.find_all_by_name(name, @version).last - return spec if spec + files.sort.each do |prefix, basename| + absolute_path = File.join(prefix, basename) + next if File.directory? absolute_path - say "Unable to find gem '#{name}' in #{@path_kind}" - - if Gem.configuration.verbose then - say "\nDirectories searched:" - @spec_dirs.sort.each { |dir| say dir } + if options[:prefix] + say absolute_path + else + say basename + end + end 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 c5d6dd7d70..4690b13a94 100644 --- a/lib/rubygems/commands/dependency_command.rb +++ b/lib/rubygems/commands/dependency_command.rb @@ -38,121 +38,89 @@ 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 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 + 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 gem_dependency args, version, prerelease # :nodoc: - args << '' if args.empty? + options[:args] << '' if options[:args].empty? - pattern = if args.length == 1 and args.first =~ /\A\/(.*)\/(i)?\z/m then + pattern = if options[:args].length == 1 and + options[:args].first =~ /\A\/(.*)\/(i)?\z/m then flags = $2 ? Regexp::IGNORECASE : nil Regexp.new $1, flags else - /\A#{Regexp.union(*args)}/ + /\A#{Regexp.union(*options[:args])}/ end + # TODO: deprecate for real damnit dependency = Gem::Deprecate.skip_during { - Gem::Dependency.new pattern, version + Gem::Dependency.new pattern, options[:version] } + dependency.prerelease = options[:prerelease] - dependency.prerelease = prerelease + specs = [] - dependency - end + specs.concat dependency.matching_specs if local? - 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 + if remote? and not options[:reverse_dependencies] then + fetcher = Gem::SpecFetcher.fetcher - def display_readable specs, reverse # :nodoc: - response = '' + ss, _ = fetcher.spec_for_dependency dependency - 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" + ss.each { |s,o| specs << s } end - say response - end + if specs.empty? then + patterns = options[:args].join ',' + say "No gems found matching #{patterns} (#{options[:version]})" if + Gem.configuration.verbose - def execute - ensure_local_only_reverse_dependencies + terminate_interaction 1 + end - dependency = - gem_dependency options[:args], options[:version], options[:prerelease] + specs = specs.uniq.sort - specs = fetch_specs dependency + reverse = Hash.new { |h, k| h[k] = [] } - reverse = reverse_dependencies specs + if options[:reverse_dependencies] then + specs.each do |spec| + reverse[spec.full_name] = find_reverse_dependencies spec + end + end if options[:pipe_format] then - display_pipe specs + 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 else - display_readable specs, reverse - end - end + 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 - 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 + say response end end - 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: + def print_dependencies(spec, level = 0) response = '' response << ' ' * level + "Gem #{spec.full_name}\n" unless spec.dependencies.empty? then @@ -163,30 +131,10 @@ use with other commands. 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 # :nodoc: + def find_reverse_dependencies(spec) result = [] Gem::Specification.each do |sp| diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb index d32d12b757..40e71cf094 100644 --- a/lib/rubygems/commands/environment_command.rb +++ b/lib/rubygems/commands/environment_command.rb @@ -21,9 +21,6 @@ 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. @@ -72,83 +69,66 @@ lib/rubygems/defaults/operating_system.rb def execute out = '' arg = options[:args][0] - 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}]" + 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" end - say out - true - end - - def add_path out, path - path.each do |component| - out << " - #{component}\n" - end - end - - def show_environment # :nodoc: - 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 << " - GEM PATHS:\n" + out << " - #{Gem.dir}\n" - out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n" - - out << " - RUBYGEMS PLATFORMS:\n" - Gem.platforms.each do |platform| - out << " - #{platform}\n" - end - - out << " - GEM PATHS:\n" - out << " - #{Gem.dir}\n" + path = Gem.path.dup + path.delete Gem.dir + path.each do |p| + out << " - #{p}\n" + end - 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 << " - 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 << " - REMOTE SOURCES:\n" - Gem.sources.each do |s| - out << " - #{s}\n" + else + raise Gem::CommandLineError, "Unknown environment option [#{arg}]" end - - out << " - SHELL PATH:\n" - - shell_path = ENV['PATH'].split(File::PATH_SEPARATOR) - add_path out, shell_path - - out + say out + true end end diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb index c57ab0089a..ec021359b6 100644 --- a/lib/rubygems/commands/fetch_command.rb +++ b/lib/rubygems/commands/fetch_command.rb @@ -28,16 +28,6 @@ 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 @@ -52,15 +42,13 @@ then repackaging it. 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.max_by { |s,| s.version } + spec, source = specs_and_sources.sort_by { |s,| s.version }.first 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 ed7be903ac..7f1fb486e0 100644 --- a/lib/rubygems/commands/help_command.rb +++ b/lib/rubygems/commands/help_command.rb @@ -46,10 +46,6 @@ 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' @@ -59,9 +55,8 @@ 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 or the local CPU starts with "arm" and the gem's - CPU is exactly "arm" (for gems that support generic ARM architecture). + * The CPU must match exactly, unless one of the platforms has + "universal" as the CPU. * The OS must match exactly. * The versions must match exactly unless one of the versions is nil. @@ -71,20 +66,11 @@ 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 @@ -94,8 +80,6 @@ platform. def initialize super 'help', "Provide help on the 'gem' command" - - @command_manager = Gem::CommandManager.instance end def arguments # :nodoc: @@ -112,92 +96,78 @@ platform. end def execute + command_manager = Gem::CommandManager.instance arg = options[:args][0] if begins? "commands", arg then - show_commands - - elsif begins? "options", arg then - say Gem::Command::HELP + out = [] + out << "GEM commands are:" + out << nil - elsif begins? "examples", arg then - say EXAMPLES + margin_width = 4 - elsif begins? "platforms", arg then - say PLATFORMS + desc_width = command_manager.command_names.map { |n| n.size }.max + 4 - elsif options[:help] then - show_help + summary_width = 80 - margin_width - desc_width + wrap_indent = ' ' * (margin_width + desc_width) + format = "#{' ' * margin_width}%-#{desc_width}s%s" - elsif arg then - show_command_help arg + command_manager.command_names.each do |cmd_name| + command = command_manager[cmd_name] - else - say Gem::Command::HELP - end - end + summary = + if command then + command.summary + else + "[No command found for #{cmd_name}, bug?]" + end - def show_commands # :nodoc: - out = [] - out << "GEM commands are:" - out << nil + 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 - margin_width = 4 + 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'." - desc_width = @command_manager.command_names.map { |n| n.size }.max + 4 + say out.join("\n") - summary_width = 80 - margin_width - desc_width - wrap_indent = ' ' * (margin_width + desc_width) - format = "#{' ' * margin_width}%-#{desc_width}s%s" + elsif begins? "options", arg then + say Gem::Command::HELP - @command_manager.command_names.each do |cmd_name| - command = @command_manager[cmd_name] + elsif begins? "examples", arg then + say EXAMPLES - summary = - if command then - command.summary - else - "[No command found for #{cmd_name}]" - end + elsif begins? "platforms", arg then + say PLATFORMS - summary = wrap(summary, summary_width).split "\n" - out << sprintf(format, cmd_name, summary.shift) - until summary.empty? do - out << "#{wrap_indent}#{summary.shift}" + 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 - 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 + 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 - 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'" + say Gem::Command::HELP end end diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index f02b12906d..0b58fa665e 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -4,6 +4,8 @@ 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 @@ -38,12 +40,6 @@ 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 @@ -113,44 +109,7 @@ to write the specification by hand. For example: "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags" end - 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: + def install_from_gemdeps(gf) require 'rubygems/request_set' rs = Gem::RequestSet.new rs.load_gemdeps gf @@ -172,26 +131,51 @@ to write the specification by hand. For example: raise Gem::SystemExitException, 0 end - def install_gem name, version # :nodoc: - return if options[:conservative] and - not Gem::Dependency.new(name, version).matching_specs.empty? + def execute + if gf = options[:gemdeps] then + install_from_gemdeps gf + return + end - inst = Gem::DependencyInstaller.new options - inst.install name, Gem::Requirement.create(version) + @installed_specs = [] - @installed_specs.push(*inst.installed_gems) + ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9' - show_install_errors inst.errors - end + if options[:install_dir] and options[:user_install] + alert_error "Use --install-dir or --user-install but not both" + terminate_interaction 1 + 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 - install_gem gem_name, gem_version + 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 rescue Gem::InstallError => e alert_error "Error installing #{gem_name}:\n\t#{e.message}" exit_code |= 1 @@ -202,38 +186,12 @@ to write the specification by hand. For example: end end - 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' + unless @installed_specs.empty? then + gems = @installed_specs.length == 1 ? 'gem' : 'gems' + say "#{@installed_specs.length} #{gems} installed" 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 - - def show_installed # :nodoc: - return if @installed_specs.empty? - - gems = @installed_specs.length == 1 ? 'gem' : 'gems' - say "#{@installed_specs.length} #{gems} installed" + raise Gem::SystemExitException, exit_code end end diff --git a/lib/rubygems/commands/list_command.rb b/lib/rubygems/commands/list_command.rb index 0d15950475..f3e5da9551 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 local gems whose name starts with STRING' + super 'list', 'Display gems whose name starts with STRING' remove_option('--name-matches') end @@ -21,17 +21,6 @@ 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 75419c857a..0f98077cbd 100644 --- a/lib/rubygems/commands/mirror_command.rb +++ b/lib/rubygems/commands/mirror_command.rb @@ -10,12 +10,6 @@ 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 f51bc5e93f..887faab0a2 100644 --- a/lib/rubygems/commands/outdated_command.rb +++ b/lib/rubygems/commands/outdated_command.rb @@ -15,18 +15,19 @@ class Gem::Commands::OutdatedCommand < Gem::Command add_platform_option end - def description # :nodoc: - <<-EOF -The outdated command lists gems you way wish to upgrade to a newer version. + 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 -You can check for dependency mismatches using the dependency command and -update the gems with the update or install commands. - EOF - end + next if remotes.empty? - def execute - Gem::Specification.outdated_and_latest_version.each do |spec, remote_version| - say "#{spec.name} (#{spec.version} < #{remote_version})" + remotes.sort! { |a,b| a[0].version <=> b[0].version } + + highest = remotes.last.first + + say "#{local.name} (#{local.version} < #{highest.version})" end end end diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb index 13b8793021..11e6e026fd 100644 --- a/lib/rubygems/commands/owner_command.rb +++ b/lib/rubygems/commands/owner_command.rb @@ -7,14 +7,7 @@ class Gem::Commands::OwnerCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - <<-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 + 'Manage gem owners on RubyGems.org.' end def arguments # :nodoc: @@ -26,7 +19,7 @@ permission to. end def initialize - super 'owner', 'Manage gem owners of a gem on the push server' + super 'owner', description add_proxy_option add_key_option defaults.merge! :add => [], :remove => [] @@ -38,15 +31,9 @@ permission to. 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 3f3bca45be..8d479211ac 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -31,12 +31,6 @@ 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 @@ -111,21 +105,16 @@ with an extension. Gem::RemoteFetcher.fetcher.download_to_cache dep end - 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 + # TODO use installer options + install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install'] + installer_env_shebang = install_defaults.to_s['--env-shebang'] installer = Gem::Installer.new(gem, :wrappers => true, :force => true, :install_dir => spec.base_dir, - :env_shebang => env_shebang, + :env_shebang => installer_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 b90be7bd10..fccad206fa 100644 --- a/lib/rubygems/commands/push_command.rb +++ b/lib/rubygems/commands/push_command.rb @@ -8,13 +8,7 @@ class Gem::Commands::PushCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - <<-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 + 'Push a gem up to RubyGems.org' end def arguments # :nodoc: @@ -26,7 +20,7 @@ command. For further discussion see the help for the yank command. end def initialize - super 'push', 'Push a gem up to the gem server', :host => self.host + super 'push', description, :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 c9c3014975..05b214bb63 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -61,15 +61,6 @@ 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 86597f99a6..df00f3a5df 100644 --- a/lib/rubygems/commands/rdoc_command.rb +++ b/lib/rubygems/commands/rdoc_command.rb @@ -45,12 +45,8 @@ class Gem::Commands::RdocCommand < Gem::Command def description # :nodoc: <<-DESC -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. +The rdoc command builds RDoc and RI documentation for installed gems. 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 5bc9650672..c125715fe2 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 remote gems whose name contains STRING' + super 'search', 'Display all gems whose name contains STRING' remove_option '--name-matches' @@ -19,19 +19,6 @@ 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 60d96c5828..f4cc3e57ae 100644 --- a/lib/rubygems/commands/sources_command.rb +++ b/lib/rubygems/commands/sources_command.rb @@ -37,165 +37,103 @@ class Gem::Commands::SourcesCommand < Gem::Command add_proxy_option end - def add_source source_uri # :nodoc: - check_rubygems_https source_uri + def defaults_str + '--list' + end + + 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 = File.join Gem.user_home, '.gem', 'specs' + FileUtils.rm_rf path - begin - if Gem.sources.include? source_uri then - say "source #{source_uri} already present in the cache" + unless File.exist? path then + say "*** Removed specs cache ***" else - source.load_specs :released - Gem.sources << source - Gem.configuration.write + unless File.writable? path then + say "*** Unable to remove source cache (write protected) ***" + else + say "*** Unable to remove source cache ***" + end - say "#{source_uri} added to sources" + terminate_interaction 1 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 - def check_rubygems_https source_uri # :nodoc: - uri = URI source_uri + if source_uri = options[:add] then + 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 - end - - def clear_all # :nodoc: - path = Gem.spec_cache_dir - FileUtils.rm_rf path - - unless File.exist? path then - say "*** Removed specs cache ***" - else - unless File.writable? path then - say "*** Unable to remove source cache (write protected) ***" - else - say "*** Unable to remove source cache ***" + terminate_interaction 1 unless ask_yes_no question end - terminate_interaction 1 + 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 end - 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: - -* 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. + if options[:remove] then + source_uri = options[:remove] -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 + unless Gem.sources.include? source_uri then + say "source #{source_uri} not present in cache" + else + Gem.sources.delete source_uri + Gem.configuration.write - Gem.sources.each do |src| - say src + say "#{source_uri} removed from sources" + end end - end - - def list? # :nodoc: - !(options[:list] || - options[:add] || - options[:clear_all] || - options[:remove] || - options[:update]) - 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] + if options[:update] then + Gem.sources.each_source do |src| + src.load_specs :released + src.load_specs :latest + end - list if list? - end + say "source cache successfully updated" + 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 + if options[:list] then + say "*** CURRENT SOURCES ***" + say - say "#{source_uri} removed from sources" + Gem.sources.each do |src| + say src + end end end - def update # :nodoc: - Gem.sources.each_source do |src| - src.load_specs :released - src.load_specs :latest - end - - say "source cache successfully updated" - end + private - def remove_cache_file desc, path # :nodoc: + def remove_cache_file(desc, path) 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 d96c8b8627..b40dfd5f3c 100644 --- a/lib/rubygems/commands/specification_command.rb +++ b/lib/rubygems/commands/specification_command.rb @@ -50,22 +50,6 @@ 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 0ef0755960..36c517e27c 100644 --- a/lib/rubygems/commands/stale_command.rb +++ b/lib/rubygems/commands/stale_command.rb @@ -5,16 +5,6 @@ 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 8e6af2ba65..56aa8ee57f 100644 --- a/lib/rubygems/commands/uninstall_command.rb +++ b/lib/rubygems/commands/uninstall_command.rb @@ -1,7 +1,6 @@ require 'rubygems/command' require 'rubygems/version_option' require 'rubygems/uninstaller' -require 'fileutils' ## # Gem uninstaller command line tool @@ -15,7 +14,7 @@ class Gem::Commands::UninstallCommand < Gem::Command def initialize super 'uninstall', 'Uninstall gems from the local repository', :version => Gem::Requirement.default, :user_install => true, - :install_dir => Gem.dir, :check_dev => false + :check_dev => false add_option('-a', '--[no-]all', 'Uninstall all matching versions' @@ -68,12 +67,6 @@ 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 @@ -88,49 +81,13 @@ 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 - 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 + # REFACTOR: stolen from cleanup_command 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 e60e7d90fd..7eefd32a6e 100644 --- a/lib/rubygems/commands/unpack_command.rb +++ b/lib/rubygems/commands/unpack_command.rb @@ -34,24 +34,6 @@ 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 77bf5edb45..a31de0071a 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -52,46 +52,27 @@ 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 - end + else + say "Updating installed gems" - say "Updating installed gems" + hig = {} # highest installed gems - 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 + end gems_to_update = which_to_update hig, options[:args].uniq @@ -104,65 +85,51 @@ command to remove old versions. end end - def fetch_remote_gems spec # :nodoc: - dependency = Gem::Dependency.new spec.name, "> #{spec.version}" - dependency.prerelease = options[:prerelease] - - fetcher = Gem::SpecFetcher.fetcher - - spec_tuples, _ = fetcher.search_for_dependency dependency + def update_gem name, version = Gem::Requirement.default + return if @updated.any? { |spec| spec.name == name } - spec_tuples - end + @installer ||= Gem::DependencyInstaller.new options - def highest_installed_gems # :nodoc: - hig = {} # highest installed gems + success = false - Gem::Specification.each do |spec| - if hig[spec.name].nil? or hig[spec.name].version < spec.version then - hig[spec.name] = spec - end + 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 - hig + @installer.installed_gems.each do |spec| + @updated << spec + end end - 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? + def update_gems gems_to_update + gems_to_update.uniq.sort.each do |(name, version)| + update_gem name, version end - highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last - - highest_remote_gem ||= [Gem::NameTuple.null] - - highest_remote_gem.first.version + @updated end - def install_rubygems version # :nodoc: - args = update_rubygems_arguments + ## + # Update RubyGems software to the latest version. - update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" + def update_rubygems + unless options[:args].empty? then + alert_error "Gem names are not allowed with the --system option" + terminate_interaction 1 + end - Dir.chdir update_dir do - say "Installing RubyGems #{version}" + options[:user_install] = false - # 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 + # TODO: rename version and other variable name conflicts + # TODO: get rid of all this indirection on name and other BS - def rubygems_target_version version = options[:system] - update_latest = version == true - - if update_latest then + if version == true then version = Gem::Version.new Gem::VERSION requirement = Gem::Requirement.new ">= #{Gem::VERSION}" else @@ -179,72 +146,46 @@ command to remove old versions. } gems_to_update = which_to_update hig, options[:args], :system - _, up_ver = gems_to_update.first + name, up_ver = gems_to_update.first + current_ver = Gem.rubygems_version - target = if update_latest then + target = if options[:system] == true then up_ver else version end - 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 - - @installer.installed_gems.each do |spec| - @updated << spec + if current_ver == target then + # if options[:system] != true and version == current_ver then + say "Latest version currently installed. Aborting." + terminate_interaction 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 + update_gem name, target 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] - args + + 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 end def which_to_update highest_installed_gems, gem_names, system = false @@ -254,7 +195,21 @@ command to remove old versions. next if not gem_names.empty? and gem_names.all? { |name| /#{name}/ !~ l_spec.name } - highest_remote_ver = highest_remote_version l_spec + 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 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 99b9085b2b..6495278a87 100644 --- a/lib/rubygems/commands/which_command.rb +++ b/lib/rubygems/commands/which_command.rb @@ -23,17 +23,6 @@ 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 2285bb4017..df4142d395 100644 --- a/lib/rubygems/commands/yank_command.rb +++ b/lib/rubygems/commands/yank_command.rb @@ -9,21 +9,7 @@ class Gem::Commands::YankCommand < Gem::Command include Gem::GemcutterUtilities def description # :nodoc: - <<-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 + 'Remove a specific gem version release from RubyGems.org' end def arguments # :nodoc: @@ -35,7 +21,7 @@ as the reason for the removal request. end def initialize - super 'yank', 'Remove a pushed gem from the index' + super 'yank', description add_version_option("remove") add_platform_option("remove") diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index d0699dcb29..244e845e6f 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -141,11 +141,6 @@ class Gem::ConfigFile attr_reader :ssl_ca_cert ## - # Path name of directory or file of openssl client certificate, used for remote https connection with client authentication - - attr_reader :ssl_client_cert - - ## # Create the config file object. +args+ is the list of arguments # from the command line. # @@ -215,7 +210,6 @@ class Gem::ConfigFile @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert - @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert @api_keys = nil @rubygems_api_key = nil @@ -252,10 +246,6 @@ Your gem push credentials file located at: has file permissions of 0#{existing_permissions.to_s 8} but 0600 is required. -To fix this error run: - -\tchmod 0600 #{credentials_path} - You should reset your credentials at: \thttps://rubygems.org/profile/edit @@ -319,9 +309,6 @@ if you believe they were disclosed to a third party. @rubygems_api_key = api_key end - YAMLErrors = [ArgumentError] - YAMLErrors << Psych::SyntaxError if defined?(Psych::SyntaxError) - def load_file(filename) Gem.load_yaml @@ -334,8 +321,8 @@ if you believe they were disclosed to a third party. return {} end return content - rescue *YAMLErrors => e - warn "Failed to load #{filename}, #{e.to_s}" + rescue ArgumentError + warn "Failed to load #{filename}" rescue Errno::EACCES warn "Failed to load #{filename} due to permissions problem." end diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index 0416644920..f4f7fc8393 100755 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -48,12 +48,7 @@ module Kernel # normal require handle loading a gem from the rescue below. if Gem::Specification.unresolved_deps.empty? then - begin - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - ensure - RUBYGEMS_ACTIVATION_MONITOR.enter - end + return gem_original_require(path) end # If +path+ is for a gem that has already been loaded, don't @@ -62,16 +57,11 @@ module Kernel #-- # TODO request access to the C implementation of this to speed up RubyGems - spec = Gem::Specification.stubs.find { |s| + spec = Gem::Specification.find { |s| s.activated? and s.contains_requirable_file? path } - begin - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - ensure - RUBYGEMS_ACTIVATION_MONITOR.enter - end if spec + return gem_original_require(path) if spec # Attempt to find +path+ in any unresolved gems... @@ -119,21 +109,11 @@ module Kernel valid.activate end - begin - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - ensure - RUBYGEMS_ACTIVATION_MONITOR.enter - end + gem_original_require path rescue LoadError => load_error if load_error.message.start_with?("Could not find") or (load_error.message.end_with?(path) and Gem.try_activate(path)) then - begin - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - ensure - RUBYGEMS_ACTIVATION_MONITOR.enter - end + return gem_original_require(path) end raise load_error diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb index 591580b7da..cc8dc722fc 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb @@ -15,14 +15,6 @@ module Gem end ## - # Default spec directory path to be used if an alternate value is not - # specified in the environment - - def self.default_spec_cache_dir - File.join Gem.user_home, '.gem', 'specs' - end - - ## # Default home directory path to be used if an alternate value is not # specified in the environment @@ -134,11 +126,4 @@ module Gem def self.default_cert_path File.join Gem.user_home, ".gem", "gem-public_cert.pem" end - - ## - # Whether to expect full paths in default gems - true for non-MRI - # ruby implementations - def self.default_gems_use_full_paths? - ruby_engine != 'ruby' - end end diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index a96d67c3e5..1e3cc168a8 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -203,8 +203,6 @@ class Gem::Dependency requirement.satisfied_by? version end - alias === =~ - # DOC: this method needs either documented or :nodoc'd def match? obj, version=nil @@ -252,10 +250,10 @@ class Gem::Dependency # DOC: this method needs either documented or :nodoc'd def matching_specs platform_only = false - matches = Gem::Specification.stubs.find_all { |spec| + matches = Gem::Specification.find_all { |spec| self.name === spec.name and # TODO: == instead of === requirement.satisfied_by? spec.version - }.map(&:to_spec) + } if platform_only matches.reject! { |spec| diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index e7c489a759..6f19a310f7 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -1,11 +1,11 @@ require 'rubygems' require 'rubygems/dependency_list' -require 'rubygems/dependency_resolver' require 'rubygems/package' require 'rubygems/installer' require 'rubygems/spec_fetcher' require 'rubygems/user_interaction' -require 'rubygems/source' +require 'rubygems/source_local' +require 'rubygems/source_specific_file' require 'rubygems/available_set' ## @@ -15,7 +15,15 @@ class Gem::DependencyInstaller include Gem::UserInteraction - DEFAULT_OPTIONS = { # :nodoc: + attr_reader :gems_to_install + attr_reader :installed_gems + + ## + # Documentation types. For use by the Gem.done_installing hook + + attr_reader :document + + DEFAULT_OPTIONS = { :env_shebang => false, :document => %w[ri], :domain => :both, # HACK dup @@ -27,31 +35,9 @@ class Gem::DependencyInstaller :wrappers => true, :build_args => nil, :build_docs_in_background => false, - :install_as_default => false }.freeze ## - # Documentation types. For use by the Gem.done_installing hook - - attr_reader :document - - ## - # Errors from SpecFetcher while searching for remote specifications - - attr_reader :errors - - ## - #-- - # TODO remove, no longer used - - attr_reader :gems_to_install # :nodoc: - - ## - # List of gems installed by #install in alphabetic order - - attr_reader :installed_gems - - ## # Creates a new installer instance. # # Options are: @@ -70,8 +56,7 @@ class Gem::DependencyInstaller # :wrappers:: See Gem::Installer::new # :build_args:: See Gem::Installer::new - def initialize options = {} - @only_install_dir = !!options[:install_dir] + def initialize(options = {}) @install_dir = options[:install_dir] || Gem.dir if options[:install_dir] then @@ -97,7 +82,6 @@ class Gem::DependencyInstaller @wrappers = options[:wrappers] @build_args = options[:build_args] @build_docs_in_background = options[:build_docs_in_background] - @install_as_default = options[:install_as_default] # Indicates that we should not try to update any deps unless # we absolutely must. @@ -109,61 +93,13 @@ class Gem::DependencyInstaller @cache_dir = options[:cache_dir] || @install_dir + # Set with any errors that SpecFetcher finds while search through + # gemspecs for a dep @errors = nil end - ## - #-- - # TODO remove, no longer used - - def add_found_dependencies to_do, dependency_list # :nodoc: - seen = {} - dependencies = Hash.new { |h, name| h[name] = Gem::Dependency.new name } - - until to_do.empty? do - spec = to_do.shift - - # HACK why is spec nil? - next if spec.nil? or seen[spec.name] - seen[spec.name] = true - - deps = spec.runtime_dependencies - - if @development - if @dev_shallow - if @toplevel_specs.include? spec.full_name - deps |= spec.development_dependencies - end - else - deps |= spec.development_dependencies - end - end - - deps.each do |dep| - dependencies[dep.name] = dependencies[dep.name].merge dep - - if @minimal_deps - next if Gem::Specification.any? do |installed_spec| - dep.name == installed_spec.name and - dep.requirement.satisfied_by? installed_spec.version - end - end - - results = find_gems_with_sources(dep) - - results.sorted.each do |t| - to_do.push t.spec - end - - results.remove_installed! dep - - @available << results - results.inject_into_list dependency_list - end - end + attr_reader :errors - dependency_list.remove_specs_unsatisfied_by dependencies - end ## # Creates an AvailableSet to install from based on +dep_or_name+ and # +version+ @@ -202,7 +138,7 @@ class Gem::DependencyInstaller # sources. Gems are sorted with newer gems preferred over older gems, and # local gems preferred over remote gems. - def find_gems_with_sources dep # :nodoc: + def find_gems_with_sources(dep) set = Gem::AvailableSet.new if consider_local? @@ -243,50 +179,10 @@ class Gem::DependencyInstaller end ## - # Finds a spec and the source_uri it came from for gem +gem_name+ and - # +version+. Returns an Array of specs and sources required for - # installation of the gem. - - def find_spec_by_name_and_version gem_name, - version = Gem::Requirement.default, - prerelease = false - set = Gem::AvailableSet.new - - if consider_local? - if gem_name =~ /\.gem$/ and File.file? gem_name then - src = Gem::Source::SpecificFile.new(gem_name) - set.add src.spec, src - else - local = Gem::Source::Local.new - - if s = local.find_gem(gem_name, version) - set.add s, local - end - end - end - - if set.empty? - dep = Gem::Dependency.new gem_name, version - dep.prerelease = true if prerelease - - set = find_gems_with_sources(dep) - set.match_platform! - end - - if set.empty? - raise Gem::SpecificGemNotFoundException.new(gem_name, version, @errors) - end - - @available = set - end - - ## # Gathers all dependencies necessary for the installation from local and # remote sources unless the ignore_dependencies was given. - #-- - # TODO remove, no longer used - def gather_dependencies # :nodoc: + def gather_dependencies specs = @available.all_specs # these gems were listed by the user, always install them @@ -318,19 +214,93 @@ class Gem::DependencyInstaller @gems_to_install = dependency_list.dependency_order.reverse end - def in_background what # :nodoc: - fork_happened = false - if @build_docs_in_background and Process.respond_to?(:fork) - begin - Process.fork do - yield + def add_found_dependencies to_do, dependency_list + seen = {} + dependencies = Hash.new { |h, name| h[name] = Gem::Dependency.new name } + + until to_do.empty? do + spec = to_do.shift + + # HACK why is spec nil? + next if spec.nil? or seen[spec.name] + seen[spec.name] = true + + deps = spec.runtime_dependencies + + if @development + if @dev_shallow + if @toplevel_specs.include? spec.full_name + deps |= spec.development_dependencies + end + else + deps |= spec.development_dependencies end - fork_happened = true - say "#{what} in a background process." - rescue NotImplementedError + end + + deps.each do |dep| + dependencies[dep.name] = dependencies[dep.name].merge dep + + if @minimal_deps + next if Gem::Specification.any? do |installed_spec| + dep.name == installed_spec.name and + dep.requirement.satisfied_by? installed_spec.version + end + end + + results = find_gems_with_sources(dep) + + results.sorted.each do |t| + to_do.push t.spec + end + + results.remove_installed! dep + + @available << results + results.inject_into_list dependency_list end end - yield unless fork_happened + + dependency_list.remove_specs_unsatisfied_by dependencies + end + + ## + # Finds a spec and the source_uri it came from for gem +gem_name+ and + # +version+. Returns an Array of specs and sources required for + # installation of the gem. + + def find_spec_by_name_and_version(gem_name, + version = Gem::Requirement.default, + prerelease = false) + + set = Gem::AvailableSet.new + + if consider_local? + if gem_name =~ /\.gem$/ and File.file? gem_name then + src = Gem::Source::SpecificFile.new(gem_name) + set.add src.spec, src + else + local = Gem::Source::Local.new + + if s = local.find_gem(gem_name, version) + set.add s, local + end + end + end + + if set.empty? + dep = Gem::Dependency.new gem_name, version + # HACK Dependency objects should be immutable + dep.prerelease = true if prerelease + + set = find_gems_with_sources(dep) + set.match_platform! + end + + if set.empty? + raise Gem::SpecificGemNotFoundException.new(gem_name, version, @errors) + end + + @available = set end ## @@ -348,29 +318,60 @@ class Gem::DependencyInstaller # separately. def install dep_or_name, version = Gem::Requirement.default - request_set = resolve_dependencies dep_or_name, version + available_set_for dep_or_name, version @installed_gems = [] - options = { - :bin_dir => @bin_dir, - :build_args => @build_args, - :env_shebang => @env_shebang, - :force => @force, - :format_executable => @format_executable, - :ignore_dependencies => @ignore_dependencies, - :security_policy => @security_policy, - :user_install => @user_install, - :wrappers => @wrappers, - :install_as_default => @install_as_default - } - options[:install_dir] = @install_dir if @only_install_dir + gather_dependencies - request_set.install options do |_, installer| - @installed_gems << installer.spec if installer - end + # REFACTOR is the last gem always the one that the user requested? + # This code assumes that but is that actually validated by the code? + + last = @gems_to_install.size - 1 + @gems_to_install.each_with_index do |spec, index| + # REFACTOR more current spec set hardcoding, should be abstracted? + next if Gem::Specification.include?(spec) and index != last + + # TODO: make this sorta_verbose so other users can benefit from it + say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose + + source = @available.source_for spec + + begin + # REFACTOR make the fetcher to use configurable + local_gem_path = source.download spec, @cache_dir + rescue Gem::RemoteFetcher::FetchError + # TODO I doubt all fetch errors are recoverable, we should at least + # report the errors probably. + next if @force + raise + end + + if @development + if @dev_shallow + is_dev = @toplevel_specs.include? spec.full_name + else + is_dev = true + end + end - @installed_gems.sort! + inst = Gem::Installer.new local_gem_path, + :bin_dir => @bin_dir, + :development => is_dev, + :env_shebang => @env_shebang, + :force => @force, + :format_executable => @format_executable, + :ignore_dependencies => @ignore_dependencies, + :install_dir => @install_dir, + :security_policy => @security_policy, + :user_install => @user_install, + :wrappers => @wrappers, + :build_args => @build_args + + spec = inst.install + + @installed_gems << spec + end # Since this is currently only called for docs, we can be lazy and just say # it's documentation. Ideally the hook adder could decide whether to be in @@ -384,34 +385,18 @@ class Gem::DependencyInstaller @installed_gems end - def install_development_deps # :nodoc: - if @development and @dev_shallow then - :shallow - elsif @development then - :all - else - :none - end - end - - def resolve_dependencies dep_or_name, version # :nodoc: - as = available_set_for dep_or_name, version - - request_set = as.to_request_set install_development_deps - request_set.soft_missing = @force - - installer_set = Gem::DependencyResolver::InstallerSet.new @domain - installer_set.always_install.concat request_set.always_install - installer_set.ignore_installed = @only_install_dir - - if @ignore_dependencies then - installer_set.ignore_dependencies = true - request_set.soft_missing = true + def in_background what + fork_happened = false + if @build_docs_in_background and Process.respond_to?(:fork) + begin + Process.fork do + yield + end + fork_happened = true + say "#{what} in a background process." + rescue NotImplementedError + end end - - request_set.resolve Gem::DependencyResolver.compose_sets(as, installer_set) - - request_set + yield unless fork_happened end - end diff --git a/lib/rubygems/dependency_resolver.rb b/lib/rubygems/dependency_resolver.rb index abce692920..66f55eb9ad 100644 --- a/lib/rubygems/dependency_resolver.rb +++ b/lib/rubygems/dependency_resolver.rb @@ -1,254 +1,575 @@ require 'rubygems' require 'rubygems/dependency' require 'rubygems/exceptions' -require 'rubygems/util/list' require 'uri' require 'net/http' -## -# Given a set of Gem::Dependency objects as +needed+ and a way to query the -# set of available specs via +set+, calculates a set of ActivationRequest -# objects which indicate all the specs that should be activated to meet the -# all the requirements. +module Gem -class Gem::DependencyResolver - - ## - # Contains all the conflicts encountered while doing resolution + # Raised when a DependencyConflict reaches the toplevel. + # Indicates which dependencies were incompatible. + # + class DependencyResolutionError < Gem::Exception + def initialize(conflict) + @conflict = conflict + a, b = conflicting_dependencies - attr_reader :conflicts + super "unable to resolve conflicting dependencies '#{a}' and '#{b}'" + end - attr_accessor :development + attr_reader :conflict - attr_reader :missing + def conflicting_dependencies + @conflict.conflicting_dependencies + end + end - ## - # When a missing dependency, don't stop. Just go on and record what was - # missing. + # Raised when a dependency requests a gem for which there is + # no spec. + # + class UnsatisfiableDepedencyError < Gem::Exception + def initialize(dep) + super "unable to find any gem matching dependency '#{dep}'" - attr_accessor :soft_missing + @dependency = dep + end - def self.compose_sets *sets - Gem::DependencyResolver::ComposedSet.new(*sets) + attr_reader :dependency end - ## - # Provide a DependencyResolver that queries only against the already - # installed gems. + # Raised when dependencies conflict and create the inability to + # find a valid possible spec for a request. + # + class ImpossibleDependenciesError < Gem::Exception + def initialize(request, conflicts) + s = conflicts.size == 1 ? "" : "s" + super "detected #{conflicts.size} conflict#{s} with dependency '#{request.dependency}'" + @request = request + @conflicts = conflicts + end + + def dependency + @request.dependency + end - def self.for_current_gems needed - new needed, Gem::DependencyResolver::CurrentSet.new + attr_reader :conflicts end - ## - # Create DependencyResolver object which will resolve the tree starting - # with +needed+ Depedency objects. + # Given a set of Gem::Dependency objects as +needed+ and a way + # to query the set of available specs via +set+, calculates + # a set of ActivationRequest objects which indicate all the specs + # that should be activated to meet the all the requirements. # - # +set+ is an object that provides where to look for specifications to - # satisify the Dependencies. This defaults to IndexSet, which will query - # rubygems.org. - - def initialize needed, set = nil - @set = set || Gem::DependencyResolver::IndexSet.new - @needed = needed - - @conflicts = nil - @development = false - @missing = [] - @soft_missing = false - end + class DependencyResolver + + # Represents a specification retrieved via the rubygems.org + # API. This is used to avoid having to load the full + # Specification object when all we need is the name, version, + # and dependencies. + # + class APISpecification + attr_reader :set # :nodoc: + + def initialize(set, api_data) + @set = set + @name = api_data[:name] + @version = Gem::Version.new api_data[:number] + @dependencies = api_data[:dependencies].map do |name, ver| + Gem::Dependency.new name, ver.split(/\s*,\s*/) + end + end - def requests s, act, reqs=nil - s.dependencies.reverse_each do |d| - next if d.type == :development and not @development - reqs = Gem::List.new Gem::DependencyResolver::DependencyRequest.new(d, act), reqs + attr_reader :name, :version, :dependencies + + def == other # :nodoc: + self.class === other and + @set == other.set and + @name == other.name and + @version == other.version and + @dependencies == other.dependencies + end + + def full_name + "#{@name}-#{@version}" + end end - @set.prefetch reqs + # The global rubygems pool, available via the rubygems.org API. + # Returns instances of APISpecification. + # + class APISet + def initialize + @data = Hash.new { |h,k| h[k] = [] } + @dep_uri = URI 'https://rubygems.org/api/v1/dependencies' + end - reqs - end + # Return data for all versions of the gem +name+. + # + def versions(name) + if @data.key?(name) + return @data[name] + end - ## - # Proceed with resolution! Returns an array of ActivationRequest objects. + uri = @dep_uri + "?gems=#{name}" + str = Gem::RemoteFetcher.fetcher.fetch_path uri - def resolve - @conflicts = [] + Marshal.load(str).each do |ver| + @data[ver[:name]] << ver + end - needed = nil + @data[name] + end - @needed.reverse_each do |n| - request = Gem::DependencyResolver::DependencyRequest.new n, nil + # Return an array of APISpecification objects matching + # DependencyRequest +req+. + # + def find_all(req) + res = [] - needed = Gem::List.new request, needed + versions(req.name).each do |ver| + if req.dependency.match? req.name, ver[:number] + res << APISpecification.new(self, ver) + end + end + + res + end + + # A hint run by the resolver to allow the Set to fetch + # data for DependencyRequests +reqs+. + # + def prefetch(reqs) + names = reqs.map { |r| r.dependency.name } + needed = names.find_all { |d| !@data.key?(d) } + + return if needed.empty? + + uri = @dep_uri + "?gems=#{needed.sort.join ','}" + str = Gem::RemoteFetcher.fetcher.fetch_path uri + + Marshal.load(str).each do |ver| + @data[ver[:name]] << ver + end + end end - res = resolve_for needed, nil + # Represents a possible Specification object returned + # from IndexSet. Used to delay needed to download full + # Specification objects when only the +name+ and +version+ + # are needed. + # + class IndexSpecification + def initialize(set, name, version, source, plat) + @set = set + @name = name + @version = version + @source = source + @platform = plat + + @spec = nil + end - raise Gem::DependencyResolutionError, res if - res.kind_of? Gem::DependencyResolver::DependencyConflict + attr_reader :name, :version, :source - res.to_a - end + def full_name + "#{@name}-#{@version}" + end - ## - # The meat of the algorithm. Given +needed+ DependencyRequest objects and - # +specs+ being a list to ActivationRequest, calculate a new list of - # ActivationRequest objects. - - def resolve_for needed, specs - while needed - dep = needed.value - needed = needed.tail - - # If there is already a spec activated for the requested name... - if specs && existing = specs.find { |s| dep.name == s.name } - - # then we're done since this new dep matches the - # existing spec. - next if dep.matches_spec? existing - - # There is a conflict! We return the conflict - # object which will be seen by the caller and be - # handled at the right level. - - # If the existing activation indicates that there - # are other possibles for it, then issue the conflict - # on the dep for the activation itself. Otherwise, issue - # it on the requester's request itself. - # - if existing.others_possible? - conflict = - Gem::DependencyResolver::DependencyConflict.new dep, existing - else - depreq = existing.request.requester.request - conflict = - Gem::DependencyResolver::DependencyConflict.new depreq, existing, dep + def spec + @spec ||= @set.load_spec(@name, @version, @source) + end + + def dependencies + spec.dependencies + end + end + + # The global rubygems pool represented via the traditional + # source index. + # + class IndexSet + def initialize + @f = Gem::SpecFetcher.fetcher + + @all = Hash.new { |h,k| h[k] = [] } + + list, _ = @f.available_specs(:released) + list.each do |uri, specs| + specs.each do |n| + @all[n.name] << [uri, n] + end end - @conflicts << conflict - return conflict + @specs = {} end - # Get a list of all specs that satisfy dep and platform - possible = @set.find_all dep - possible = select_local_platforms possible + # Return an array of IndexSpecification objects matching + # DependencyRequest +req+. + # + def find_all(req) + res = [] - case possible.size - when 0 - @missing << dep + name = req.dependency.name - unless @soft_missing - # If there are none, then our work here is done. - raise Gem::UnsatisfiableDependencyError, dep + @all[name].each do |uri, n| + if req.dependency.match? n + res << IndexSpecification.new(self, n.name, n.version, + uri, n.platform) + end + end + + res + end + + # No prefetching needed since we load the whole index in + # initially. + # + def prefetch(gems) + end + + # Called from IndexSpecification to get a true Specification + # object. + # + def load_spec(name, ver, source) + key = "#{name}-#{ver}" + @specs[key] ||= source.fetch_spec(Gem::NameTuple.new(name, ver)) + end + end + + # A set which represents the installed gems. Respects + # all the normal settings that control where to look + # for installed gems. + # + class CurrentSet + def find_all(req) + req.dependency.matching_specs + end + + def prefetch(gems) + end + end + + # Create DependencyResolver object which will resolve + # the tree starting with +needed+ Depedency objects. + # + # +set+ is an object that provides where to look for + # specifications to satisify the Dependencies. This + # defaults to IndexSet, which will query rubygems.org. + # + def initialize(needed, set=IndexSet.new) + @set = set || IndexSet.new # Allow nil to mean IndexSet + @needed = needed + + @conflicts = nil + end + + # Provide a DependencyResolver that queries only against + # the already installed gems. + # + def self.for_current_gems(needed) + new needed, CurrentSet.new + end + + # Contains all the conflicts encountered while doing resolution + # + attr_reader :conflicts + + # Proceed with resolution! Returns an array of ActivationRequest + # objects. + # + def resolve + @conflicts = [] + + needed = @needed.map { |n| DependencyRequest.new(n, nil) } + + res = resolve_for needed, [] + + if res.kind_of? DependencyConflict + raise DependencyResolutionError.new(res) + end + + res + end + + # Used internally to indicate that a dependency conflicted + # with a spec that would be activated. + # + class DependencyConflict + def initialize(dependency, activated, failed_dep=dependency) + @dependency = dependency + @activated = activated + @failed_dep = failed_dep + end + + attr_reader :dependency, :activated + + # Return the Specification that listed the dependency + # + def requester + @failed_dep.requester + end + + def for_spec?(spec) + @dependency.name == spec.name + end + + # Return the 2 dependency objects that conflicted + # + def conflicting_dependencies + [@failed_dep.dependency, @activated.request.dependency] + end + end + + # Used Internally. Wraps a Depedency object to also track + # which spec contained the Dependency. + # + class DependencyRequest + def initialize(dep, act) + @dependency = dep + @requester = act + end + + attr_reader :dependency, :requester + + def name + @dependency.name + end + + def matches_spec?(spec) + @dependency.matches_spec? spec + end + + def to_s + @dependency.to_s + end + + def ==(other) + case other + when Dependency + @dependency == other + when DependencyRequest + @dependency == other.dependency && @requester == other.requester + else + false end - when 1 - # If there is one, then we just add it to specs - # and process the specs dependencies by adding - # them to needed. - - spec = possible.first - act = Gem::DependencyResolver::ActivationRequest.new spec, dep, false - - specs = Gem::List.prepend specs, act - - # Put the deps for at the beginning of needed - # rather than the end to match the depth first - # searching done by the multiple case code below. - # - # This keeps the error messages consistent. - needed = requests(spec, act, needed) - else - # There are multiple specs for this dep. This is - # the case that this class is built to handle. - - # Sort them so that we try the highest versions - # first. - possible = possible.sort_by do |s| - [s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1] + end + end + + # Specifies a Specification object that should be activated. + # Also contains a dependency that was used to introduce this + # activation. + # + class ActivationRequest + def initialize(spec, req, others_possible=true) + @spec = spec + @request = req + @others_possible = others_possible + end + + attr_reader :spec, :request + + # Indicate if this activation is one of a set of possible + # requests for the same Dependency request. + # + def others_possible? + @others_possible + end + + # Return the ActivationRequest that contained the dependency + # that we were activated for. + # + def parent + @request.requester + end + + def name + @spec.name + end + + def full_name + @spec.full_name + end + + def version + @spec.version + end + + def full_spec + Gem::Specification === @spec ? @spec : @spec.spec + end + + def download(path) + if @spec.respond_to? :source + source = @spec.source + else + source = Gem.sources.first end - # We track the conflicts seen so that we can report them - # to help the user figure out how to fix the situation. - conflicts = [] - - # To figure out which to pick, we keep resolving - # given each one being activated and if there isn't - # a conflict, we know we've found a full set. - # - # We use an until loop rather than #reverse_each - # to keep the stack short since we're using a recursive - # algorithm. - # - until possible.empty? - s = possible.pop - - # Recursively call #resolve_for with this spec - # and add it's dependencies into the picture... - - act = Gem::DependencyResolver::ActivationRequest.new s, dep - - try = requests(s, act, needed) - - res = resolve_for try, Gem::List.prepend(specs, act) - - # While trying to resolve these dependencies, there may - # be a conflict! - - if res.kind_of? Gem::DependencyResolver::DependencyConflict - # The conflict might be created not by this invocation - # but rather one up the stack, so if we can't attempt - # to resolve this conflict (conflict isn't with the spec +s+) - # then just return it so the caller can try to sort it out. - return res unless res.for_spec? s - - # Otherwise, this is a conflict that we can attempt to fix - conflicts << [s, res] - - # Optimization: - # - # Because the conflict indicates the dependency that trigger - # it, we can prune possible based on this new information. - # - # This cuts down on the number of iterations needed. - possible.delete_if { |x| !res.dependency.matches_spec? x } - else - # No conflict, return the specs - return res - end + Gem.ensure_gem_subdirectories path + + source.download full_spec, path + end + + def ==(other) + case other + when Gem::Specification + @spec == other + when ActivationRequest + @spec == other.spec && @request == other.request + else + false end + end - # We tried all possibles and nothing worked, so we let the user - # know and include as much information about the problem since - # the user is going to have to take action to fix this. - raise Gem::ImpossibleDependenciesError.new(dep, conflicts) + ## + # Indicates if the requested gem has already been installed. + + def installed? + this_spec = full_spec + + Gem::Specification.any? do |s| + s == this_spec + end end end - specs - end + def requests(s, act) + reqs = [] + s.dependencies.each do |d| + next unless d.type == :runtime + reqs << DependencyRequest.new(d, act) + end - ## - # Returns the gems in +specs+ that match the local platform. + @set.prefetch(reqs) - def select_local_platforms specs # :nodoc: - specs.select do |spec| - Gem::Platform.match spec.platform + reqs end - end -end + # The meat of the algorithm. Given +needed+ DependencyRequest objects + # and +specs+ being a list to ActivationRequest, calculate a new list + # of ActivationRequest objects. + # + def resolve_for(needed, specs) + until needed.empty? + dep = needed.shift + + # If there is already a spec activated for the requested name... + if existing = specs.find { |s| dep.name == s.name } + + # then we're done since this new dep matches the + # existing spec. + next if dep.matches_spec? existing + + # There is a conflict! We return the conflict + # object which will be seen by the caller and be + # handled at the right level. + + # If the existing activation indicates that there + # are other possibles for it, then issue the conflict + # on the dep for the activation itself. Otherwise, issue + # it on the requester's request itself. + # + if existing.others_possible? + conflict = DependencyConflict.new(dep, existing) + else + depreq = existing.request.requester.request + conflict = DependencyConflict.new(depreq, existing, dep) + end + @conflicts << conflict -require 'rubygems/dependency_resolver/api_set' -require 'rubygems/dependency_resolver/api_specification' -require 'rubygems/dependency_resolver/activation_request' -require 'rubygems/dependency_resolver/composed_set' -require 'rubygems/dependency_resolver/current_set' -require 'rubygems/dependency_resolver/dependency_conflict' -require 'rubygems/dependency_resolver/dependency_request' -require 'rubygems/dependency_resolver/index_set' -require 'rubygems/dependency_resolver/index_specification' -require 'rubygems/dependency_resolver/installed_specification' -require 'rubygems/dependency_resolver/installer_set' + return conflict + end + + # Get a list of all specs that satisfy dep + possible = @set.find_all(dep) + case possible.size + when 0 + # If there are none, then our work here is done. + raise UnsatisfiableDepedencyError.new(dep) + when 1 + # If there is one, then we just add it to specs + # and process the specs dependencies by adding + # them to needed. + + spec = possible.first + act = ActivationRequest.new(spec, dep, false) + + specs << act + + # Put the deps for at the beginning of needed + # rather than the end to match the depth first + # searching done by the multiple case code below. + # + # This keeps the error messages consistent. + needed = requests(spec, act) + needed + else + # There are multiple specs for this dep. This is + # the case that this class is built to handle. + + # Sort them so that we try the highest versions + # first. + possible = possible.sort_by { |s| s.version } + + # We track the conflicts seen so that we can report them + # to help the user figure out how to fix the situation. + conflicts = [] + + # To figure out which to pick, we keep resolving + # given each one being activated and if there isn't + # a conflict, we know we've found a full set. + # + # We use an until loop rather than #reverse_each + # to keep the stack short since we're using a recursive + # algorithm. + # + until possible.empty? + s = possible.pop + + # Recursively call #resolve_for with this spec + # and add it's dependencies into the picture... + + act = ActivationRequest.new(s, dep) + + try = requests(s, act) + needed + + res = resolve_for(try, specs + [act]) + + # While trying to resolve these dependencies, there may + # be a conflict! + + if res.kind_of? DependencyConflict + # The conflict might be created not by this invocation + # but rather one up the stack, so if we can't attempt + # to resolve this conflict (conflict isn't with the spec +s+) + # then just return it so the caller can try to sort it out. + return res unless res.for_spec? s + + # Otherwise, this is a conflict that we can attempt to fix + conflicts << [s, res] + + # Optimization: + # + # Because the conflict indicates the dependency that trigger + # it, we can prune possible based on this new information. + # + # This cuts down on the number of iterations needed. + possible.delete_if { |x| !res.dependency.matches_spec? x } + else + # No conflict, return the specs + return res + end + end + + # We tried all possibles and nothing worked, so we let the user + # know and include as much information about the problem since + # the user is going to have to take action to fix this. + raise ImpossibleDependenciesError.new(dep, conflicts) + end + end + + specs + end + end +end diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 4a988f9edf..ff389b320b 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -7,13 +7,7 @@ # Base exception class for RubyGems. All exception raised by RubyGems are a # subclass of this one. class Gem::Exception < RuntimeError - - ## - #-- - # TODO: remove in RubyGems 3, nobody sets this - - attr_accessor :source_exception # :nodoc: - + attr_accessor :source_exception end class Gem::CommandLineError < Gem::Exception; end @@ -23,28 +17,6 @@ class Gem::DependencyError < Gem::Exception; end class Gem::DependencyRemovalException < Gem::Exception; end ## -# Raised by Gem::DependencyResolver when a Gem::DependencyConflict reaches the -# toplevel. Indicates which dependencies were incompatible through #conflict -# and #conflicting_dependencies - -class Gem::DependencyResolutionError < Gem::Exception - - attr_reader :conflict - - def initialize conflict - @conflict = conflict - a, b = conflicting_dependencies - - super "unable to resolve conflicting dependencies '#{a}' and '#{b}'" - end - - def conflicting_dependencies - @conflict.conflicting_dependencies - end - -end - -## # Raised when attempting to uninstall a gem that isn't in GEM_HOME. class Gem::GemNotInHomeException < Gem::Exception @@ -93,42 +65,6 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException attr_reader :name, :version, :errors end -## -# Raised by Gem::DependencyResolver when dependencies conflict and create the -# inability to find a valid possible spec for a request. - -class Gem::ImpossibleDependenciesError < Gem::Exception - - attr_reader :conflicts - attr_reader :request - - def initialize request, conflicts - @request = request - @conflicts = conflicts - - super build_message - end - - def build_message # :nodoc: - requester = @request.requester - requester = requester ? requester.spec.full_name : 'The user' - dependency = @request.dependency - - message = "#{requester} requires #{dependency} but it conflicted:\n" - - @conflicts.each do |_, conflict| - message << conflict.explanation - end - - message - end - - def dependency - @request.dependency - end - -end - class Gem::InstallError < Gem::Exception; end ## @@ -171,26 +107,3 @@ class Gem::SystemExitException < SystemExit end -## -# Raised by DependencyResolver when a dependency requests a gem for which -# there is no spec. - -class Gem::UnsatisfiableDependencyError < Gem::Exception - - attr_reader :dependency - - def initialize dep - requester = dep.requester ? dep.requester.request : '(unknown)' - - super "Unable to resolve dependency: #{requester} requires #{dep}" - - @dependency = dep - end - -end - -## -# Backwards compatible typo'd exception class for early RubyGems 2.0.x - -Gem::UnsatisfiableDepedencyError = Gem::UnsatisfiableDependencyError # :nodoc: - diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 8c05723573..79cae906ee 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -4,23 +4,8 @@ # See LICENSE.txt for permissions. #++ -require 'rubygems/user_interaction' -require 'thread' - class Gem::Ext::Builder - include Gem::UserInteraction - - ## - # The builder shells-out to run various commands after changing the - # directory. This means multiple installations cannot be allowed to build - # extensions in parallel as they may change each other's directories leading - # to broken extensions or failed installations. - - CHDIR_MUTEX = Mutex.new # :nodoc: - - attr_accessor :build_args # :nodoc: - def self.class_name name =~ /Ext::(.*)Builder/ $1.downcase @@ -33,7 +18,7 @@ class Gem::Ext::Builder # try to find make program from Ruby configure arguments first RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/ - make_program = ENV['MAKE'] || ENV['make'] || $1 + make_program = $1 || ENV['MAKE'] || ENV['make'] unless make_program then make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make' end @@ -78,108 +63,5 @@ class Gem::Ext::Builder end end - ## - # Creates a new extension builder for +spec+ using the given +build_args+. - # The gem for +spec+ is unpacked in +gem_dir+. - - def initialize spec, build_args - @spec = spec - @build_args = build_args - @gem_dir = spec.gem_dir - - @ran_rake = nil - end - - ## - # Chooses the extension builder class for +extension+ - - def builder_for extension # :nodoc: - case extension - when /extconf/ then - Gem::Ext::ExtConfBuilder - when /configure/ then - Gem::Ext::ConfigureBuilder - when /rakefile/i, /mkrf_conf/i then - @ran_rake = true - Gem::Ext::RakeBuilder - when /CMakeLists.txt/ then - Gem::Ext::CmakeBuilder - else - extension_dir = File.join @gem_dir, File.dirname(extension) - - message = "No builder for extension '#{extension}'" - build_error extension_dir, message - end - end - - ## - # Logs the build +output+ in +build_dir+, then raises ExtensionBuildError. - - def build_error build_dir, output, backtrace = nil # :nodoc: - gem_make_out = File.join build_dir, 'gem_make.out' - - open gem_make_out, 'wb' do |io| io.puts output end - - message = <<-EOF -ERROR: Failed to build gem native extension. - - #{output} - -Gem files will remain installed in #{@gem_dir} for inspection. -Results logged to #{gem_make_out} -EOF - - raise Gem::Installer::ExtensionBuildError, message, backtrace - end - - def build_extension extension, dest_path # :nodoc: - results = [] - - extension ||= '' # I wish I knew why this line existed - extension_dir = File.join @gem_dir, File.dirname(extension) - - builder = builder_for extension - - begin - FileUtils.mkdir_p dest_path - - CHDIR_MUTEX.synchronize do - Dir.chdir extension_dir do - results = builder.build(extension, @gem_dir, dest_path, - results, @build_args) - - say results.join("\n") if Gem.configuration.really_verbose - end - end - rescue - build_error extension_dir, results.join("\n"), $@ - end - end - - ## - # Builds extensions. Valid types of extensions are extconf.rb files, - # configure scripts and rakefiles or mkrf_conf files. - - def build_extensions - return if @spec.extensions.empty? - - if @build_args.empty? - say "Building native extensions. This could take a while..." - else - say "Building native extensions with: '#{@build_args.join ' '}'" - say "This could take a while..." - end - - dest_path = File.join @gem_dir, @spec.require_paths.first - - @ran_rake = false # only run rake once - - @spec.extensions.each do |extension| - break if @ran_rake - - build_extension extension, dest_path - end - end - end diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb index 7a3fd6b116..8060e15312 100644 --- a/lib/rubygems/gem_runner.rb +++ b/lib/rubygems/gem_runner.rb @@ -33,11 +33,17 @@ class Gem::GemRunner ## # Run the gem command with the following arguments. - def run args - build_args = extract_build_args args + def run(args) + if args.include?('--') + # We need to preserve the original ARGV to use for passing gem options + # to source gems. If there is a -- in the line, strip all options after + # it...its for the source building process. + # TODO use slice! + build_args = args[args.index("--") + 1...args.length] + args = args[0...args.index("--")] + end do_configuration args - cmd = @command_manager_class.instance cmd.command_names.each do |command_name| @@ -54,20 +60,6 @@ class Gem::GemRunner cmd.run Gem.configuration.args, build_args end - ## - # Separates the build arguments (those following <code>--</code>) from the - # other arguments in the list. - - def extract_build_args args # :nodoc: - return [] unless offset = args.index('--') - - build_args = args.slice!(offset...args.length) - - build_args.shift - - build_args - end - private def do_configuration(args) diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index 9dbc18ba98..04d7cd300f 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -1,17 +1,11 @@ require 'rubygems/remote_fetcher' -## -# Utility methods for using the RubyGems API. - module Gem::GemcutterUtilities - # TODO: move to Gem::Command OptionParser.accept Symbol do |value| value.to_sym end - attr_writer :host - ## # Add the --key option @@ -23,9 +17,6 @@ module Gem::GemcutterUtilities end end - ## - # The API key from the command options or from the user's configuration. - def api_key if options[:key] then verify_api_key options[:key] @@ -36,49 +27,7 @@ module Gem::GemcutterUtilities end end - ## - # The host to connect to either from the RUBYGEMS_HOST environment variable - # or from the user's configuration - - def host - configured_host = Gem.host unless - Gem.configuration.disable_default_gem_server - - @host ||= - begin - env_rubygems_host = ENV['RUBYGEMS_HOST'] - env_rubygems_host = nil if - env_rubygems_host and env_rubygems_host.empty? - - env_rubygems_host|| configured_host - end - end - - ## - # Creates an RubyGems API to +host+ and +path+ with the given HTTP +method+. - - def rubygems_api_request(method, path, host = nil, &block) - require 'net/http' - - self.host = host if host - unless self.host - alert_error "You must specify a gem server" - terminate_interaction 1 # TODO: question this - end - - uri = URI.parse "#{self.host}/#{path}" - - request_method = Net::HTTP.const_get method.to_s.capitalize - - Gem::RemoteFetcher.fetcher.request(uri, request_method, &block) - end - - ## - # Signs in with the RubyGems API at +sign_in_host+ and sets the rubygems API - # key. - - def sign_in sign_in_host = nil - sign_in_host ||= self.host + def sign_in sign_in_host = self.host return if Gem.configuration.rubygems_api_key pretty_host = if Gem::DEFAULT_HOST == sign_in_host then @@ -106,36 +55,47 @@ module Gem::GemcutterUtilities end end - ## - # Retrieves the pre-configured API key +key+ or terminates interaction with - # an error. + attr_writer :host + def host + configured_host = Gem.host unless + Gem.configuration.disable_default_gem_server - def verify_api_key(key) - if Gem.configuration.api_keys.key? key then - Gem.configuration.api_keys[key] - else - alert_error "No such API key. Please add it to your configuration (done automatically on initial `gem push`)." + @host ||= + begin + env_rubygems_host = ENV['RUBYGEMS_HOST'] + env_rubygems_host = nil if + env_rubygems_host and env_rubygems_host.empty? + + env_rubygems_host|| configured_host + end + end + + def rubygems_api_request(method, path, host = nil, &block) + require 'net/http' + + self.host = host if host + unless self.host + alert_error "You must specify a gem server" terminate_interaction 1 # TODO: question this end + + uri = URI.parse "#{self.host}/#{path}" + + request_method = Net::HTTP.const_get method.to_s.capitalize + + Gem::RemoteFetcher.fetcher.request(uri, request_method, &block) end - ## - # If +response+ is an HTTP Success (2XX) response, yields the response if a - # block was given or shows the response body to the user. - # - # If the response was not successful, shows an error to the user including - # the +error_prefix+ and the response body. - - def with_response response, error_prefix = nil - case response + def with_response resp, error_prefix = nil + case resp when Net::HTTPSuccess then if block_given? then - yield response + yield resp else - say response.body + say resp.body end else - message = response.body + message = resp.body message = "#{error_prefix}: #{message}" if error_prefix say message @@ -143,5 +103,13 @@ module Gem::GemcutterUtilities end end -end + def verify_api_key(key) + if Gem.configuration.api_keys.key? key then + Gem.configuration.api_keys[key] + else + alert_error "No such API key. Please add it to your configuration (done automatically on initial `gem push`)." + terminate_interaction 1 # TODO: question this + end + end +end diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index d3f55cd5ea..ffa8f910df 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -26,9 +26,6 @@ module Gem::InstallUpdateOptions OptionParser.accept Gem::Security::Policy do |value| require 'rubygems/security' - raise OptionParser::InvalidArgument, 'OpenSSL not installed' unless - defined?(Gem::Security::HighSecurity) - value = Gem::Security::Policies[value] valid = Gem::Security::Policies.keys.sort message = "#{value} (#{valid.join ', '} are valid)" diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 261af890c8..0ccf7ad52f 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -9,6 +9,7 @@ require 'rubygems/package' require 'rubygems/ext' require 'rubygems/user_interaction' require 'fileutils' +require 'thread' ## # The installer installs the files contained in the .gem into the Gem.home. @@ -32,6 +33,14 @@ class Gem::Installer ENV_PATHS = %w[/usr/bin/env /bin/env] ## + # The builder shells-out to run various commands after changing the + # directory. This means multiple installations cannot be allowed to build + # extensions in parallel as they may change each other's directories leading + # to broken extensions or failed installations. + + CHDIR_MUTEX = Mutex.new # :nodoc: + + ## # Raised when there is an error while building extensions. # class ExtensionBuildError < Gem::InstallError; end @@ -84,8 +93,8 @@ class Gem::Installer # :env_shebang:: Use /usr/bin/env in bin wrappers. # :force:: Overrides all version checks and security policy checks, except # for a signed-gems-only policy. - # :format_executable:: Format the executable the same as the Ruby executable. - # If your Ruby is ruby18, foo_exec will be installed as + # :format_executable:: Format the executable the same as the ruby executable. + # If your ruby is ruby18, foo_exec will be installed as # foo_exec18. # :ignore_dependencies:: Don't raise if a dependency is missing. # :install_dir:: The directory to install the gem into. @@ -144,7 +153,7 @@ class Gem::Installer io.gets # blankline # TODO detect a specially formatted comment instead of trying - # to run a regexp against Ruby code. + # to run a regexp against ruby code. next unless io.gets =~ /This file was generated by RubyGems/ ruby_executable = true @@ -213,25 +222,20 @@ class Gem::Installer FileUtils.mkdir_p gem_dir - spec.loaded_from = spec_file - - if @options[:install_as_default] - extract_bin - write_default_spec - else - extract_files + extract_files - build_extensions - write_build_info_file - run_post_build_hooks + build_extensions + write_build_info_file + run_post_build_hooks - generate_bin - write_spec - write_cache_file - end + generate_bin + write_spec + write_cache_file say spec.post_install_message unless spec.post_install_message.nil? + spec.loaded_from = spec_file + Gem::Specification.add_spec spec unless Gem::Specification.include? spec run_post_install_hooks @@ -332,14 +336,6 @@ class Gem::Installer end ## - # The location of of the default spec file for default gems. - # - - def default_spec_file - File.join gem_home, "specifications/default", "#{spec.full_name}.gemspec" - end - - ## # Writes the .gemspec specification (in Ruby) to the gem home's # specifications directory. @@ -351,16 +347,6 @@ class Gem::Installer end ## - # Writes the full .gemspec specification (in Ruby) to the gem home's - # specifications/default directory. - - def write_default_spec - File.open(default_spec_file, "w") do |file| - file.puts spec.to_ruby - end - end - - ## # Creates windows .bat files for easy running of commands def generate_windows_script(filename, bindir) @@ -561,13 +547,13 @@ class Gem::Installer :bin_dir => nil, :env_shebang => false, :force => false, + :install_dir => Gem.dir, :only_install_dir => false }.merge options @env_shebang = options[:env_shebang] @force = options[:force] - @install_dir = options[:install_dir] - @gem_home = options[:install_dir] || Gem.dir + @gem_home = options[:install_dir] @ignore_dependencies = options[:ignore_dependencies] @format_executable = options[:format_executable] @security_policy = options[:security_policy] @@ -642,7 +628,7 @@ TEXT end ## - # return the stub script text used to launch the true Ruby script + # return the stub script text used to launch the true ruby script def windows_stub_script(bindir, bin_file_name) ruby = File.basename(Gem.ruby).chomp('"') @@ -661,20 +647,75 @@ TEXT # configure scripts and rakefiles or mkrf_conf files. def build_extensions - builder = Gem::Ext::Builder.new spec, @build_args + return if spec.extensions.empty? - builder.build_extensions + if @build_args.empty? + say "Building native extensions. This could take a while..." + else + say "Building native extensions with: '#{@build_args.join(' ')}'" + say "This could take a while..." + end + + dest_path = File.join gem_dir, spec.require_paths.first + ran_rake = false # only run rake once + + spec.extensions.each do |extension| + break if ran_rake + results = [] + + extension ||= "" + extension_dir = File.join gem_dir, File.dirname(extension) + + builder = case extension + when /extconf/ then + Gem::Ext::ExtConfBuilder + when /configure/ then + Gem::Ext::ConfigureBuilder + when /rakefile/i, /mkrf_conf/i then + ran_rake = true + Gem::Ext::RakeBuilder + when /CMakeLists.txt/ then + Gem::Ext::CmakeBuilder + else + message = "No builder for extension '#{extension}'" + extension_build_error extension_dir, message + end + + begin + FileUtils.mkdir_p dest_path + + CHDIR_MUTEX.synchronize do + Dir.chdir extension_dir do + results = builder.build(extension, gem_dir, dest_path, + results, @build_args) + + say results.join("\n") if Gem.configuration.really_verbose + end + end + rescue + extension_build_error(extension_dir, results.join("\n"), $@) + end + end end ## # Logs the build +output+ in +build_dir+, then raises ExtensionBuildError. - # - # TODO: Delete this for RubyGems 3. It remains for API compatibility - def extension_build_error(build_dir, output, backtrace = nil) # :nodoc: - builder = Gem::Ext::Builder.new spec, @build_args + def extension_build_error(build_dir, output, backtrace = nil) + gem_make_out = File.join build_dir, 'gem_make.out' + + open gem_make_out, 'wb' do |io| io.puts output end - builder.build_error build_dir, output, backtrace + message = <<-EOF +ERROR: Failed to build gem native extension. + + #{output} + +Gem files will remain installed in #{gem_dir} for inspection. +Results logged to #{gem_make_out} +EOF + + raise ExtensionBuildError, message, backtrace end ## @@ -687,15 +728,6 @@ TEXT end ## - # Extracts only the bin/ files from the gem into the gem directory. - # This is used by default gems to allow a gem-aware stub to function - # without the full gem installed. - - def extract_bin - @package.extract_files gem_dir, "bin/*" - end - - ## # Prefix and suffix the program filename the same as ruby. def formatted_program_filename(filename) @@ -718,7 +750,7 @@ TEXT ## # Performs various checks before installing the gem such as the install - # repository is writable and its directories exist, required Ruby and + # repository is writable and its directories exist, required ruby and # rubygems versions are met and that dependencies are installed. # # Version and dependency checks are skipped if this install is forced. @@ -735,11 +767,7 @@ TEXT ensure_loadable_spec - if options[:install_as_default] - Gem.ensure_default_gem_subdirectories gem_home - else - Gem.ensure_gem_subdirectories gem_home - end + Gem.ensure_gem_subdirectories gem_home return true if @force diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb index f16ab369fa..d16fad26f1 100644 --- a/lib/rubygems/name_tuple.rb +++ b/lib/rubygems/name_tuple.rb @@ -43,20 +43,6 @@ class Gem::NameTuple end ## - # Returns the full name (name-version) of this Gem. Platform information is - # included if it is not the default Ruby platform. This mimics the behavior - # of Gem::Specification#full_name. - - def full_name - case @platform - when nil, 'ruby', '' - "#{@name}-#{@version}" - else - "#{@name}-#{@version}-#{@platform}" - end - end - - ## # Indicate if this NameTuple matches the current platform. def match_platform? @@ -73,7 +59,12 @@ class Gem::NameTuple # Return the name that the gemspec file would be def spec_name - "#{full_name}.gemspec" + case @platform + when nil, 'ruby', '' + "#{@name}-#{@version}.gemspec" + else + "#{@name}-#{@version}-#{@platform}.gemspec" + end end ## @@ -83,12 +74,10 @@ class Gem::NameTuple [@name, @version, @platform] end - def inspect # :nodoc: + def to_s "#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>" end - alias to_s inspect # :nodoc: - def <=> other to_a <=> other.to_a end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index ba379c24cb..957446257d 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -37,7 +37,7 @@ # the_gem.spec # get the spec out of the gem # the_gem.verify # check the gem is OK (contains valid gem specification, contains a not corrupt contents archive) # -# #files are the files in the .gem tar file, not the Ruby files in the gem +# #files are the files in the .gem tar file, not the ruby files in the gem # #extract_files and #contents automatically call #verify require 'rubygems/security' @@ -280,16 +280,11 @@ EOM algorithms = if @checksums then @checksums.keys else - [Gem::Security::DIGEST_NAME].compact + [Gem::Security::DIGEST_NAME] end algorithms.each do |algorithm| - digester = - if defined?(OpenSSL::Digest) then - OpenSSL::Digest.new algorithm - else - Digest.const_get(algorithm).new - end + digester = OpenSSL::Digest.new algorithm digester << entry.read(16384) until entry.eof? @@ -303,11 +298,8 @@ EOM ## # Extracts the files in this package into +destination_dir+ - # - # If +pattern+ is specified, only entries matching that glob will be - # extracted. - def extract_files destination_dir, pattern = "*" + def extract_files destination_dir verify unless @spec FileUtils.mkdir_p destination_dir @@ -318,7 +310,7 @@ EOM reader.each do |entry| next unless entry.full_name == 'data.tar.gz' - extract_tar_gz entry, destination_dir, pattern + extract_tar_gz entry, destination_dir return # ignore further entries end @@ -332,20 +324,11 @@ EOM # If an entry in the archive contains a relative path above # +destination_dir+ or an absolute path is encountered an exception is # raised. - # - # If +pattern+ is specified, only entries matching that glob will be - # extracted. - def extract_tar_gz io, destination_dir, pattern = "*" # :nodoc: + def extract_tar_gz io, destination_dir # :nodoc: open_tar_gz io do |tar| tar.each do |entry| - # Some entries start with "./" which fnmatch does not like, see github - # issue #644 - full_name = entry.full_name.sub %r%\A\./%, '' - - next unless File.fnmatch pattern, full_name - - destination = install_location full_name, destination_dir + destination = install_location entry.full_name, destination_dir FileUtils.rm_rf destination @@ -445,13 +428,12 @@ EOM # certificate and key are not present only checksum generation is set up. def setup_signer - passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] if @spec.signing_key then - @signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain, passphrase + @signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain @spec.signing_key = nil @spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_s } else - @signer = Gem::Security::Signer.new nil, nil, passphrase + @signer = Gem::Security::Signer.new nil, nil @spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_pem } if @signer.cert_chain end @@ -528,38 +510,27 @@ EOM end ## - # Verifies +entry+ in a .gem file. - - def verify_entry entry - file_name = entry.full_name - @files << file_name - - case file_name - when /\.sig$/ then - @signatures[$`] = entry.read if @security_policy - return - else - digest entry - end - - case file_name - when /^metadata(.gz)?$/ then - load_spec entry - when 'data.tar.gz' then - verify_gz entry - end - rescue => e - message = "package is corrupt, exception while verifying: " + - "#{e.message} (#{e.class})" - raise Gem::Package::FormatError.new message, @gem - end - - ## # Verifies the files of the +gem+ def verify_files gem gem.each do |entry| - verify_entry entry + file_name = entry.full_name + @files << file_name + + case file_name + when /\.sig$/ then + @signatures[$`] = entry.read if @security_policy + next + else + digest entry + end + + case file_name + when /^metadata(.gz)?$/ then + load_spec entry + when 'data.tar.gz' then + verify_gz entry + end end unless @spec then diff --git a/lib/rubygems/package/tar_test_case.rb b/lib/rubygems/package/tar_test_case.rb index 5253e32f36..4601f1328f 100644 --- a/lib/rubygems/package/tar_test_case.rb +++ b/lib/rubygems/package/tar_test_case.rb @@ -71,7 +71,7 @@ class Gem::Package::TarTestCase < Gem::TestCase SP(Z(to_oct(sum, 6))) end - def header(type, fname, dname, length, mode, mtime, checksum = nil) + def header(type, fname, dname, length, mode, checksum = nil) checksum ||= " " * 8 arr = [ # struct tarfile_entry_posix @@ -80,7 +80,7 @@ class Gem::Package::TarTestCase < Gem::TestCase Z(to_oct(0, 7)), # char uid[8]; ditto Z(to_oct(0, 7)), # char gid[8]; ditto Z(to_oct(length, 11)), # char size[12]; 0 padded, octal, null - Z(to_oct(mtime, 11)), # char mtime[12]; 0 padded, octal, null + Z(to_oct(0, 11)), # char mtime[12]; 0 padded, octal, null checksum, # char checksum[8]; 0 padded, octal, null, space type, # char typeflag[1]; file: "0" dir: "5" "\0" * 100, # char linkname[100]; ASCII + (Z unless filled) @@ -105,16 +105,16 @@ class Gem::Package::TarTestCase < Gem::TestCase ret end - def tar_dir_header(name, prefix, mode, mtime) - h = header("5", name, prefix, 0, mode, mtime) + def tar_dir_header(name, prefix, mode) + h = header("5", name, prefix, 0, mode) checksum = calc_checksum(h) - header("5", name, prefix, 0, mode, mtime, checksum) + header("5", name, prefix, 0, mode, checksum) end - def tar_file_header(fname, dname, mode, length, mtime) - h = header("0", fname, dname, length, mode, mtime) + def tar_file_header(fname, dname, mode, length) + h = header("0", fname, dname, length, mode) checksum = calc_checksum(h) - header("0", fname, dname, length, mode, mtime, checksum) + header("0", fname, dname, length, mode, checksum) end def to_oct(n, pad_size) @@ -130,7 +130,7 @@ class Gem::Package::TarTestCase < Gem::TestCase end def util_dir_entry - util_entry tar_dir_header("foo", "bar", 0, Time.now) + util_entry tar_dir_header("foo", "bar", 0) end end diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb index e1b38ad6b5..f2c11e3544 100644 --- a/lib/rubygems/package/tar_writer.rb +++ b/lib/rubygems/package/tar_writer.rb @@ -4,8 +4,6 @@ # See LICENSE.txt for additional licensing information. #++ -require 'digest' - ## # Allows writing of tar files @@ -123,8 +121,7 @@ class Gem::Package::TarWriter @io.pos = init_pos header = Gem::Package::TarHeader.new :name => name, :mode => mode, - :size => size, :prefix => prefix, - :mtime => Time.now + :size => size, :prefix => prefix @io.write header @io.pos = final_pos @@ -143,15 +140,7 @@ class Gem::Package::TarWriter def add_file_digest name, mode, digest_algorithms # :yields: io digests = digest_algorithms.map do |digest_algorithm| digest = digest_algorithm.new - digest_name = - if digest.respond_to? :name then - digest.name - else - /::([^:]+)$/ =~ digest_algorithm.name - $1 - end - - [digest_name, digest] + [digest.name, digest] end digests = Hash[*digests.flatten] @@ -176,32 +165,22 @@ class Gem::Package::TarWriter def add_file_signed name, mode, signer digest_algorithms = [ signer.digest_algorithm, - Digest::SHA512, - ].compact.uniq + OpenSSL::Digest::SHA512, + ].uniq digests = add_file_digest name, mode, digest_algorithms do |io| yield io end - signature_digest = digests.values.compact.find do |digest| - digest_name = - if digest.respond_to? :name then - digest.name - else - /::([^:]+)$/ =~ digest.class.name - $1 - end - - digest_name == signer.digest_name + signature_digest = digests.values.find do |digest| + digest.name == signer.digest_name end - if signer.key then - signature = signer.sign signature_digest.digest + signature = signer.sign signature_digest.digest - add_file_simple "#{name}.sig", 0444, signature.length do |io| - io.write signature - end - end + add_file_simple "#{name}.sig", 0444, signature.length do |io| + io.write signature + end if signature digests end @@ -216,8 +195,7 @@ class Gem::Package::TarWriter name, prefix = split_name name header = Gem::Package::TarHeader.new(:name => name, :mode => mode, - :size => size, :prefix => prefix, - :mtime => Time.now).to_s + :size => size, :prefix => prefix).to_s @io.write header os = BoundedStream.new @io, size @@ -278,8 +256,7 @@ class Gem::Package::TarWriter header = Gem::Package::TarHeader.new :name => name, :mode => mode, :typeflag => "5", :size => 0, - :prefix => prefix, - :mtime => Time.now + :prefix => prefix @io.write header diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb index 2af303eecf..7195b322ef 100644 --- a/lib/rubygems/path_support.rb +++ b/lib/rubygems/path_support.rb @@ -13,10 +13,6 @@ class Gem::PathSupport attr_reader :path ## - # Directory with spec cache - attr_reader :spec_cache_dir # :nodoc: - - ## # # Constructor. Takes a single argument which is to be treated like a # hashtable, or defaults to ENV, the system environment. @@ -32,12 +28,6 @@ class Gem::PathSupport end self.path = env["GEM_PATH"] || ENV["GEM_PATH"] - - @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/platform.rb b/lib/rubygems/platform.rb index 247ee6ed3e..4a4674b72f 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -2,8 +2,6 @@ require "rubygems/deprecate" ## # Available list of platforms for targeting Gem installations. -# -# See `gem help platform` for information on platform matching. class Gem::Platform @@ -131,16 +129,12 @@ class Gem::Platform # Does +other+ match this platform? Two platforms match if they have the # same CPU, or either has a CPU of 'universal', they have the same OS, and # they have the same version, or either has no version. - # - # Additionally, the platform will match if the local CPU is 'arm' and the - # other CPU starts with "arm" (for generic ARM family support). def ===(other) return nil unless Gem::Platform === other # cpu - (@cpu == 'universal' or other.cpu == 'universal' or @cpu == other.cpu or - (@cpu == 'arm' and other.cpu =~ /\Aarm/)) and + (@cpu == 'universal' or other.cpu == 'universal' or @cpu == other.cpu) and # os @os == other.os and @@ -181,13 +175,13 @@ class Gem::Platform end ## - # A pure-Ruby gem that may use Gem::Specification#extensions to build + # A pure-ruby gem that may use Gem::Specification#extensions to build # binary files. RUBY = 'ruby' ## - # A platform-specific gem that is built for the packaging Ruby's platform. + # A platform-specific gem that is built for the packaging ruby's platform. # This will be replaced with Gem::Platform::local. CURRENT = 'current' diff --git a/lib/rubygems/psych_additions.rb b/lib/rubygems/psych_additions.rb index dcc13fdf2e..08a5cb37ea 100644 --- a/lib/rubygems/psych_additions.rb +++ b/lib/rubygems/psych_additions.rb @@ -3,7 +3,7 @@ # in Specification._load, but if we don't have the constant, Marshal # blows up. -module Psych # :nodoc: +module Psych class PrivateType end end diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index 6abd6bd9db..86bad9de41 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -1,7 +1,7 @@ require 'rubygems' -require 'rubygems/request' -require 'rubygems/uri_formatter' require 'rubygems/user_interaction' +require 'thread' +require 'uri' require 'resolv' ## @@ -72,7 +72,18 @@ class Gem::RemoteFetcher Socket.do_not_reverse_lookup = true - @proxy = proxy + @connections = {} + @connections_mutex = Mutex.new + @requests = Hash.new 0 + @proxy_uri = + case proxy + when :no_proxy then nil + when nil then get_proxy_from_env + when URI::HTTP then proxy + else URI.parse(proxy) + end + @user_agent = user_agent + @env_no_proxy = get_no_proxy_from_env @dns = dns end @@ -191,7 +202,7 @@ class Gem::RemoteFetcher source_uri.path end - source_path = Gem::UriFormatter.new(source_path).unescape + source_path = unescape source_path begin FileUtils.cp source_path, local_gem_path unless @@ -310,6 +321,128 @@ class Gem::RemoteFetcher response['content-length'].to_i end + def escape(str) + return unless str + @uri_parser ||= uri_escaper + @uri_parser.escape str + end + + def unescape(str) + return unless str + @uri_parser ||= uri_escaper + @uri_parser.unescape str + end + + def uri_escaper + URI::Parser.new + rescue NameError + URI + end + + ## + # Returns list of no_proxy entries (if any) from the environment + + def get_no_proxy_from_env + env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY'] + + return [] if env_no_proxy.nil? or env_no_proxy.empty? + + env_no_proxy.split(/\s*,\s*/) + end + + ## + # Returns an HTTP proxy URI if one is set in the environment variables. + + def get_proxy_from_env + env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] + + return nil if env_proxy.nil? or env_proxy.empty? + + uri = URI.parse(normalize_uri(env_proxy)) + + if uri and uri.user.nil? and uri.password.nil? then + # Probably we have http_proxy_* variables? + uri.user = escape(ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER']) + uri.password = escape(ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS']) + end + + uri + end + + ## + # Normalize the URI by adding "http://" if it is missing. + + def normalize_uri(uri) + (uri =~ /^(https?|ftp|file):/i) ? uri : "http://#{uri}" + end + + ## + # Creates or an HTTP connection based on +uri+, or retrieves an existing + # connection, using a proxy if needed. + + def connection_for(uri) + net_http_args = [uri.host, uri.port] + + if @proxy_uri and not no_proxy?(uri.host) then + net_http_args += [ + @proxy_uri.host, + @proxy_uri.port, + @proxy_uri.user, + @proxy_uri.password + ] + end + + connection_id = [Thread.current.object_id, *net_http_args].join ':' + + 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) + end + + connection.start unless connection.started? + + connection + rescue defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : Errno::EHOSTDOWN, + Errno::EHOSTDOWN => e + raise FetchError.new(e.message, uri) + end + + def configure_connection_for_https(connection) + require 'net/https' + connection.use_ssl = true + connection.verify_mode = + Gem.configuration.ssl_verify_mode || OpenSSL::SSL::VERIFY_PEER + store = OpenSSL::X509::Store.new + if Gem.configuration.ssl_ca_cert + if File.directory? Gem.configuration.ssl_ca_cert + store.add_path Gem.configuration.ssl_ca_cert + else + store.add_file Gem.configuration.ssl_ca_cert + end + else + store.set_default_paths + add_rubygems_trusted_certs(store) + end + connection.cert_store = store + rescue LoadError => e + raise unless (e.respond_to?(:path) && e.path == 'openssl') || + e.message =~ / -- openssl$/ + + raise Gem::Exception.new( + 'Unable to require openssl, install OpenSSL and rebuild ruby (preferred) or use non-HTTPS sources') + end + + def add_rubygems_trusted_certs(store) + pattern = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__)) + Dir.glob(pattern).each do |ssl_cert_file| + store.add_file ssl_cert_file + end + end + def correct_for_windows_path(path) if path[0].chr == '/' && path[1].chr =~ /[a-z]/i && path[2].chr == ':' path = path[1..-1] @@ -318,17 +451,136 @@ class Gem::RemoteFetcher end end + def no_proxy? host + host = host.downcase + @env_no_proxy.each do |pattern| + pattern = pattern.downcase + return true if host[-pattern.length, pattern.length ] == pattern + end + return false + end + ## # Performs a Net::HTTP request of type +request_class+ on +uri+ returning # a Net::HTTP response object. request maintains a table of persistent # connections to reduce connect overhead. def request(uri, request_class, last_modified = nil) - request = Gem::Request.new uri, request_class, last_modified, @proxy + request = request_class.new uri.request_uri + + unless uri.nil? || uri.user.nil? || uri.user.empty? then + request.basic_auth uri.user, uri.password + end + + request.add_field 'User-Agent', @user_agent + request.add_field 'Connection', 'keep-alive' + request.add_field 'Keep-Alive', '30' + + if last_modified then + last_modified = last_modified.utc + request.add_field 'If-Modified-Since', last_modified.rfc2822 + end + + yield request if block_given? + + connection = connection_for uri + + retried = false + bad_response = false + + begin + @requests[connection.object_id] += 1 + + say "#{request.method} #{uri}" if + Gem.configuration.really_verbose + + file_name = File.basename(uri.path) + # perform download progress reporter only for gems + if request.response_body_permitted? && file_name =~ /\.gem$/ + reporter = ui.download_reporter + response = connection.request(request) do |incomplete_response| + if Net::HTTPOK === incomplete_response + reporter.fetch(file_name, incomplete_response.content_length) + downloaded = 0 + data = '' + + incomplete_response.read_body do |segment| + data << segment + downloaded += segment.length + reporter.update(downloaded) + end + reporter.done + if incomplete_response.respond_to? :body= + incomplete_response.body = data + else + incomplete_response.instance_variable_set(:@body, data) + end + end + end + else + response = connection.request request + end + + say "#{response.code} #{response.message}" if + Gem.configuration.really_verbose + + rescue Net::HTTPBadResponse + say "bad response" if Gem.configuration.really_verbose + + reset connection + + raise FetchError.new('too many bad responses', uri) if bad_response + + bad_response = true + retry + # HACK work around EOFError bug in Net::HTTP + # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible + # to install gems. + rescue EOFError, Timeout::Error, + Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE + + requests = @requests[connection.object_id] + say "connection reset after #{requests} requests, retrying" if + Gem.configuration.really_verbose + + raise FetchError.new('too many connection resets', uri) if retried + + reset connection + + retried = true + retry + end - request.fetch do |req| - yield req if block_given? + response + end + + ## + # Resets HTTP connection +connection+. + + def reset(connection) + @requests.delete connection.object_id + + connection.finish + connection.start + end + + def user_agent + ua = "RubyGems/#{Gem::VERSION} #{Gem::Platform.local}" + + ruby_version = RUBY_VERSION + ruby_version += 'dev' if RUBY_PATCHLEVEL == -1 + + ua << " Ruby/#{ruby_version} (#{RUBY_RELEASE_DATE}" + if RUBY_PATCHLEVEL >= 0 then + ua << " patchlevel #{RUBY_PATCHLEVEL}" + elsif defined?(RUBY_REVISION) then + ua << " revision #{RUBY_REVISION}" end + ua << ")" + + ua << " #{RUBY_ENGINE}" if defined?(RUBY_ENGINE) and RUBY_ENGINE != 'ruby' + + ua end def https?(uri) diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index a45c64e0b4..6c52b90c40 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -5,179 +5,178 @@ require 'rubygems/dependency_list' require 'rubygems/installer' require 'tsort' -class Gem::RequestSet +module Gem + class RequestSet - include TSort + include TSort - ## - # Array of gems to install even if already installed + def initialize(*deps) + @dependencies = deps - attr_reader :always_install - - attr_reader :dependencies - - attr_accessor :development - - ## - # Treat missing dependencies as silent errors - - attr_accessor :soft_missing + yield self if block_given? + end - def initialize *deps - @dependencies = deps + attr_reader :dependencies - @always_install = [] - @development = false - @requests = [] - @soft_missing = false - @sorted = nil - @specs = nil + # Declare that a gem of name +name+ with +reqs+ requirements + # is needed. + # + def gem(name, *reqs) + @dependencies << Gem::Dependency.new(name, reqs) + end - yield self if block_given? - end + # Add +deps+ Gem::Depedency objects to the set. + # + def import(deps) + @dependencies += deps + end - ## - # Declare that a gem of name +name+ with +reqs+ requirements is needed. + # Resolve the requested dependencies and return an Array of + # Specification objects to be activated. + # + def resolve(set=nil) + r = Gem::DependencyResolver.new(@dependencies, set) + @requests = r.resolve + end - def gem name, *reqs - @dependencies << Gem::Dependency.new(name, reqs) - end + # Resolve the requested dependencies against the gems + # available via Gem.path and return an Array of Specification + # objects to be activated. + # + def resolve_current + resolve DependencyResolver::CurrentSet.new + end - ## - # Add +deps+ Gem::Dependency objects to the set. + # Load a dependency management file. + # + def load_gemdeps(path) + gf = GemDepedencyAPI.new(self, path) + gf.load + end - def import deps - @dependencies += deps - end + def specs + @specs ||= @requests.map { |r| r.full_spec } + end - def install options, &block - if dir = options[:install_dir] - return install_into dir, false, options, &block + def tsort_each_node(&block) + @requests.each(&block) end - cache_dir = options[:cache_dir] || Gem.dir + def tsort_each_child(node) + node.spec.dependencies.each do |dep| + next if dep.type == :development + + match = @requests.find { |r| dep.match? r.spec.name, r.spec.version } + if match + begin + yield match + rescue TSort::Cyclic + end + else + raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}" + end + end + end - specs = [] + def sorted_requests + @sorted ||= strongly_connected_components.flatten + end - sorted_requests.each do |req| - if req.installed? and - @always_install.none? { |spec| spec == req.spec.spec } then - yield req, nil if block_given? - next + def specs_in(dir) + Dir["#{dir}/specifications/*.gemspec"].map do |g| + Gem::Specification.load g end + end - path = req.download cache_dir + def install_into(dir, force=true, &b) + existing = force ? [] : specs_in(dir) - inst = Gem::Installer.new path, options + dir = File.expand_path dir - yield req, inst if block_given? + installed = [] - specs << inst.install - end + sorted_requests.each do |req| + if existing.find { |s| s.full_name == req.spec.full_name } + b.call req, nil if b + next + end - specs - end + path = req.download(dir) - def install_into dir, force = true, options = {} - existing = force ? [] : specs_in(dir) - existing.delete_if { |s| @always_install.include? s } + inst = Gem::Installer.new path, :install_dir => dir, + :only_install_dir => true - dir = File.expand_path dir + b.call req, inst if b - installed = [] + inst.install - sorted_requests.each do |req| - if existing.find { |s| s.full_name == req.spec.full_name } - yield req, nil if block_given? - next + installed << req end - path = req.download(dir) + installed + end - unless path then # already installed - yield req, nil if block_given? - next + def install(options, &b) + if dir = options[:install_dir] + return install_into(dir, false, &b) end - options[:install_dir] = dir - options[:only_install_dir] = true - - inst = Gem::Installer.new path, options + cache_dir = options[:cache_dir] || Gem.dir - yield req, inst if block_given? + specs = [] - inst.install + sorted_requests.each do |req| + if req.installed? + b.call req, nil if b + next + end - installed << req - end + path = req.download cache_dir - installed - end + inst = Gem::Installer.new path, options - ## - # Load a dependency management file. + b.call req, inst if b - def load_gemdeps path - gf = Gem::RequestSet::GemDepedencyAPI.new self, path - gf.load - end + specs << inst.install + end - ## - # Resolve the requested dependencies and return an Array of Specification - # objects to be activated. + specs + end - def resolve set = nil - resolver = Gem::DependencyResolver.new @dependencies, set - resolver.development = @development - resolver.soft_missing = @soft_missing + # A semi-compatible DSL for Bundler's Gemfile format + # + class GemDepedencyAPI + def initialize(set, path) + @set = set + @path = path + end - @requests = resolver.resolve - end + def load + instance_eval File.read(@path).untaint, @path, 1 + end - ## - # Resolve the requested dependencies against the gems available via Gem.path - # and return an Array of Specification objects to be activated. + # DSL - def resolve_current - resolve Gem::DependencyResolver::CurrentSet.new - end + def source(url) + end - def sorted_requests - @sorted ||= strongly_connected_components.flatten - end + def gem(name, *reqs) + # Ignore the opts for now. + reqs.pop if reqs.last.kind_of?(Hash) - def specs - @specs ||= @requests.map { |r| r.full_spec } - end - - def specs_in dir - Dir["#{dir}/specifications/*.gemspec"].map do |g| - Gem::Specification.load g - end - end + @set.gem name, *reqs + end - def tsort_each_node &block # :nodoc: - @requests.each(&block) - end + def platform(what) + if what == :ruby + yield + end + end - def tsort_each_child node # :nodoc: - node.spec.dependencies.each do |dep| - next if dep.type == :development and not @development + alias_method :platforms, :platform - match = @requests.find { |r| dep.match? r.spec.name, r.spec.version } - if match - begin - yield match - rescue TSort::Cyclic - end - else - unless @soft_missing - raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}" - end + def group(*what) end end end - end - -require 'rubygems/request_set/gem_dependency_api' diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb index bfd6fd225b..bed47ab9f3 100644 --- a/lib/rubygems/security.rb +++ b/lib/rubygems/security.rb @@ -12,6 +12,20 @@ begin rescue LoadError => e raise unless (e.respond_to?(:path) && e.path == 'openssl') || e.message =~ / -- openssl$/ + + module OpenSSL # :nodoc: + class Digest # :nodoc: + class SHA1 # :nodoc: + def name + 'SHA1' + end + end + end + module PKey # :nodoc: + class RSA # :nodoc: + end + end + end end ## @@ -338,26 +352,17 @@ module Gem::Security ## # Digest algorithm used to sign gems - DIGEST_ALGORITHM = - if defined?(OpenSSL::Digest) then - OpenSSL::Digest::SHA1 - end + DIGEST_ALGORITHM = OpenSSL::Digest::SHA1 ## # Used internally to select the signing digest from all computed digests - DIGEST_NAME = # :nodoc: - if DIGEST_ALGORITHM then - DIGEST_ALGORITHM.new.name - end + DIGEST_NAME = DIGEST_ALGORITHM.new.name # :nodoc: ## # Algorithm for creating the key pair used to sign gems - KEY_ALGORITHM = - if defined?(OpenSSL::PKey) then - OpenSSL::PKey::RSA - end + KEY_ALGORITHM = OpenSSL::PKey::RSA ## # Length of keys created by KEY_ALGORITHM @@ -365,12 +370,6 @@ module Gem::Security KEY_LENGTH = 2048 ## - # Cipher used to encrypt the key pair used to sign gems. - # Must be in the list returned by OpenSSL::Cipher.ciphers - - KEY_CIPHER = OpenSSL::Cipher.new('AES-256-CBC') if defined?(OpenSSL::Cipher) - - ## # One year in seconds ONE_YEAR = 86400 * 365 @@ -564,18 +563,13 @@ module Gem::Security ## # Writes +pemmable+, which must respond to +to_pem+ to +path+ with the given - # +permissions+. If passed +cipher+ and +passphrase+ those arguments will be - # passed to +to_pem+. + # +permissions+. - def self.write pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER + def self.write pemmable, path, permissions = 0600 path = File.expand_path path open path, 'wb', permissions do |io| - if passphrase and cipher - io.write pemmable.to_pem cipher, passphrase - else - io.write pemmable.to_pem - end + io.write pemmable.to_pem end path @@ -585,11 +579,8 @@ module Gem::Security end -if defined?(OpenSSL::SSL) then - require 'rubygems/security/policy' - require 'rubygems/security/policies' - require 'rubygems/security/trust_dir' -end - +require 'rubygems/security/policy' +require 'rubygems/security/policies' require 'rubygems/security/signer' +require 'rubygems/security/trust_dir' diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb index 7238b2e477..467ee932b5 100644 --- a/lib/rubygems/security/policy.rb +++ b/lib/rubygems/security/policy.rb @@ -1,5 +1,3 @@ -require 'rubygems/user_interaction' - ## # A Gem::Security::Policy object encapsulates the settings for verifying # signed gem files. This is the base class. You can either declare an @@ -8,8 +6,6 @@ require 'rubygems/user_interaction' class Gem::Security::Policy - include Gem::UserInteraction - attr_reader :name attr_accessor :only_signed @@ -179,19 +175,6 @@ class Gem::Security::Policy true end - ## - # Extracts the email or subject from +certificate+ - - def subject certificate # :nodoc: - certificate.extensions.each do |extension| - next unless extension.oid == 'subjectAltName' - - return extension.value - end - - certificate.subject.to_s - end - def inspect # :nodoc: ("[Policy: %s - data: %p signer: %p chain: %p root: %p " + "signed-only: %p trusted-only: %p]") % [ @@ -201,24 +184,16 @@ class Gem::Security::Policy end ## - # For +full_name+, verifies the certificate +chain+ is valid, the +digests+ - # match the signatures +signatures+ created by the signer depending on the - # +policy+ settings. + # Verifies the certificate +chain+ is valid, the +digests+ match the + # signatures +signatures+ created by the signer depending on the +policy+ + # settings. # # If +key+ is given it is used to validate the signing certificate. - def verify chain, key = nil, digests = {}, signatures = {}, - full_name = '(unknown)' - if signatures.empty? then - if @only_signed then - raise Gem::Security::Exception, - "unsigned gems are not allowed by the #{name} policy" - elsif digests.empty? then - # lack of signatures is irrelevant if there is nothing to check - # against - else - alert_warning "#{full_name} is not signed" - end + def verify chain, key = nil, digests = {}, signatures = {} + if @only_signed and signatures.empty? then + raise Gem::Security::Exception, + "unsigned gems are not allowed by the #{name} policy" end opt = @opt @@ -247,13 +222,7 @@ class Gem::Security::Policy check_root chain, time if @verify_root - if @only_trusted then - check_trust chain, digester, trust_dir - elsif signatures.empty? and digests.empty? then - # trust is irrelevant if there's no signatures to verify - else - alert_warning "#{subject signer} is not trusted for #{full_name}" - end + check_trust chain, digester, trust_dir if @only_trusted signatures.each do |file, _| digest = signer_digests[file] @@ -283,7 +252,7 @@ class Gem::Security::Policy OpenSSL::X509::Certificate.new cert_pem end - verify chain, nil, digests, signatures, spec.full_name + verify chain, nil, digests, signatures true end diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb index bb1eae7cf2..78455c0732 100644 --- a/lib/rubygems/security/signer.rb +++ b/lib/rubygems/security/signer.rb @@ -29,7 +29,7 @@ class Gem::Security::Signer # +chain+ containing X509 certificates, encoding certificates or paths to # certificates. - def initialize key, cert_chain, passphrase = nil + def initialize key, cert_chain @cert_chain = cert_chain @key = key @@ -46,7 +46,7 @@ class Gem::Security::Signer @digest_algorithm = Gem::Security::DIGEST_ALGORITHM @digest_name = Gem::Security::DIGEST_NAME - @key = OpenSSL::PKey::RSA.new File.read(@key), passphrase if + @key = OpenSSL::PKey::RSA.new File.read @key if @key and not OpenSSL::PKey::RSA === @key if @cert_chain then @@ -63,22 +63,6 @@ class Gem::Security::Signer end ## - # Extracts the full name of +cert+. If the certificate has a subjectAltName - # this value is preferred, otherwise the subject is used. - - def extract_name cert # :nodoc: - subject_alt_name = cert.extensions.find { |e| 'subjectAltName' == e.oid } - - if subject_alt_name then - /\Aemail:/ =~ subject_alt_name.value - - $' || subject_alt_name.value - else - cert.subject - end - end - - ## # Loads any missing issuers in the cert chain from the trusted certificates. # # If the issuer does not exist it is ignored as it will be checked later. @@ -105,9 +89,7 @@ class Gem::Security::Signer re_sign_key end - full_name = extract_name @cert_chain.last - - Gem::Security::SigningPolicy.verify @cert_chain, @key, {}, {}, full_name + Gem::Security::SigningPolicy.verify @cert_chain, @key @key.sign @digest_algorithm.new, data end diff --git a/lib/rubygems/server.rb b/lib/rubygems/server.rb index 3ca588ae92..dd582193ee 100644 --- a/lib/rubygems/server.rb +++ b/lib/rubygems/server.rb @@ -670,13 +670,13 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } # documentation for the particular gem, otherwise a list with results is # shown. # - # === Additional trick - install documentation for Ruby core + # === Additional trick - install documentation for ruby core # # Note: please adjust paths accordingly use for example 'locate yaml.rb' and # 'gem environment' to identify directories, that are specific for your # local installation # - # 1. install Ruby sources + # 1. install ruby sources # cd /usr/src # sudo apt-get source ruby # @@ -702,7 +702,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } # name pattern was found. # # The search is based on the file system content, not on the gems metadata. - # This allows additional documentation folders like 'core' for the Ruby core + # This allows additional documentation folders like 'core' for the ruby core # documentation - just put it underneath the main doc folder. def show_rdoc_for_pattern(pattern, res) diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index f0e2a597b9..96d57870e2 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -25,23 +25,14 @@ class Gem::Source end def <=>(other) - case other - when Gem::Source::Installed, - Gem::Source::Local, - Gem::Source::SpecificFile then - -1 - when Gem::Source then - if !@uri - return 0 unless other.uri - return 1 - end + if !@uri + return 0 unless other.uri + return -1 + end - return -1 if !other.uri + return 1 if !other.uri - @uri.to_s <=> other.uri.to_s - else - nil - end + @uri.to_s <=> other.uri.to_s end include Comparable @@ -67,7 +58,8 @@ class Gem::Source def cache_dir(uri) # Correct for windows paths escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/') - File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) + root = File.join Gem.user_home, '.gem', 'specs' + File.join root, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) end def update_cache? @@ -149,16 +141,4 @@ class Gem::Source fetcher = Gem::RemoteFetcher.fetcher fetcher.download spec, @uri.to_s, dir end - - def pretty_print q # :nodoc: - q.group 2, '[Remote:', ']' do - q.breakable - q.text @uri.to_s - end - end - end - -require 'rubygems/source/installed' -require 'rubygems/source/specific_file' -require 'rubygems/source/local' diff --git a/lib/rubygems/source_local.rb b/lib/rubygems/source_local.rb index 0808f4694a..44b170c4a4 100644 --- a/lib/rubygems/source_local.rb +++ b/lib/rubygems/source_local.rb @@ -1,5 +1,92 @@ require 'rubygems/source' -require 'rubygems/source_local' -# TODO warn upon require, this file is deprecated. +class Gem::Source::Local < Gem::Source + def initialize + @uri = nil + end + def load_specs(type) + names = [] + + @specs = {} + + Dir["*.gem"].each do |file| + begin + pkg = Gem::Package.new(file) + rescue SystemCallError, Gem::Package::FormatError + # ignore + else + tup = pkg.spec.name_tuple + @specs[tup] = [File.expand_path(file), pkg] + + case type + when :released + unless pkg.spec.version.prerelease? + names << pkg.spec.name_tuple + end + when :prerelease + if pkg.spec.version.prerelease? + names << pkg.spec.name_tuple + end + when :latest + tup = pkg.spec.name_tuple + + cur = names.find { |x| x.name == tup.name } + if !cur + names << tup + elsif cur.version < tup.version + names.delete cur + names << tup + end + else + names << pkg.spec.name_tuple + end + end + end + + names + end + + def find_gem(gem_name, version=Gem::Requirement.default, + prerelease=false) + load_specs :complete + + found = [] + + @specs.each do |n, data| + if n.name == gem_name + s = data[1].spec + + if version.satisfied_by?(s.version) + if prerelease + found << s + elsif !s.version.prerelease? + found << s + end + end + end + end + + found.sort_by { |s| s.version }.last + end + + def fetch_spec(name) + load_specs :complete + + if data = @specs[name] + data.last.spec + else + raise Gem::Exception, "Unable to find spec for '#{name}'" + end + end + + def download(spec, cache_dir=nil) + load_specs :complete + + @specs.each do |name, data| + return data[0] if data[1].spec == spec + end + + raise Gem::Exception, "Unable to find file for '#{spec.full_name}'" + end +end diff --git a/lib/rubygems/source_specific_file.rb b/lib/rubygems/source_specific_file.rb index f785c2667c..d296e617cc 100644 --- a/lib/rubygems/source_specific_file.rb +++ b/lib/rubygems/source_specific_file.rb @@ -1,4 +1,28 @@ -require 'rubygems/source/specific_file' +class Gem::Source::SpecificFile < Gem::Source + def initialize(file) + @uri = nil + @path = ::File.expand_path(file) -# TODO warn upon require, this file is deprecated. + @package = Gem::Package.new @path + @spec = @package.spec + @name = @spec.name_tuple + end + attr_reader :spec + + def load_specs(*a) + [@name] + end + + def fetch_spec(name) + return @spec if name == @name + raise Gem::Exception, "Unable to find '#{name}'" + @spec + end + + def download(spec, dir=nil) + return @path if spec == @spec + raise Gem::Exception, "Unable to download '#{spec.full_name}'" + end + +end diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 2ed7d4286a..3d484d1c13 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -38,6 +38,7 @@ class Gem::SpecFetcher end def initialize + @dir = File.join Gem.user_home, '.gem', 'specs' @update_cache = File.stat(Gem.user_home).uid == Process.uid @specs = {} @@ -74,12 +75,6 @@ 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) @@ -200,11 +195,8 @@ class Gem::SpecFetcher when :released tuples_for source, :released when :complete - names = - tuples_for(source, :prerelease, true) + + tuples_for(source, :prerelease, true) + tuples_for(source, :released) - - names.sort when :prerelease tuples_for(source, :prerelease) else @@ -223,15 +215,15 @@ class Gem::SpecFetcher def tuples_for(source, type, gracefully_ignore=false) cache = @caches[type] - tuples = + if gracefully_ignore begin cache[source.uri] ||= source.load_specs(type) rescue Gem::RemoteFetcher::FetchError - raise unless gracefully_ignore [] end - - tuples.sort_by { |tup| tup.name } + else + cache[source.uri] ||= source.load_specs(type) + end end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 12943a3e24..87557cee5f 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -5,13 +5,10 @@ # See LICENSE.txt for permissions. #++ - require 'rubygems/version' require 'rubygems/requirement' require 'rubygems/platform' require 'rubygems/deprecate' -require 'rubygems/basic_specification' -require 'rubygems/stub_specification' # :stopdoc: # date.rb can't be loaded for `make install` due to miniruby @@ -34,7 +31,7 @@ class Date; end # s.homepage = 'https://rubygems.org/gems/example' # end # -# Starting in RubyGems 2.0, a Specification can hold arbitrary +# Starting in RubyGems 1.9.0, a Specification can hold arbitrary # metadata. This metadata is accessed via Specification#metadata # and has the following restrictions: # @@ -48,7 +45,7 @@ class Date; end # # s.metadata = { "bugtracker" => "http://somewhere.com/blah" } -class Gem::Specification < Gem::BasicSpecification +class Gem::Specification # REFACTOR: Consider breaking out this version stuff into a separate # module. There's enough special stuff around it that it may justify @@ -110,10 +107,6 @@ class Gem::Specification < Gem::BasicSpecification today = Time.now.utc TODAY = Time.utc(today.year, today.month, today.day) - LOAD_CACHE = {} - - private_constant :LOAD_CACHE if defined? private_constant - # :startdoc: ## @@ -163,17 +156,6 @@ class Gem::Specification < Gem::BasicSpecification :version => nil, } - Dupable = { } - - @@default_value.each do |k,v| - case v - when Time, Numeric, Symbol, true, false, nil - Dupable[k] = false - else - Dupable[k] = true - end - end - @@attributes = @@default_value.keys.sort_by { |s| s.to_s } @@array_attributes = @@default_value.reject { |k,v| v != [] }.keys @@nil_attributes, @@non_nil_attributes = @@default_value.keys.partition { |k| @@ -458,7 +440,7 @@ class Gem::Specification < Gem::BasicSpecification # # For example, the rake gem has rake as an executable. You don’t specify the # full path (as in bin/rake); all application-style files are expected to be - # found in bindir. These files must be executable Ruby files. Files that + # found in bindir. These files must be executable ruby files. Files that # use bash or other interpreters will not work. # # Usage: @@ -617,12 +599,17 @@ class Gem::Specification < Gem::BasicSpecification attr_writer :default_executable ## + # Path this gemspec was loaded from. This attribute is not persisted. + + attr_reader :loaded_from + + ## # Allows deinstallation of gems with legacy platforms. attr_writer :original_platform # :nodoc: ## - # The version of Ruby required by this gem + # The version of ruby required by this gem attr_reader :required_ruby_version @@ -646,68 +633,58 @@ class Gem::Specification < Gem::BasicSpecification attr_accessor :specification_version - def self._all # :nodoc: - unless defined?(@@all) && @@all then - @@all = stubs.map(&:to_spec) - - # After a reset, make sure already loaded specs - # are still marked as activated. - specs = {} - Gem.loaded_specs.each_value{|s| specs[s] = true} - @@all.each{|s| s.activated = true if specs[s]} - - _resort!(@@all) + class << self + def default_specifications_dir + File.join(Gem.default_dir, "specifications", "default") end - @@all - end - def self._clear_load_cache # :nodoc: - LOAD_CACHE.clear - end - - # :nodoc: - def self.each_gemspec(dirs) - dirs.each do |dir| - Dir[File.join(dir, "*.gemspec")].each do |path| - yield path.untaint - end + def each_spec(search_dirs) # :nodoc: + search_dirs.each { |dir| + Dir[File.join(dir, "*.gemspec")].each { |path| + spec = Gem::Specification.load path.untaint + # #load returns nil if the spec is bad, so we just ignore + # it at this stage + yield(spec) if spec + } + } end - end - # :nodoc: - def self.each_stub(dirs) - each_gemspec(dirs) do |path| - stub = Gem::StubSpecification.new(path) - yield stub if stub.valid? + def each_default(&block) # :nodoc: + each_spec([default_specifications_dir], + &block) end - end - # :nodoc: - def self.each_spec(dirs) - each_gemspec(dirs) do |path| - spec = self.load path - yield spec if spec + def each_normal(&block) # :nodoc: + each_spec(dirs, &block) end end - ## - # Returns a Gem::StubSpecification for every installed gem + def self._all # :nodoc: + unless defined?(@@all) && @@all then - def self.stubs - @@stubs ||= begin - stubs = {} - each_stub([default_specifications_dir] + dirs) do |stub| - stubs[stub.full_name] ||= stub + specs = {} + each_default do |spec| + specs[spec.full_name] ||= spec end + each_normal do |spec| + specs[spec.full_name] ||= spec + end + + @@all = specs.values - stubs = stubs.values - _resort!(stubs) - stubs + # After a reset, make sure already loaded specs + # are still marked as activated. + specs = {} + Gem.loaded_specs.each_value{|s| specs[s] = true} + @@all.each{|s| s.activated = true if specs[s]} + + _resort! end + @@all end - def self._resort!(specs) # :nodoc: - specs.sort! { |a, b| + def self._resort! # :nodoc: + @@all.sort! { |a, b| names = a.name <=> b.name next names if names.nonzero? b.version <=> a.version @@ -718,9 +695,7 @@ class Gem::Specification < Gem::BasicSpecification # Loads the default specifications. It should be called only once. def self.load_defaults - each_spec([default_specifications_dir]) do |spec| - # #load returns nil if the spec is bad, so we just ignore - # it at this stage + each_default do |spec| Gem.register_default_spec(spec) end end @@ -743,9 +718,7 @@ class Gem::Specification < Gem::BasicSpecification return if _all.include? spec _all << spec - stubs << spec - _resort!(_all) - _resort!(stubs) + _resort! end ## @@ -786,7 +759,7 @@ class Gem::Specification < Gem::BasicSpecification # -- wilsonb def self.all= specs - @@all = @@stubs = specs + @@all = specs end ## @@ -888,10 +861,9 @@ class Gem::Specification < Gem::BasicSpecification # amongst the specs that are not activated. def self.find_inactive_by_path path - stub = stubs.find { |s| - s.contains_requirable_file? path unless s.activated? + self.find { |spec| + spec.contains_requirable_file? path unless spec.activated? } - stub && stub.to_spec end ## @@ -972,7 +944,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 ## @@ -983,9 +955,6 @@ class Gem::Specification < Gem::BasicSpecification file = file.dup.untaint return unless File.file?(file) - spec = LOAD_CACHE[file] - return spec if spec - code = if defined? Encoding File.read file, :mode => 'r:UTF-8:-' else @@ -999,7 +968,6 @@ class Gem::Specification < Gem::BasicSpecification if Gem::Specification === spec spec.loaded_from = file.to_s - LOAD_CACHE[file] = spec return spec end @@ -1034,43 +1002,25 @@ class Gem::Specification < Gem::BasicSpecification end ## - # Return a list of all outdated local gem names. This method is HEAVY + # Return a list of all outdated specifications. This method is HEAVY # as it must go fetch specifications from the server. - # - # Use outdated_and_latest_version if you wish to retrieve the latest remote - # version as well. def self.outdated - outdated_and_latest_version.map { |local, _| local.name } - end - - ## - # Enumerates the outdated local gems yielding the local specification and - # the latest remote version. - # - # This method may take some time to return as it must check each local gem - # against the server's index. - - def self.outdated_and_latest_version - return enum_for __method__ unless block_given? + outdateds = [] # TODO: maybe we should switch to rubygems' version service? fetcher = Gem::SpecFetcher.fetcher - latest_specs(true).each do |local_spec| - dependency = - Gem::Dependency.new local_spec.name, ">= #{local_spec.version}" + latest_specs(true).each do |local| + dependency = Gem::Dependency.new local.name, ">= #{local.version}" + remotes, _ = fetcher.search_for_dependency dependency + remotes = remotes.map { |n, _| n.version } + latest = remotes.sort.last - remotes, = fetcher.search_for_dependency dependency - remotes = remotes.map { |n, _| n.version } - - latest_remote = remotes.sort.last - - yield [local_spec, latest_remote] if - latest_remote and local_spec.version < latest_remote + outdateds << local.name if latest and local.version < latest end - nil + outdateds end ## @@ -1081,7 +1031,6 @@ class Gem::Specification < Gem::BasicSpecification raise "wtf: #{spec.full_name} not in #{all_names.inspect}" unless _all.include? spec _all.delete spec - stubs.delete_if { |s| s.full_name == spec.full_name } end ## @@ -1106,8 +1055,6 @@ class Gem::Specification < Gem::BasicSpecification @@dirs = nil Gem.pre_reset_hooks.each { |hook| hook.call } @@all = nil - @@stubs = nil - _clear_load_cache unresolved = unresolved_deps unless unresolved.empty? then w = "W" + "ARN" @@ -1354,6 +1301,20 @@ class Gem::Specification < Gem::BasicSpecification end ## + # Returns the full path to the base gem directory. + # + # eg: /usr/local/lib/ruby/gems/1.8 + + def base_dir + return Gem.dir unless loaded_from + @base_dir ||= if default_gem? then + File.dirname File.dirname File.dirname loaded_from + else + File.dirname File.dirname loaded_from + end + end + + ## # Returns the full path to installed gem's bin directory. # # NOTE: do not confuse this with +bindir+, which is just 'bin', not @@ -1427,6 +1388,19 @@ class Gem::Specification < Gem::BasicSpecification end ## + # Return true if this spec can require +file+. + + def contains_requirable_file? file + root = full_gem_path + suffixes = Gem.suffixes + + require_paths.any? do |lib| + base = "#{root}/#{lib}/#{file}" + suffixes.any? { |suf| File.file? "#{base}#{suf}" } + end + end + + ## # The date this gem was created. Lazily defaults to the current UTC date. # # There is no need to set this in your gem specification. @@ -1671,14 +1645,35 @@ class Gem::Specification < Gem::BasicSpecification spec end - # :nodoc: - def find_full_gem_path - super || File.expand_path(File.join(gems_dir, original_name)) + ## + # The full path to the gem (install path + full name). + + def full_gem_path + # TODO: This is a heavily used method by gems, so we'll need + # to aleast just alias it to #gem_dir rather than remove it. + + # TODO: also, shouldn't it default to full_name if it hasn't been written? + return @full_gem_path if defined?(@full_gem_path) && @full_gem_path + + @full_gem_path = File.expand_path File.join(gems_dir, full_name) + @full_gem_path.untaint + + return @full_gem_path if File.directory? @full_gem_path + + @full_gem_path = File.expand_path File.join(gems_dir, original_name) end - private :find_full_gem_path + + ## + # Returns the full name (name-version) of this Gem. Platform information + # is included (name-version-platform) if it is specified and not the + # default Ruby platform. def full_name - @full_name ||= super + @full_name ||= if platform == Gem::Platform::RUBY or platform.nil? then + "#{@name}-#{@version}".untaint + else + "#{@name}-#{@version}-#{platform}".untaint + end end ## @@ -1690,6 +1685,15 @@ class Gem::Specification < Gem::BasicSpecification end ## + # Returns the full path to the gems directory containing this spec's + # gem directory. eg: /usr/local/lib/ruby/1.8/gems + + def gems_dir + # TODO: this logic seems terribly broken, but tests fail if just base_dir + @gems_dir ||= File.join(loaded_from && base_dir || Gem.dir, "gems") + end + + ## # Deprecated and ignored, defaults to true. # # Formerly used to indicate this gem was RDoc-capable. @@ -1721,7 +1725,9 @@ class Gem::Specification < Gem::BasicSpecification # :startdoc: def hash # :nodoc: - name.hash ^ version.hash + @@attributes.inject(0) { |hash_code, (name, _)| + hash_code ^ self.send(name).hash + } end def init_with coder # :nodoc: @@ -1736,7 +1742,7 @@ class Gem::Specification < Gem::BasicSpecification def initialize name = nil, version = nil @loaded = false @activated = false - self.loaded_from = nil + @loaded_from = nil @original_platform = nil @@nil_attributes.each do |key| @@ -1745,7 +1751,11 @@ class Gem::Specification < Gem::BasicSpecification @@non_nil_attributes.each do |key| default = default_value(key) - value = Dupable[key] ? default.dup : default + value = case default + when Time, Numeric, Symbol, true, false, nil then default + else default.dup + end + instance_variable_set "@#{key}", value end @@ -1840,14 +1850,22 @@ class Gem::Specification < Gem::BasicSpecification @licenses ||= [] end - def loaded_from= path # :nodoc: - super + ## + # Set the location a Specification was loaded from. +obj+ is converted + # to a String. + + def loaded_from= path + @loaded_from = path.to_s + # reset everything @loaded_from depends upon + @base_dir = nil @bin_dir = nil @cache_dir = nil @cache_file = nil @doc_dir = nil + @full_gem_path = nil @gem_dir = nil + @gems_dir = nil @ri_dir = nil @spec_dir = nil @spec_file = nil @@ -2032,10 +2050,6 @@ 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. @@ -2097,17 +2111,11 @@ class Gem::Specification < Gem::BasicSpecification # Returns an object you can use to sort specifications in #sort_by. def sort_obj + # TODO: this is horrible. Deprecate it. [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1] end ## - # Used by Gem::DependencyResolver to order Gem::Specification objects - - def source # :nodoc: - self - end - - ## # Returns the full path to the directory containing this spec's # gemspec file. eg: /usr/local/lib/ruby/gems/1.8/specifications @@ -2186,7 +2194,6 @@ class Gem::Specification < Gem::BasicSpecification mark_version result = [] result << "# -*- encoding: utf-8 -*-" - result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{require_paths.join("\0")}" result << nil result << "Gem::Specification.new do |s|" @@ -2274,13 +2281,6 @@ class Gem::Specification < Gem::BasicSpecification "#<Gem::Specification name=#{@name} version=#{@version}>" end - ## - # Returns self - - def to_spec - self - end - def to_yaml(opts = {}) # :nodoc: if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then # Because the user can switch the YAML engine behind our @@ -2581,6 +2581,11 @@ class Gem::Specification < Gem::BasicSpecification end end + def default_gem? + loaded_from && + File.dirname(loaded_from) == self.class.default_specifications_dir + end + extend Gem::Deprecate # TODO: diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index d6c1a36ad1..7d087afade 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -58,7 +58,7 @@ module Gem end ## - # Allows setting path to Ruby. This method is available when requiring + # Allows setting path to ruby. This method is available when requiring # 'rubygems/test_case' def self.ruby= ruby @@ -84,23 +84,6 @@ end class Gem::TestCase < MiniTest::Unit::TestCase - def assert_activate expected, *specs - specs.each do |spec| - case spec - when String then - Gem::Specification.find_by_name(spec).activate - when Gem::Specification then - spec.activate - else - flunk spec.inspect - end - end - - loaded = Gem.loaded_specs.values.map(&:full_name) - - assert_equal expected.sort, loaded.sort if expected - end - # TODO: move to minitest def assert_path_exists path, msg = nil msg = message(msg) { "Expected path '#{path}' to exist" } @@ -223,11 +206,10 @@ class Gem::TestCase < MiniTest::Unit::TestCase @gemhome = File.join @tempdir, 'gemhome' @userhome = File.join @tempdir, 'userhome' - ENV["GEM_SPEC_CACHE"] = File.join @tempdir, 'spec_cache' @orig_ruby = if ENV['RUBY'] then - ruby = Gem.ruby - Gem.ruby = ENV['RUBY'] + ruby = Gem.instance_variable_get :@ruby + Gem.instance_variable_set :@ruby, ENV['RUBY'] ruby end @@ -245,9 +227,6 @@ class Gem::TestCase < MiniTest::Unit::TestCase FileUtils.mkdir_p @gemhome FileUtils.mkdir_p @userhome - @orig_gem_private_key_passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] - ENV['GEM_PRIVATE_KEY_PASSPHRASE'] = PRIVATE_KEY_PASSPHRASE - @default_dir = File.join @tempdir, 'default' @default_spec_dir = File.join @default_dir, "specifications", "default" Gem.instance_variable_set :@default_dir, @default_dir @@ -293,6 +272,39 @@ class Gem::TestCase < MiniTest::Unit::TestCase end @marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" + + # TODO: move to installer test cases + Gem.post_build_hooks.clear + Gem.post_install_hooks.clear + Gem.done_installing_hooks.clear + Gem.post_reset_hooks.clear + Gem.post_uninstall_hooks.clear + Gem.pre_install_hooks.clear + Gem.pre_reset_hooks.clear + Gem.pre_uninstall_hooks.clear + + # TODO: move to installer test cases + Gem.post_build do |installer| + @post_build_hook_arg = installer + true + end + + Gem.post_install do |installer| + @post_install_hook_arg = installer + end + + Gem.post_uninstall do |uninstaller| + @post_uninstall_hook_arg = uninstaller + end + + Gem.pre_install do |installer| + @pre_install_hook_arg = installer + true + end + + Gem.pre_uninstall do |uninstaller| + @pre_uninstall_hook_arg = uninstaller + end end ## @@ -316,7 +328,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase ENV['GEM_HOME'] = @orig_gem_home ENV['GEM_PATH'] = @orig_gem_path - Gem.ruby = @orig_ruby if @orig_ruby + _ = @orig_ruby + Gem.instance_variable_set :@ruby, @orig_ruby if @orig_ruby if @orig_ENV_HOME then ENV['HOME'] = @orig_ENV_HOME @@ -325,47 +338,6 @@ class Gem::TestCase < MiniTest::Unit::TestCase end Gem.instance_variable_set :@default_dir, nil - - ENV['GEM_PRIVATE_KEY_PASSPHRASE'] = @orig_gem_private_key_passphrase - - Gem::Specification._clear_load_cache - end - - def common_installer_setup - common_installer_teardown - - Gem.post_build do |installer| - @post_build_hook_arg = installer - true - end - - Gem.post_install do |installer| - @post_install_hook_arg = installer - end - - Gem.post_uninstall do |uninstaller| - @post_uninstall_hook_arg = uninstaller - end - - Gem.pre_install do |installer| - @pre_install_hook_arg = installer - true - end - - Gem.pre_uninstall do |uninstaller| - @pre_uninstall_hook_arg = uninstaller - end - end - - def common_installer_teardown - Gem.post_build_hooks.clear - Gem.post_install_hooks.clear - Gem.done_installing_hooks.clear - Gem.post_reset_hooks.clear - Gem.post_uninstall_hooks.clear - Gem.pre_install_hooks.clear - Gem.pre_reset_hooks.clear - Gem.pre_uninstall_hooks.clear end ## @@ -594,21 +566,6 @@ class Gem::TestCase < MiniTest::Unit::TestCase end end - def loaded_spec_names - Gem.loaded_specs.values.map(&:full_name).sort - end - - def unresolved_names - Gem::Specification.unresolved_deps.values.map(&:to_s).sort - end - - def save_loaded_features - old_loaded_features = $LOADED_FEATURES.dup - yield - ensure - $LOADED_FEATURES.replace old_loaded_features - end - ## # Create a new spec (or gem if passed an array of files) and set it # up properly. Use this instead of util_spec and util_gem. @@ -785,7 +742,7 @@ Also, a list: @a_evil9 = quick_gem('a_evil', '9', &init) @b2 = quick_gem('b', '2', &init) @c1_2 = quick_gem('c', '1.2', &init) - @x = quick_gem('x', '1', &init) + @x = quick_gem('x', '1', &init) @dep_x = quick_gem('dep_x', '1') do |s| s.files = %w[lib/code.rb] s.require_paths = %w[lib] @@ -805,15 +762,14 @@ Also, a list: util_build_gem @a2_pre end - write_file File.join(*%W[gems #{@a1.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@a2.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@a_evil9.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@b2.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@x.original_name} lib code.rb]) - write_file File.join(*%W[gems #{@dep_x.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@a1.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@a2.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@b2.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@x.original_name} lib code.rb]) + write_file File.join(*%W[gems #{@dep_x.original_name} lib code.rb]) [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1, @x, @dep_x].each do |spec| util_build_gem spec @@ -1016,7 +972,7 @@ Also, a list: end ## - # Finds the path to the Ruby executable + # Finds the path to the ruby executable def self.rubybin ruby = ENV["RUBY"] @@ -1056,24 +1012,6 @@ Also, a list: end ## - # Constructs a Gem::DependencyResolver::DependencyRequest from a - # Gem::Dependency +dep+, a +from_name+ and +from_version+ requesting the - # dependency and a +parent+ DependencyRequest - - def dependency_request dep, from_name, from_version, parent = nil - remote = Gem::Source.new @uri - - parent ||= Gem::DependencyResolver::DependencyRequest.new \ - dep, nil - - spec = Gem::DependencyResolver::IndexSpecification.new \ - nil, from_name, from_version, remote, Gem::Platform::RUBY - activation = Gem::DependencyResolver::ActivationRequest.new spec, parent - - Gem::DependencyResolver::DependencyRequest.new dep, activation - end - - ## # Constructs a new Gem::Requirement. def req *requirements @@ -1097,11 +1035,7 @@ Also, a list: class StaticSet def initialize(specs) - @specs = specs - end - - def add spec - @specs << spec + @specs = specs.sort_by { |s| s.full_name } end def find_spec(dep) @@ -1114,15 +1048,6 @@ Also, a list: @specs.find_all { |s| dep.matches_spec? s } end - def load_spec name, ver, platform, source - dep = Gem::Dependency.new name, ver - spec = find_spec dep - - Gem::Specification.new spec.name, spec.version do |s| - s.platform = spec.platform - end - end - def prefetch(reqs) end end @@ -1155,18 +1080,18 @@ Also, a list: end ## - # Loads an RSA private key named +key_name+ with +passphrase+ in <tt>test/rubygems/</tt> + # Loads an RSA private key named +key_name+ in <tt>test/rubygems/</tt> - def self.load_key key_name, passphrase = nil + def self.load_key key_name key_file = key_path key_name key = File.read key_file - OpenSSL::PKey::RSA.new key, passphrase + OpenSSL::PKey::RSA.new key end ## - # Returns the path to the key named +key_name+ from <tt>test/rubygems</tt> + # Returns the path tot he key named +key_name+ from <tt>test/rubygems</tt> def self.key_path key_name File.expand_path "../../../test/rubygems/#{key_name}_key.pem", __FILE__ @@ -1175,24 +1100,17 @@ Also, a list: # :stopdoc: # only available in RubyGems tests - PRIVATE_KEY_PASSPHRASE = 'Foo bar' - begin - PRIVATE_KEY = load_key 'private' - PRIVATE_KEY_PATH = key_path 'private' + PRIVATE_KEY = load_key 'private' + PRIVATE_KEY_PATH = key_path 'private' + PUBLIC_KEY = PRIVATE_KEY.public_key - # ENCRYPTED_PRIVATE_KEY is PRIVATE_KEY encrypted with PRIVATE_KEY_PASSPHRASE - ENCRYPTED_PRIVATE_KEY = load_key 'encrypted_private', PRIVATE_KEY_PASSPHRASE - ENCRYPTED_PRIVATE_KEY_PATH = key_path 'encrypted_private' - - PUBLIC_KEY = PRIVATE_KEY.public_key - - PUBLIC_CERT = load_cert 'public' - PUBLIC_CERT_PATH = cert_path 'public' + PUBLIC_CERT = load_cert 'public' + PUBLIC_CERT_PATH = cert_path 'public' rescue Errno::ENOENT PRIVATE_KEY = nil PUBLIC_KEY = nil PUBLIC_CERT = nil - end if defined?(OpenSSL::SSL) + end end diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index 143ab6df26..d672b9dec1 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -43,15 +43,14 @@ class Gem::Uninstaller def initialize(gem, options = {}) # TODO document the valid options - @gem = gem - @version = options[:version] || Gem::Requirement.default - @gem_home = File.expand_path(options[:install_dir] || Gem.dir) - @force_executables = options[:executables] - @force_all = options[:all] - @force_ignore = options[:ignore] - @bin_dir = options[:bin_dir] - @format_executable = options[:format_executable] - @abort_on_dependent = options[:abort_on_dependent] + @gem = gem + @version = options[:version] || Gem::Requirement.default + @gem_home = File.expand_path(options[:install_dir] || Gem.dir) + @force_executables = options[:executables] + @force_all = options[:all] + @force_ignore = options[:ignore] + @bin_dir = options[:bin_dir] + @format_executable = options[:format_executable] # Indicate if development dependencies should be checked when # uninstalling. (default: false) @@ -144,7 +143,7 @@ class Gem::Uninstaller @spec = spec unless dependencies_ok? spec - if abort_on_dependent? || !ask_if_ok(spec) + unless ask_if_ok(spec) raise Gem::DependencyRemovalException, "Uninstallation aborted due to dependent gem(s)" end @@ -291,10 +290,6 @@ class Gem::Uninstaller deplist.ok_to_remove?(spec.full_name, @check_dev) end - def abort_on_dependent? - @abort_on_dependent - end - def ask_if_ok(spec) msg = [''] msg << 'You have requested to uninstall the gem:' diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 2e546462d4..bbf04f5403 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -147,16 +147,13 @@ class Gem::Version # FIX: These are only used once, in .correct?. Do they deserve to be # constants? - VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc: + VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*' # :nodoc: ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc: ## # A string representation of this Version. - def version - @version.dup - end - + attr_reader :version alias to_s version ## @@ -186,12 +183,6 @@ class Gem::Version end end - @@all = {} - - def self.new version - @@all[version] ||= super - end - ## # Constructs a Version from the +version+ string. A version string is a # series of digits or ASCII letters separated by dots. @@ -200,8 +191,7 @@ class Gem::Version raise ArgumentError, "Malformed version number string #{version}" unless self.class.correct?(version) - @version = version.to_s.strip.gsub("-",".pre.") - @segments = nil + @version = version.to_s.dup.strip end ## diff --git a/lib/rubygems/version_option.rb b/lib/rubygems/version_option.rb index a0755d5020..a3de4dc9e7 100644 --- a/lib/rubygems/version_option.rb +++ b/lib/rubygems/version_option.rb @@ -42,7 +42,6 @@ module Gem::VersionOption add_option("--[no-]prerelease", "Allow prerelease versions of a gem", *wrap) do |value, options| options[:prerelease] = value - options[:explicit_prerelease] = true end end @@ -51,19 +50,14 @@ module Gem::VersionOption def add_version_option(task = command, *wrap) OptionParser.accept Gem::Requirement do |value| - Gem::Requirement.new(*value.split(/\s*,\s*/)) + Gem::Requirement.new value end add_option('-v', '--version VERSION', Gem::Requirement, "Specify version of gem to #{task}", *wrap) do |value, options| options[:version] = value - - explicit_prerelease_set = !options[:explicit_prerelease].nil? - options[:explicit_prerelease] = false unless explicit_prerelease_set - - options[:prerelease] = value.prerelease? unless - options[:explicit_prerelease] + options[:prerelease] = true if value.prerelease? end end diff --git a/test/rubygems/ca_cert.pem b/test/rubygems/ca_cert.pem index 5207531bc2..5acdcf8f32 100644 --- a/test/rubygems/ca_cert.pem +++ b/test/rubygems/ca_cert.pem @@ -43,26 +43,3 @@ ySjIblqVQkPuzebv3Ror6ZnVDukn96Mg7kP4u6zgxOeqlJGRe1M949SS9Vudjl8X SF4aZUUB9pQGhsqQJVqaz2OlhGOp9D0q54xko/rekjAIcuDjl1mdX4F2WRrzpUmZ uY/bPeOBYiVsOYVe -----END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIJANz6ehBcVuuiMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTMwNTAxMTQ0NTQxWhcNMjMwMzEwMTQ0NTQxWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAzlpZwhEYoALOEKU4lmMw5l3YI/gadzDOoELtdcidvVvovKK8IIOTDwbA -3XcjwV0UPGEPOK4Uk1aD0EKkOQVg8ivSre2a3FFGffs2kXck+doJMzAA+pf8tvFk -QsETVOurOp74GN+er2xbbRSDVxQKq6d+QTe1E60btyXQS5M1Nt5SvLn8dazZJgvv -3yzJQ1IOQl+xeEO0WVVhPIx5Mx3VtjjcDyl8aewPkYkzia6UOrAyQZnl5sIzWGOb -kYKCNeKjTPepzlbMx0dN6jBupPYGNB+4FYY9GezInjGbRP5np5382wd3EWwsVzic -Nau8kXHTL2r7GzNvoy0p//iPCqx9FQIDAQABo4GnMIGkMB0GA1UdDgQWBBS7B027 -H/ZIkW3ngm1SrR0X/aTCwDB1BgNVHSMEbjBsgBS7B027H/ZIkW3ngm1SrR0X/aTC -wKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV -BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJANz6ehBcVuuiMAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAC0glUrUiylTfuOWlwkQvi74oiYC5CzW -Jfusg6o/Gg1XEuJhaHiYMsK/do16gSc6Za3934rHQbYu3mesyFkCWF9kD4J6/hEO -OQL8xmmgN7wS6GXy6oIODpny0MgnFrV4gd1aEx69NIfL/wXaM8Gw2sj1TnuGLs8+ -HFmWLRRH3WSR7ZLnqYzPVJwhHu8vtZBL9HZk1J6xyq00Nwi2Cz5WdiHamgaza3TS -OgBdWwDeSClwhrTJni4d30dbq+eNMByIZ7QNGBQivpFzDxeNV/2UBrTU0CilKG5Q -j7ZwknfKeA4xUTd8TMK3vKab5JJCfjbXOTHZQsYUcEEGSjOMS8/YVQs= ------END CERTIFICATE----- diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 45db153c22..fda83767f2 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -13,21 +13,128 @@ end class TestGem < Gem::TestCase - PLUGINS_LOADED = [] - def setup super - PLUGINS_LOADED.clear - - common_installer_setup - ENV.delete 'RUBYGEMS_GEMDEPS' @additional = %w[a b].map { |d| File.join @tempdir, d } util_remove_interrupt_command end + def assert_activate expected, *specs + specs.each do |spec| + case spec + when String then + Gem::Specification.find_by_name(spec).activate + when Gem::Specification then + spec.activate + else + flunk spec.inspect + end + end + + loaded = Gem.loaded_specs.values.map(&:full_name) + + assert_equal expected.sort, loaded.sort if expected + end + + def test_self_activate + foo = util_spec 'foo', '1' + + assert_activate %w[foo-1], foo + end + + def loaded_spec_names + Gem.loaded_specs.values.map(&:full_name).sort + end + + def unresolved_names + Gem::Specification.unresolved_deps.values.map(&:to_s).sort + end + + # TODO: move these to specification + def test_self_activate_via_require + a1 = new_spec "a", "1", "b" => "= 1" + b1 = new_spec "b", "1", nil, "lib/b/c.rb" + b2 = new_spec "b", "2", nil, "lib/b/c.rb" + + install_specs a1, b1, b2 + + a1.activate + save_loaded_features do + require "b/c" + end + + assert_equal %w(a-1 b-1), loaded_spec_names + end + + # TODO: move these to specification + def test_self_activate_deep_unambiguous + a1 = new_spec "a", "1", "b" => "= 1" + b1 = new_spec "b", "1", "c" => "= 1" + b2 = new_spec "b", "2", "c" => "= 2" + c1 = new_spec "c", "1" + c2 = new_spec "c", "2" + + install_specs a1, b1, b2, c1, c2 + + a1.activate + assert_equal %w(a-1 b-1 c-1), loaded_spec_names + end + + def save_loaded_features + old_loaded_features = $LOADED_FEATURES.dup + yield + ensure + $LOADED_FEATURES.replace old_loaded_features + end + + # TODO: move these to specification + def test_self_activate_ambiguous_direct + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0" + b1 = new_spec("b", "1", { "c" => ">= 1" }, "lib/d.rb") + b2 = new_spec("b", "2", { "c" => ">= 2" }, "lib/d.rb") + c1 = new_spec "c", "1" + c2 = new_spec "c", "2" + + Gem::Specification.reset + install_specs a1, b1, b2, c1, c2 + + a1.activate + assert_equal %w(a-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + + require "d" + + assert_equal %w(a-1 b-2 c-2), loaded_spec_names + assert_equal [], unresolved_names + end + end + + # TODO: move these to specification + def test_self_activate_ambiguous_indirect + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0" + b1 = new_spec "b", "1", "c" => ">= 1" + b2 = new_spec "b", "2", "c" => ">= 2" + c1 = new_spec "c", "1", nil, "lib/d.rb" + c2 = new_spec "c", "2", nil, "lib/d.rb" + + install_specs a1, b1, b2, c1, c2 + + a1.activate + assert_equal %w(a-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + + require "d" + + assert_equal %w(a-1 b-2 c-2), loaded_spec_names + assert_equal [], unresolved_names + end + end + def test_self_finish_resolve save_loaded_features do a1 = new_spec "a", "1", "b" => "> 0" @@ -50,6 +157,36 @@ class TestGem < Gem::TestCase end end + def test_self_activate_via_require_wtf + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0", "d" => "> 0" # this + b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/b.rb" + b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/b.rb" # this + c1 = new_spec "c", "1" + c2 = new_spec "c", "2" # this + d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb" + d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" # this + + install_specs a1, b1, b2, c1, c2, d1, d2 + + a1.activate + + assert_equal %w(a-1), loaded_spec_names + assert_equal ["b (> 0)", "d (> 0)"], unresolved_names + + require "b" + + e = assert_raises Gem::LoadError do + require "d" + end + + assert_equal "unable to find a version of 'd' to activate", e.message + + assert_equal %w(a-1 b-2 c-2), loaded_spec_names + assert_equal ["d (> 0)"], unresolved_names + end + end + def test_self_finish_resolve_wtf save_loaded_features do a1 = new_spec "a", "1", "b" => "> 0", "d" => "> 0" # this @@ -74,6 +211,94 @@ class TestGem < Gem::TestCase end end + # TODO: move these to specification + def test_self_activate_ambiguous_unrelated + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0" + b1 = new_spec "b", "1", "c" => ">= 1" + b2 = new_spec "b", "2", "c" => ">= 2" + c1 = new_spec "c", "1" + c2 = new_spec "c", "2" + d1 = new_spec "d", "1", nil, "lib/d.rb" + + install_specs a1, b1, b2, c1, c2, d1 + + a1.activate + assert_equal %w(a-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + + require "d" + + assert_equal %w(a-1 d-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + end + end + + # TODO: move these to specification + def test_self_activate_ambiguous_indirect_conflict + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0" + a2 = new_spec "a", "2", "b" => "> 0" + b1 = new_spec "b", "1", "c" => ">= 1" + b2 = new_spec "b", "2", "c" => ">= 2" + c1 = new_spec "c", "1", nil, "lib/d.rb" + c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2 + + install_specs a1, a2, b1, b2, c1, c2 + + a2.activate + assert_equal %w(a-2), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + + require "d" + + assert_equal %w(a-2 b-1 c-1), loaded_spec_names + assert_equal [], unresolved_names + end + end + + # TODO: move these to specification + def test_require_already_activated + save_loaded_features do + a1 = new_spec "a", "1", nil, "lib/d.rb" + + install_specs a1 # , a2, b1, b2, c1, c2 + + a1.activate + assert_equal %w(a-1), loaded_spec_names + assert_equal [], unresolved_names + + assert require "d" + + assert_equal %w(a-1), loaded_spec_names + assert_equal [], unresolved_names + end + end + + # TODO: move these to specification + def test_require_already_activated_indirect_conflict + save_loaded_features do + a1 = new_spec "a", "1", "b" => "> 0" + a2 = new_spec "a", "2", "b" => "> 0" + b1 = new_spec "b", "1", "c" => ">= 1" + b2 = new_spec "b", "2", "c" => ">= 2" + c1 = new_spec "c", "1", nil, "lib/d.rb" + c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2 + + install_specs a1, a2, b1, b2, c1, c2 + + a1.activate + c1.activate + assert_equal %w(a-1 c-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + + assert require "d" + + assert_equal %w(a-1 c-1), loaded_spec_names + assert_equal ["b (> 0)"], unresolved_names + end + end + def test_require_missing save_loaded_features do assert_raises ::LoadError do @@ -96,6 +321,221 @@ class TestGem < Gem::TestCase end end + # TODO: move these to specification + def test_self_activate_loaded + foo = util_spec 'foo', '1' + + assert foo.activate + refute foo.activate + end + + ## + # [A] depends on + # [B] >= 1.0 (satisfied by 2.0) + # [C] depends on nothing + + def test_self_activate_unrelated + a = util_spec 'a', '1.0', 'b' => '>= 1.0' + util_spec 'b', '1.0' + c = util_spec 'c', '1.0' + + assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" + end + + ## + # [A] depends on + # [B] >= 1.0 (satisfied by 2.0) + # [C] = 1.0 depends on + # [B] ~> 1.0 + # + # and should resolve using b-1.0 + # TODO: move these to specification + + def test_self_activate_over + a = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '= 1.0' + util_spec 'b', '1.0' + util_spec 'b', '1.1' + util_spec 'b', '2.0' + util_spec 'c', '1.0', 'b' => '~> 1.0' + + a.activate + + assert_equal %w[a-1.0 c-1.0], loaded_spec_names + assert_equal ["b (>= 1.0, ~> 1.0)"], unresolved_names + end + + ## + # [A] depends on + # [B] ~> 1.0 (satisfied by 1.1) + # [C] = 1.0 depends on + # [B] = 1.0 + # + # and should resolve using b-1.0 + # + # TODO: this is not under, but over... under would require depth + # first resolve through a dependency that is later pruned. + + def test_self_activate_under + a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0' + util_spec 'b', '1.0' + util_spec 'b', '1.1' + c, _ = util_spec 'c', '1.0', 'b' => '= 1.0' + + assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" + end + + ## + # [A1] depends on + # [B] > 0 (satisfied by 2.0) + # [B1] depends on + # [C] > 0 (satisfied by 1.0) + # [B2] depends on nothing! + # [C1] depends on nothing + + def test_self_activate_dropped + a1, = util_spec 'a', '1', 'b' => nil + util_spec 'b', '1', 'c' => nil + util_spec 'b', '2' + util_spec 'c', '1' + + assert_activate %w[b-2 a-1], a1, "b" + end + + ## + # [A] depends on + # [B] >= 1.0 (satisfied by 1.1) depends on + # [Z] + # [C] >= 1.0 depends on + # [B] = 1.0 + # + # and should backtrack to resolve using b-1.0, pruning Z from the + # resolve. + + def test_self_activate_raggi_the_edgecase_generator + a, _ = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '>= 1.0' + util_spec 'b', '1.0' + util_spec 'b', '1.1', 'z' => '>= 1.0' + c, _ = util_spec 'c', '1.0', 'b' => '= 1.0' + + assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" + end + + def test_self_activate_conflict + util_spec 'b', '1.0' + util_spec 'b', '2.0' + + gem "b", "= 1.0" + + assert_raises Gem::LoadError do + gem "b", "= 2.0" + end + end + + ## + # [A] depends on + # [C] = 1.0 depends on + # [B] = 2.0 + # [B] ~> 1.0 (satisfied by 1.0) + + def test_self_activate_checks_dependencies + a, _ = util_spec 'a', '1.0' + a.add_dependency 'c', '= 1.0' + a.add_dependency 'b', '~> 1.0' + + util_spec 'b', '1.0' + util_spec 'b', '2.0' + c, _ = util_spec 'c', '1.0', 'b' => '= 2.0' + + e = assert_raises Gem::LoadError do + assert_activate nil, a, c, "b" + end + + expected = "can't satisfy 'b (~> 1.0)', already activated 'b-2.0'" + assert_equal expected, e.message + end + + ## + # [A] depends on + # [B] ~> 1.0 (satisfied by 1.0) + # [C] = 1.0 depends on + # [B] = 2.0 + + def test_self_activate_divergent + a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0' + util_spec 'b', '1.0' + util_spec 'b', '2.0' + c, _ = util_spec 'c', '1.0', 'b' => '= 2.0' + + e = assert_raises Gem::LoadError do + assert_activate nil, a, c, "b" + end + + assert_match(/Unable to activate c-1.0,/, e.message) + assert_match(/because b-1.0 conflicts with b .= 2.0/, e.message) + end + + ## + # DOC + + def test_self_activate_platform_alternate + @x1_m = util_spec 'x', '1' do |s| + s.platform = Gem::Platform.new %w[cpu my_platform 1] + end + + @x1_o = util_spec 'x', '1' do |s| + s.platform = Gem::Platform.new %w[cpu other_platform 1] + end + + @w1 = util_spec 'w', '1', 'x' => nil + + util_set_arch 'cpu-my_platform1' + + assert_activate %w[x-1-cpu-my_platform-1 w-1], @w1, @x1_m + end + + ## + # DOC + + def test_self_activate_platform_bump + @y1 = util_spec 'y', '1' + + @y1_1_p = util_spec 'y', '1.1' do |s| + s.platform = Gem::Platform.new %w[cpu my_platform 1] + end + + @z1 = util_spec 'z', '1', 'y' => nil + + assert_activate %w[y-1 z-1], @z1, @y1 + end + + ## + # [C] depends on + # [A] = 1.a + # [B] = 1.0 depends on + # [A] >= 0 (satisfied by 1.a) + + def test_self_activate_prerelease + @c1_pre = util_spec 'c', '1.a', "a" => "1.a", "b" => "1" + @a1_pre = util_spec 'a', '1.a' + @b1 = util_spec 'b', '1' do |s| + s.add_dependency 'a' + s.add_development_dependency 'aa' + end + + assert_activate %w[a-1.a b-1 c-1.a], @c1_pre, @a1_pre, @b1 + end + + ## + # DOC + + def test_self_activate_old_required + e1, = util_spec 'e', '1', 'd' => '= 1' + @d1 = util_spec 'd', '1' + @d2 = util_spec 'd', '2' + + assert_activate %w[d-1 e-1], e1, "d" + end + def test_self_bin_path_no_exec_name e = assert_raises ArgumentError do Gem.bin_path 'a' @@ -350,7 +790,9 @@ class TestGem < Gem::TestCase spec } - Gem.refresh + # HACK should be Gem.refresh + Gem.searcher = nil + Gem::Specification.reset expected = [ File.expand_path('test/rubygems/sff/discover.rb', @@project_dir), @@ -364,37 +806,6 @@ class TestGem < Gem::TestCase assert_equal cwd, $LOAD_PATH.shift end - def test_self_find_latest_files - cwd = File.expand_path("test/rubygems", @@project_dir) - $LOAD_PATH.unshift cwd - - discover_path = File.join 'lib', 'sff', 'discover.rb' - - _, foo2 = %w(1 2).map { |version| - spec = quick_gem 'sff', version do |s| - s.files << discover_path - end - - write_file(File.join 'gems', spec.full_name, discover_path) do |fp| - fp.puts "# #{spec.full_name}" - end - - spec - } - - Gem.refresh - - expected = [ - File.expand_path('test/rubygems/sff/discover.rb', @@project_dir), - File.join(foo2.full_gem_path, discover_path), - ] - - assert_equal expected, Gem.find_latest_files('sff/discover') - assert_equal expected, Gem.find_latest_files('sff/**.rb'), '[ruby-core:31730]' - ensure - assert_equal cwd, $LOAD_PATH.shift - end - def test_self_latest_spec_for a1 = quick_spec 'a', 1 a2 = quick_spec 'a', 2 @@ -917,20 +1328,14 @@ class TestGem < Gem::TestCase Dir.chdir @tempdir do FileUtils.mkdir_p 'lib' File.open plugin_path, "w" do |fp| - fp.puts "class TestGem; PLUGINS_LOADED << 'plugin'; end" - end - - foo1 = quick_spec 'foo', '1' do |s| - s.files << plugin_path + fp.puts "class TestGem; TEST_SPEC_PLUGIN_LOAD = :loaded; end" end - install_gem foo1 - - foo2 = quick_spec 'foo', '2' do |s| + foo = quick_spec 'foo', '1' do |s| s.files << plugin_path end - install_gem foo2 + install_gem foo end Gem.searcher = nil @@ -940,7 +1345,7 @@ class TestGem < Gem::TestCase Gem.load_plugins - assert_equal %w[plugin], PLUGINS_LOADED + assert_equal :loaded, TEST_SPEC_PLUGIN_LOAD end def test_load_env_plugins @@ -1153,61 +1558,6 @@ class TestGem < Gem::TestCase assert_equal '["a-1", "b-1", "c-1"]', out.strip end - def test_register_default_spec - Gem.clear_default_specs - - old_style = Gem::Specification.new do |spec| - spec.files = ["foo.rb", "bar.rb"] - end - - Gem.register_default_spec old_style - - assert_equal old_style, Gem.find_unresolved_default_spec("foo.rb") - assert_equal old_style, Gem.find_unresolved_default_spec("bar.rb") - assert_equal nil, Gem.find_unresolved_default_spec("baz.rb") - - Gem.clear_default_specs - - new_style = Gem::Specification.new do |spec| - spec.files = ["lib/foo.rb", "ext/bar.rb", "bin/exec", "README"] - spec.require_paths = ["lib", "ext"] - end - - Gem.register_default_spec new_style - - assert_equal new_style, Gem.find_unresolved_default_spec("foo.rb") - assert_equal new_style, Gem.find_unresolved_default_spec("bar.rb") - assert_equal nil, Gem.find_unresolved_default_spec("exec") - assert_equal nil, Gem.find_unresolved_default_spec("README") - end - - def test_default_gems_use_full_paths - begin - if defined?(RUBY_ENGINE) then - engine = RUBY_ENGINE - Object.send :remove_const, :RUBY_ENGINE - end - Object.const_set :RUBY_ENGINE, 'ruby' - - refute Gem.default_gems_use_full_paths? - ensure - Object.send :remove_const, :RUBY_ENGINE - Object.const_set :RUBY_ENGINE, engine if engine - end - - begin - if defined?(RUBY_ENGINE) then - engine = RUBY_ENGINE - Object.send :remove_const, :RUBY_ENGINE - end - Object.const_set :RUBY_ENGINE, 'jruby' - assert Gem.default_gems_use_full_paths? - ensure - Object.send :remove_const, :RUBY_ENGINE - Object.const_set :RUBY_ENGINE, engine if engine - end - end - def with_plugin(path) test_plugin_path = File.expand_path("test/rubygems/plugin/#{path}", @@project_dir) @@ -1284,3 +1634,4 @@ class TestGem < Gem::TestCase File.join Gem.dir, "cache" end end + diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb index f6433c5cc3..e201d73275 100644 --- a/test/rubygems/test_gem_command_manager.rb +++ b/test/rubygems/test_gem_command_manager.rb @@ -58,7 +58,7 @@ class TestGemCommandManager < Gem::TestCase use_ui @ui do assert_raises Gem::MockGemUi::TermError do - @command_manager.run %w[interrupt] + @command_manager.run 'interrupt' end assert_equal '', ui.output assert_equal "ERROR: Interrupted\n", ui.error @@ -75,7 +75,7 @@ class TestGemCommandManager < Gem::TestCase @command_manager.register_command :crash use_ui @ui do assert_raises Gem::MockGemUi::TermError do - @command_manager.run %w[crash] + @command_manager.run 'crash' end assert_equal '', ui.output err = ui.error.split("\n").first @@ -89,7 +89,7 @@ class TestGemCommandManager < Gem::TestCase def test_process_args_bad_arg use_ui @ui do assert_raises Gem::MockGemUi::TermError do - @command_manager.process_args %w[--bad-arg] + @command_manager.process_args("--bad-arg") end end @@ -107,7 +107,7 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[install] + @command_manager.process_args("install") assert_equal %w[ri], check_options[:document].sort assert_equal false, check_options[:force] assert_equal :both, check_options[:domain] @@ -118,10 +118,8 @@ class TestGemCommandManager < Gem::TestCase #check settings check_options = nil - @command_manager.process_args %w[ - install --force --local --rdoc --install-dir . - --version 3.0 --no-wrapper --bindir . - ] + @command_manager.process_args( + "install --force --local --rdoc --install-dir . --version 3.0 --no-wrapper --bindir . ") assert_equal %w[rdoc ri], check_options[:document].sort assert_equal true, check_options[:force] assert_equal :local, check_options[:domain] @@ -132,17 +130,17 @@ class TestGemCommandManager < Gem::TestCase #check remote domain check_options = nil - @command_manager.process_args %w[install --remote] + @command_manager.process_args("install --remote") assert_equal :remote, check_options[:domain] #check both domain check_options = nil - @command_manager.process_args %w[install --both] + @command_manager.process_args("install --both") assert_equal :both, check_options[:domain] #check both domain check_options = nil - @command_manager.process_args %w[install --both] + @command_manager.process_args("install --both") assert_equal :both, check_options[:domain] end end @@ -157,12 +155,12 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[uninstall] + @command_manager.process_args("uninstall") assert_equal Gem::Requirement.default, check_options[:version] #check settings check_options = nil - @command_manager.process_args %w[uninstall foobar --version 3.0] + @command_manager.process_args("uninstall foobar --version 3.0") assert_equal "foobar", check_options[:args].first assert_equal Gem::Requirement.new('3.0'), check_options[:version] end @@ -177,12 +175,12 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[check] + @command_manager.process_args("check") assert_equal true, check_options[:alien] #check settings check_options = nil - @command_manager.process_args %w[check foobar --alien] + @command_manager.process_args("check foobar --alien") assert_equal true, check_options[:alien] end @@ -196,12 +194,12 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[build] + @command_manager.process_args("build") #NOTE: Currently no defaults #check settings check_options = nil - @command_manager.process_args %w[build foobar.rb] + @command_manager.process_args("build foobar.rb") assert_equal 'foobar.rb', check_options[:args].first end @@ -215,26 +213,26 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[query] + @command_manager.process_args("query") assert_equal(//, check_options[:name]) assert_equal :local, check_options[:domain] assert_equal false, check_options[:details] #check settings check_options = nil - @command_manager.process_args %w[query --name foobar --local --details] + @command_manager.process_args("query --name foobar --local --details") assert_equal(/foobar/i, check_options[:name]) assert_equal :local, check_options[:domain] assert_equal true, check_options[:details] #remote domain check_options = nil - @command_manager.process_args %w[query --remote] + @command_manager.process_args("query --remote") assert_equal :remote, check_options[:domain] #both (local/remote) domains check_options = nil - @command_manager.process_args %w[query --both] + @command_manager.process_args("query --both") assert_equal :both, check_options[:domain] end @@ -248,12 +246,12 @@ class TestGemCommandManager < Gem::TestCase end #check defaults - @command_manager.process_args %w[update] + @command_manager.process_args("update") assert_includes check_options[:document], 'rdoc' #check settings check_options = nil - @command_manager.process_args %w[update --force --rdoc --install-dir .] + @command_manager.process_args("update --force --rdoc --install-dir .") assert_includes check_options[:document], 'ri' assert_equal true, check_options[:force] assert_equal Dir.pwd, check_options[:install_dir] diff --git a/test/rubygems/test_gem_commands_cert_command.rb b/test/rubygems/test_gem_commands_cert_command.rb index a158a4442b..75db6c4e15 100644 --- a/test/rubygems/test_gem_commands_cert_command.rb +++ b/test/rubygems/test_gem_commands_cert_command.rb @@ -2,8 +2,8 @@ require 'rubygems/test_case' require 'rubygems/commands/cert_command' require 'rubygems/fix_openssl_warnings' if RUBY_VERSION < "1.9" -unless defined?(OpenSSL::SSL) then - warn 'Skipping `gem cert` tests. openssl not found.' +unless defined? OpenSSL then + warn "`gem cert` tests are being skipped, module OpenSSL not found" end class TestGemCommandsCertCommand < Gem::TestCase @@ -98,22 +98,14 @@ Added '/CN=alternate/DC=example' end def test_execute_build - passphrase = 'Foo bar' - @cmd.handle_options %W[--build nobody@example.com] - @build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase}" - - use_ui @build_ui do + use_ui @ui do @cmd.execute end - output = @build_ui.output.split "\n" + output = @ui.output.split "\n" - assert_equal "Passphrase for your Private Key: ", - output.shift - assert_equal "Please repeat the passphrase for your Private Key: ", - output.shift assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", output.shift assert_equal "Private Key: #{File.join @tempdir, 'gem-private_key.pem'}", @@ -123,43 +115,12 @@ Added '/CN=alternate/DC=example' output.shift assert_empty output - assert_empty @build_ui.error + assert_empty @ui.error assert_path_exists File.join(@tempdir, 'gem-private_key.pem') assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') end - def test_execute_build_bad_passphrase_confirmation - passphrase = 'Foo bar' - passphrase_confirmation = 'Fu bar' - - @cmd.handle_options %W[--build nobody@example.com] - - @build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase_confirmation}" - - use_ui @build_ui do - e = assert_raises Gem::CommandLineError do - @cmd.execute - end - - output = @build_ui.output.split "\n" - - assert_equal "Passphrase for your Private Key: ", - output.shift - assert_equal "Please repeat the passphrase for your Private Key: ", - output.shift - - assert_empty output - - assert_equal "Passphrase and passphrase confirmation don't match", - e.message - - end - - refute_path_exists File.join(@tempdir, 'gem-private_key.pem') - refute_path_exists File.join(@tempdir, 'gem-public_cert.pem') - end - def test_execute_build_key @cmd.handle_options %W[ --build nobody@example.com @@ -174,32 +135,21 @@ Added '/CN=alternate/DC=example' assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", output.shift + assert_equal "Private Key: #{File.join @tempdir, 'gem-private_key.pem'}", + output.shift - assert_empty output - assert_empty @ui.error - - assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') - end - - def test_execute_build_encrypted_key - @cmd.handle_options %W[ - --build nobody@example.com - --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} - ] - - use_ui @ui do - @cmd.execute - end - - output = @ui.output.split "\n" - - assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", + assert_equal "Don't forget to move the key file to somewhere private!", output.shift assert_empty output assert_empty @ui.error assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') + + private_key_file = File.join @tempdir, 'gem-private_key.pem' + assert_path_exists private_key_file + + assert_equal PRIVATE_KEY.to_pem, File.read(private_key_file) end def test_execute_certificate @@ -253,17 +203,6 @@ Added '/CN=alternate/DC=example' assert_equal PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem end - def test_execute_encrypted_private_key - use_ui @ui do - @cmd.send :handle_options, %W[--private-key #{ENCRYPTED_PRIVATE_KEY_PATH}] - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - - assert_equal ENCRYPTED_PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem - end - def test_execute_remove @trust_dir.trust_cert PUBLIC_CERT @@ -368,35 +307,6 @@ Removed '/CN=alternate/DC=example' assert_equal mask, File.stat(path).mode unless win_platform? end - def test_execute_sign_encrypted_key - path = File.join @tempdir, 'cert.pem' - Gem::Security.write ALTERNATE_CERT, path, 0600 - - assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s - - @cmd.handle_options %W[ - --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} - --certificate #{PUBLIC_CERT_FILE} - - --sign #{path} - ] - - use_ui @ui do - @cmd.execute - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - - cert = OpenSSL::X509::Certificate.new File.read path - - assert_equal '/CN=nobody/DC=example', cert.issuer.to_s - - mask = 0100600 & (~File.umask) - - assert_equal mask, File.stat(path).mode unless win_platform? - end - def test_execute_sign_default FileUtils.mkdir_p File.join Gem.user_home, '.gem' @@ -429,38 +339,6 @@ Removed '/CN=alternate/DC=example' assert_equal mask, File.stat(path).mode unless win_platform? end - def test_execute_sign_default_encrypted_key - FileUtils.mkdir_p File.join(Gem.user_home, '.gem') - - private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' - Gem::Security.write ENCRYPTED_PRIVATE_KEY, private_key_path, 0600, PRIVATE_KEY_PASSPHRASE - - public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' - Gem::Security.write PUBLIC_CERT, public_cert_path - - path = File.join @tempdir, 'cert.pem' - Gem::Security.write ALTERNATE_CERT, path, 0600 - - assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s - - @cmd.handle_options %W[--sign #{path}] - - use_ui @ui do - @cmd.execute - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - - cert = OpenSSL::X509::Certificate.new File.read path - - assert_equal '/CN=nobody/DC=example', cert.issuer.to_s - - mask = 0100600 & (~File.umask) - - assert_equal mask, File.stat(path).mode unless win_platform? - end - def test_execute_sign_no_cert FileUtils.mkdir_p File.join Gem.user_home, '.gem' @@ -631,24 +509,6 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis assert_equal [ALTERNATE_CERT_FILE, CHILD_CERT_FILE], @cmd.options[:sign] end - def test_handle_options_sign_encrypted_key - @cmd.handle_options %W[ - --private-key #{ALTERNATE_KEY_FILE} - --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} - - --certificate #{ALTERNATE_CERT_FILE} - --certificate #{PUBLIC_CERT_FILE} - - --sign #{ALTERNATE_CERT_FILE} - --sign #{CHILD_CERT_FILE} - ] - - assert_equal ENCRYPTED_PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem - assert_equal PUBLIC_CERT.to_pem, @cmd.options[:issuer_cert].to_pem - - assert_equal [ALTERNATE_CERT_FILE, CHILD_CERT_FILE], @cmd.options[:sign] - end - def test_handle_options_sign_nonexistent nonexistent = File.join @tempdir, 'nonexistent' e = assert_raises OptionParser::InvalidArgument do @@ -665,5 +525,5 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis e.message end -end if defined?(OpenSSL::SSL) +end if defined? OpenSSL diff --git a/test/rubygems/test_gem_commands_cleanup_command.rb b/test/rubygems/test_gem_commands_cleanup_command.rb index 6fd06d26e0..26b1fe7b0c 100644 --- a/test/rubygems/test_gem_commands_cleanup_command.rb +++ b/test/rubygems/test_gem_commands_cleanup_command.rb @@ -15,21 +15,6 @@ class TestGemCommandsCleanupCommand < Gem::TestCase install_gem @a_2 end - def test_handle_options_d - @cmd.handle_options %w[-d] - assert @cmd.options[:dryrun] - end - - def test_handle_options_dry_run - @cmd.handle_options %w[--dryrun] - assert @cmd.options[:dryrun] - end - - def test_handle_options_n - @cmd.handle_options %w[-n] - assert @cmd.options[:dryrun] - end - def test_execute @cmd.options[:args] = %w[a] diff --git a/test/rubygems/test_gem_commands_contents_command.rb b/test/rubygems/test_gem_commands_contents_command.rb index d87e84fc82..60df53f53b 100644 --- a/test/rubygems/test_gem_commands_contents_command.rb +++ b/test/rubygems/test_gem_commands_contents_command.rb @@ -91,34 +91,6 @@ class TestGemCommandsContentsCommand < Gem::TestCase assert_equal "", @ui.error end - def test_execute_missing_single - @cmd.options[:args] = %w[foo] - - assert_raises Gem::MockGemUi::TermError do - use_ui @ui do - @cmd.execute - end - end - - assert_match "Unable to find gem 'foo'", @ui.output - assert_empty @ui.error - end - - def test_execute_missing_multiple - @cmd.options[:args] = %w[foo bar] - - gem 'foo' - - use_ui @ui do - @cmd.execute - end - - assert_match "lib/foo.rb", @ui.output - assert_match "Unable to find gem 'bar'", @ui.output - - assert_empty @ui.error - end - def test_execute_multiple @cmd.options[:args] = %w[foo bar] @@ -168,10 +140,10 @@ lib/foo.rb @cmd.execute end - expected = [ - File.join(Gem::ConfigMap[:bindir], 'default_command'), - File.join(Gem::ConfigMap[:rubylibdir], 'default/gem.rb'), - File.join(Gem::ConfigMap[:archdir], 'default_gem.so') + expected = %W[ + #{Gem::ConfigMap[:bindir]}/default_command + #{Gem::ConfigMap[:rubylibdir]}/default/gem.rb + #{Gem::ConfigMap[:archdir]}/default_gem.so ].sort.join "\n" assert_equal expected, @ui.output.chomp diff --git a/test/rubygems/test_gem_commands_environment_command.rb b/test/rubygems/test_gem_commands_environment_command.rb index 253c459d94..439057df9d 100644 --- a/test/rubygems/test_gem_commands_environment_command.rb +++ b/test/rubygems/test_gem_commands_environment_command.rb @@ -11,7 +11,6 @@ class TestGemCommandsEnvironmentCommand < Gem::TestCase def test_execute orig_sources = Gem.sources.dup - orig_path, ENV['PATH'] = ENV['PATH'], %w[/usr/local/bin /usr/bin /bin].join(File::PATH_SEPARATOR) Gem.sources.replace %w[http://gems.example.com] Gem.configuration['gemcutter_key'] = 'blah' @@ -37,17 +36,10 @@ class TestGemCommandsEnvironmentCommand < Gem::TestCase assert_match %r|"gemcutter_key" => "\*\*\*\*"|, @ui.output assert_match %r|:verbose => |, @ui.output assert_match %r|REMOTE SOURCES:|, @ui.output - - assert_match %r|- SHELL PATH:|, @ui.output - assert_match %r|- /usr/local/bin$|, @ui.output - assert_match %r|- /usr/bin$|, @ui.output - assert_match %r|- /bin$|, @ui.output - - assert_empty @ui.error + assert_equal '', @ui.error ensure Gem.sources.replace orig_sources - ENV['PATH'] = orig_path end def test_execute_gemdir diff --git a/test/rubygems/test_gem_commands_fetch_command.rb b/test/rubygems/test_gem_commands_fetch_command.rb index 364881a132..924f4c44e7 100644 --- a/test/rubygems/test_gem_commands_fetch_command.rb +++ b/test/rubygems/test_gem_commands_fetch_command.rb @@ -34,32 +34,6 @@ class TestGemCommandsFetchCommand < Gem::TestCase 'gem repository directories must not be created' end - def test_execute_latest - util_setup_fake_fetcher - util_setup_spec_fetcher @a1, @a2 - - @fetcher.data["#{@gem_repo}gems/#{@a1.file_name}"] = - File.read(@a1.cache_file) - @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - File.read(@a2.cache_file) - - refute_path_exists File.join(@tempdir, 'cache'), 'sanity check' - - @cmd.options[:args] = [@a2.name] - @cmd.options[:version] = req('>= 0.1') - - use_ui @ui do - Dir.chdir @tempdir do - @cmd.execute - end - end - - assert_path_exists(File.join(@tempdir, @a2.file_name), - "#{@a2.full_name} not fetched") - refute_path_exists File.join(@tempdir, 'cache'), - 'gem repository directories must not be created' - end - def test_execute_prerelease util_setup_fake_fetcher true util_clear_gems @@ -79,8 +53,8 @@ class TestGemCommandsFetchCommand < Gem::TestCase end end - assert_path_exists(File.join(@tempdir, @a2.file_name), - "#{@a2.full_name} not fetched") + assert_path_exists(File.join(@tempdir, @a2_pre.file_name), + "#{@a2_pre.full_name} not fetched") end def test_execute_specific_prerelease diff --git a/test/rubygems/test_gem_commands_help_command.rb b/test/rubygems/test_gem_commands_help_command.rb index 3a6f2fa523..a10e575a5a 100644 --- a/test/rubygems/test_gem_commands_help_command.rb +++ b/test/rubygems/test_gem_commands_help_command.rb @@ -18,7 +18,7 @@ class TestGemCommandsHelpCommand < Gem::TestCase def test_gem_help_bad util_gem 'bad' do |out, err| assert_equal('', out) - assert_match "Unknown command bad", err + assert_match(/Unknown command bad. Try gem help commands\n/, err) end end @@ -36,12 +36,9 @@ class TestGemCommandsHelpCommand < Gem::TestCase mgr.command_names.each do |cmd| assert_match(/\s+#{cmd}\s+\S+/, out) end + assert_equal '', err - if defined?(OpenSSL::SSL) then - assert_empty err - - refute_match 'No command found for ', out - end + refute_match 'No command found for ', out end end diff --git a/test/rubygems/test_gem_commands_install_command.rb b/test/rubygems/test_gem_commands_install_command.rb index caf52f147d..f86d2837ea 100644 --- a/test/rubygems/test_gem_commands_install_command.rb +++ b/test/rubygems/test_gem_commands_install_command.rb @@ -6,7 +6,6 @@ class TestGemCommandsInstallCommand < Gem::TestCase def setup super - common_installer_setup @cmd = Gem::Commands::InstallCommand.new @cmd.options[:document] = [] @@ -169,7 +168,8 @@ class TestGemCommandsInstallCommand < Gem::TestCase # This is needed because we need to exercise the cache path # within SpecFetcher - path = File.join Gem.spec_cache_dir, "not-there.nothing%80", "latest_specs.4.8" + path = File.join Gem.user_home, '.gem', 'specs', "not-there.nothing%80", + "latest_specs.4.8" FileUtils.mkdir_p File.dirname(path) @@ -633,6 +633,67 @@ ERROR: Possible alternatives: non_existent_with_hint assert_equal x, e end + def test_execute_installs_dependencies + r, r_gem = util_gem 'r', '1', 'q' => '= 1' + q, q_gem = util_gem 'q', '1' + + util_setup_fake_fetcher + util_setup_spec_fetcher r, q + + Gem::Specification.reset + + @fetcher.data["#{@gem_repo}gems/#{q.file_name}"] = read_binary(q_gem) + @fetcher.data["#{@gem_repo}gems/#{r.file_name}"] = read_binary(r_gem) + + @cmd.options[:args] = ["r"] + + e = nil + use_ui @ui do + e = assert_raises Gem::SystemExitException do + capture_io do + @cmd.execute + end + end + end + + out = @ui.output.split "\n" + assert_equal "2 gems installed", out.shift + assert out.empty?, out.inspect + + assert_equal %w[q-1 r-1], @cmd.installed_specs.map { |spec| spec.full_name } + + assert_equal 0, e.exit_code + end + + def test_execute_satisfy_deps_of_local_from_sources + r, r_gem = util_gem 'r', '1', 'q' => '= 1' + q, q_gem = util_gem 'q', '1' + + util_setup_fake_fetcher + util_setup_spec_fetcher r, q + + Gem::Specification.reset + + @fetcher.data["#{@gem_repo}gems/#{q.file_name}"] = read_binary(q_gem) + + @cmd.options[:args] = [r_gem] + + use_ui @ui do + e = assert_raises Gem::SystemExitException do + capture_io do + @cmd.execute + end + end + assert_equal 0, e.exit_code + end + + assert_equal %w[q-1 r-1], @cmd.installed_specs.map { |spec| spec.full_name } + + out = @ui.output.split "\n" + assert_equal "2 gems installed", out.shift + assert out.empty?, out.inspect + end + def test_execute_uses_from_a_gemdeps util_setup_fake_fetcher util_setup_spec_fetcher @@ -890,3 +951,4 @@ ERROR: Possible alternatives: non_existent_with_hint end + diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb index 5d7b66137e..dfbc2572dc 100644 --- a/test/rubygems/test_gem_commands_owner_command.rb +++ b/test/rubygems/test_gem_commands_owner_command.rb @@ -6,7 +6,6 @@ class TestGemCommandsOwnerCommand < Gem::TestCase def setup super - ENV["RUBYGEMS_HOST"] = nil @fetcher = Gem::FakeFetcher.new Gem::RemoteFetcher.fetcher = @fetcher Gem.configuration.rubygems_api_key = "ed244fbf2b1a52e012da8616c512fa47f9aa5250" @@ -35,36 +34,6 @@ EOF assert_match %r{- user2@example.com}, @ui.output end - def test_show_owners_setting_up_host_through_env_var - response = "- email: user1@example.com\n" - host = "http://rubygems.example" - ENV["RUBYGEMS_HOST"] = host - - @fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, 'OK'] - - use_ui @ui do - @cmd.show_owners("freewill") - end - - assert_match %r{Owners for gem: freewill}, @ui.output - assert_match %r{- user1@example.com}, @ui.output - end - - def test_show_owners_setting_up_host - response = "- email: user1@example.com\n" - host = "http://rubygems.example" - @cmd.host = host - - @fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, 'OK'] - - use_ui @ui do - @cmd.show_owners("freewill") - end - - assert_match %r{Owners for gem: freewill}, @ui.output - assert_match %r{- user1@example.com}, @ui.output - end - def test_show_owners_denied response = "You don't have permission to push to this gem" @fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 403, 'Forbidden'] @@ -118,24 +87,6 @@ EOF assert_match response, @ui.output end - def test_add_owner_with_host_option_through_execute - host = "http://rubygems.example" - add_owner_response = "Owner added successfully." - show_owners_response = "- email: user1@example.com\n" - @fetcher.data["#{host}/api/v1/gems/freewill/owners"] = [add_owner_response, 200, 'OK'] - @fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [show_owners_response, 200, 'OK'] - - @cmd.handle_options %W[--host #{host} --add user-new1@example.com freewill] - - use_ui @ui do - @cmd.execute - end - - assert_match add_owner_response, @ui.output - assert_match %r{Owners for gem: freewill}, @ui.output - assert_match %r{- user1@example.com}, @ui.output - end - def test_add_owners_key response = "Owner added successfully." @fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 200, 'OK'] diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb index 78c3f85a5b..778ce2ee1f 100644 --- a/test/rubygems/test_gem_commands_pristine_command.rb +++ b/test/rubygems/test_gem_commands_pristine_command.rb @@ -80,36 +80,6 @@ class TestGemCommandsPristineCommand < Gem::TestCase assert_empty out, out.inspect end - def test_execute_env_shebang - a = quick_spec 'a' do |s| - s.executables = %w[foo] - s.files = %w[bin/foo] - end - write_file File.join(@tempdir, 'bin', 'foo') do |fp| - fp.puts "#!/usr/bin/ruby" - end - - install_gem a - - gem_exec = File.join @gemhome, 'bin', 'foo' - - FileUtils.rm gem_exec - - @cmd.handle_options %w[--all --env-shebang] - - use_ui @ui do - @cmd.execute - end - - assert_path_exists gem_exec - - if win_platform? - assert_match %r%\A#!\s*ruby%, File.read(gem_exec) - else - assert_match %r%\A#!\s*/usr/bin/env ruby%, File.read(gem_exec) - end - end - def test_execute_no_extension a = quick_spec 'a' do |s| s.extensions << 'ext/a/extconf.rb' end diff --git a/test/rubygems/test_gem_commands_sources_command.rb b/test/rubygems/test_gem_commands_sources_command.rb index 1e5afca009..8dc2f91ed4 100644 --- a/test/rubygems/test_gem_commands_sources_command.rb +++ b/test/rubygems/test_gem_commands_sources_command.rb @@ -194,7 +194,7 @@ beta-gems.example.com is not a URI assert_equal expected, @ui.output assert_equal '', @ui.error - dir = Gem.spec_cache_dir + dir = File.join Gem.user_home, '.gem', 'specs' refute File.exist?(dir), 'cache dir removed' end diff --git a/test/rubygems/test_gem_commands_uninstall_command.rb b/test/rubygems/test_gem_commands_uninstall_command.rb index 9ba1371b79..844c7b4b97 100644 --- a/test/rubygems/test_gem_commands_uninstall_command.rb +++ b/test/rubygems/test_gem_commands_uninstall_command.rb @@ -16,20 +16,6 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase @executable = File.join(@gemhome, 'bin', 'executable') end - def test_execute_all_gem_names - @cmd.options[:args] = %w[a b] - @cmd.options[:all] = true - - assert_raises Gem::MockGemUi::TermError do - use_ui @ui do - @cmd.execute - end - end - - assert_match(/\A(?:WARNING: Unable to use symlinks on Windows, installing wrapper\n)?ERROR: Gem names and --all may not be used together\n\z/, - @ui.error) - end - def test_execute_dependency_order c = quick_gem 'c' do |spec| spec.add_dependency 'a' @@ -57,7 +43,6 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase def test_execute_removes_executable ui = Gem::MockGemUi.new - util_setup_gem ui build_rake_in do @@ -190,32 +175,5 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase assert Gem::Specification.find_all_by_name('x').length == 0 end - def test_execute_all - util_make_gems - - default = new_default_spec 'default', '1' - install_default_gems default - - gemhome2 = "#{@gemhome}2" - - a_4 = quick_spec 'a', 4 - install_gem a_4, :install_dir => gemhome2 - - Gem::Specification.dirs = [@gemhome, gemhome2] - - assert_includes Gem::Specification.all_names, 'a-1' - assert_includes Gem::Specification.all_names, 'a-4' - assert_includes Gem::Specification.all_names, 'default-1' - - @cmd.options[:all] = true - @cmd.options[:args] = [] - - use_ui @ui do - @cmd.execute - end - - assert_equal %w[a-4 default-1], Gem::Specification.all_names.sort - end - end diff --git a/test/rubygems/test_gem_commands_update_command.rb b/test/rubygems/test_gem_commands_update_command.rb index d1c1b20c6e..006d821210 100644 --- a/test/rubygems/test_gem_commands_update_command.rb +++ b/test/rubygems/test_gem_commands_update_command.rb @@ -11,7 +11,6 @@ class TestGemCommandsUpdateCommand < Gem::TestCase def setup super - common_installer_setup @cmd = Gem::Commands::UpdateCommand.new @@ -254,7 +253,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase out = @ui.output.split "\n" assert_equal "Updating installed gems", out.shift assert_equal "Updating #{@a2.name}", out.shift - assert_equal "Gems updated: #{@a2.name} #{@b2.name} #{@c2.name}", + assert_equal "Gems updated: #{@c2.name} #{@b2.name} #{@a2.name}", out.shift assert_empty out diff --git a/test/rubygems/test_gem_config_file.rb b/test/rubygems/test_gem_config_file.rb index e9cd33579d..13f1c34b50 100644 --- a/test/rubygems/test_gem_config_file.rb +++ b/test/rubygems/test_gem_config_file.rb @@ -201,10 +201,6 @@ ERROR: Your gem push credentials file located at: has file permissions of 0644 but 0600 is required. -To fix this error run: - -\tchmod 0600 #{@cfg.credentials_path} - You should reset your credentials at: \thttps://rubygems.org/profile/edit @@ -432,14 +428,6 @@ if you believe they were disclosed to a third party. assert_equal('/home/me/certs', @cfg.ssl_ca_cert) end - def test_load_ssl_client_cert_from_config - File.open @temp_conf, 'w' do |fp| - fp.puts ":ssl_client_cert: /home/me/mine.pem" - end - util_config_file - assert_equal('/home/me/mine.pem', @cfg.ssl_client_cert) - end - def util_config_file(args = @cfg_args) @cfg = Gem::ConfigFile.new args end diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb index af6b922fe3..2b95597d4b 100644 --- a/test/rubygems/test_gem_dependency_installer.rb +++ b/test/rubygems/test_gem_dependency_installer.rb @@ -6,7 +6,6 @@ class TestGemDependencyInstaller < Gem::TestCase def setup super - common_installer_setup @gems_dir = File.join @tempdir, 'gems' @cache_dir = File.join @gemhome, 'cache' @@ -173,8 +172,7 @@ class TestGemDependencyInstaller < Gem::TestCase FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir - FileUtils.mv e1_gem, @tempdir - + FileUtils.mv e1_gem, @tempdir inst = nil Dir.chdir @tempdir do @@ -182,15 +180,40 @@ class TestGemDependencyInstaller < Gem::TestCase inst.install 'b' end - assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }, - 'sanity check' - Dir.chdir @tempdir do inst = Gem::DependencyInstaller.new inst.install 'e' end - assert_equal %w[a-1 e-1], inst.installed_gems.map { |s| s.full_name } + assert_equal %w[e-1 a-1], inst.installed_gems.map { |s| s.full_name } + end + + def test_install_ignore_satified_deps + util_setup_gems + + _, e1_gem = util_gem 'e', '1' do |s| + s.add_dependency 'b' + end + + util_clear_gems + + FileUtils.mv @a1_gem, @tempdir + FileUtils.mv @b1_gem, @tempdir + FileUtils.mv e1_gem, @tempdir + + Dir.chdir @tempdir do + i = Gem::DependencyInstaller.new :ignore_dependencies => true + i.install 'b' + end + + inst = nil + + Dir.chdir @tempdir do + inst = Gem::DependencyInstaller.new :minimal_deps => true + inst.install 'e' + end + + assert_equal %w[e-1], inst.installed_gems.map { |s| s.full_name } end def test_install_cache_dir @@ -223,18 +246,15 @@ class TestGemDependencyInstaller < Gem::TestCase Gem::Specification.reset FileUtils.mv @a1_gem, @tempdir - FileUtils.mv a2_gem, @tempdir # not in index + FileUtils.mv a2_gem, @tempdir # not in index FileUtils.mv @b1_gem, @tempdir inst = nil Dir.chdir @tempdir do inst = Gem::DependencyInstaller.new - inst.install 'a', req("= 2") + inst.install 'a', Gem::Requirement.create("= 2") end - assert_equal %w[a-2], inst.installed_gems.map { |s| s.full_name }, - 'sanity check' - FileUtils.rm File.join(@tempdir, a2.file_name) Dir.chdir @tempdir do @@ -262,18 +282,19 @@ class TestGemDependencyInstaller < Gem::TestCase Gem::Specification.reset FileUtils.mv @a1_gem, @tempdir - FileUtils.mv a2_gem, @tempdir # not in index + FileUtils.mv a2_gem, @tempdir # not in index FileUtils.mv @b1_gem, @tempdir - FileUtils.mv a3_gem, @tempdir + FileUtils.mv a3_gem, @tempdir + + inst = nil Dir.chdir @tempdir do - Gem::DependencyInstaller.new.install 'a', req("= 2") + inst = Gem::DependencyInstaller.new + inst.install 'a', Gem::Requirement.create("= 2") end FileUtils.rm File.join(@tempdir, a2.file_name) - inst = nil - Dir.chdir @tempdir do inst = Gem::DependencyInstaller.new inst.install 'b' @@ -467,42 +488,6 @@ class TestGemDependencyInstaller < Gem::TestCase assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name } end - def test_install_minimal_deps - util_setup_gems - - _, e1_gem = util_gem 'e', '1' do |s| - s.add_dependency 'b' - end - - _, b2_gem = util_gem 'b', '2' do |s| - s.add_dependency 'a' - end - - util_clear_gems - - FileUtils.mv @a1_gem, @tempdir - FileUtils.mv @b1_gem, @tempdir - FileUtils.mv b2_gem, @tempdir - FileUtils.mv e1_gem, @tempdir - - inst = nil - - Dir.chdir @tempdir do - inst = Gem::DependencyInstaller.new :ignore_dependencies => true - inst.install 'b', req('= 1') - end - - assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }, - 'sanity check' - - Dir.chdir @tempdir do - inst = Gem::DependencyInstaller.new :minimal_deps => true - inst.install 'e' - end - - assert_equal %w[a-1 e-1], inst.installed_gems.map { |s| s.full_name } - end - def test_install_env_shebang util_setup_gems @@ -642,12 +627,12 @@ class TestGemDependencyInstaller < Gem::TestCase inst = nil Dir.chdir @tempdir do - e = assert_raises Gem::UnsatisfiableDependencyError do + e = assert_raises Gem::DependencyError do inst = Gem::DependencyInstaller.new :domain => :local inst.install 'b' end - expected = "Unable to resolve dependency: b (= 1) requires a (>= 0)" + expected = "Unable to resolve dependencies: b requires a (>= 0)" assert_equal expected, e.message end @@ -925,13 +910,12 @@ class TestGemDependencyInstaller < Gem::TestCase gems = set.sorted assert_equal 2, gems.length - - remote, local = gems - + local = gems.first assert_equal 'a-1', local.spec.full_name, 'local spec' assert_equal File.join(@tempdir, @a1.file_name), local.source.download(local.spec), 'local path' + remote = gems.last assert_equal 'a-1', remote.spec.full_name, 'remote spec' assert_equal Gem::Source.new(@gem_repo), remote.source, 'remote path' diff --git a/test/rubygems/test_gem_dependency_resolver.rb b/test/rubygems/test_gem_dependency_resolver.rb index 47eef8cc55..08d8e62f2b 100644 --- a/test/rubygems/test_gem_dependency_resolver.rb +++ b/test/rubygems/test_gem_dependency_resolver.rb @@ -15,9 +15,7 @@ class TestGemDependencyResolver < Gem::TestCase exp = expected.sort_by { |s| s.full_name } act = actual.map { |a| a.spec }.sort_by { |s| s.full_name } - msg = "Set of gems was not the same: #{exp.map { |x| x.full_name}.inspect} != #{act.map { |x| x.full_name}.inspect}" - - assert_equal exp, act, msg + assert_equal exp, act end def test_no_overlap_specificly @@ -66,32 +64,6 @@ class TestGemDependencyResolver < Gem::TestCase assert_set [a2], res.resolve end - def test_picks_best_platform - is = Gem::DependencyResolver::IndexSpecification - unknown = Gem::Platform.new 'unknown' - a2_p1 = quick_spec 'a', 2 do |s| s.platform = Gem::Platform.local end - a3_p2 = quick_spec 'a', 3 do |s| s.platform = unknown end - v2 = v(2) - v3 = v(3) - source = Gem::Source.new @gem_repo - - s = set - - a2 = is.new s, 'a', v2, source, Gem::Platform::RUBY - a2_p1 = is.new s, 'a', v2, source, Gem::Platform.local.to_s - a3_p2 = is.new s, 'a', v3, source, unknown - - s.add a3_p2 - s.add a2_p1 - s.add a2 - - ad = make_dep "a" - - res = Gem::DependencyResolver.new([ad], s) - - assert_set [a2_p1], res.resolve - end - def test_only_returns_spec_once a1 = util_spec "a", "1", "c" => "= 1" b1 = util_spec "b", "1", "c" => "= 1" @@ -205,8 +177,7 @@ class TestGemDependencyResolver < Gem::TestCase r.resolve end - assert_equal "Unable to resolve dependency: (unknown) requires a (>= 0)", - e.message + assert_equal "unable to find any gem matching dependency 'a (>= 0)'", e.message assert_equal "a (>= 0)", e.dependency.to_s end @@ -244,7 +215,7 @@ class TestGemDependencyResolver < Gem::TestCase r.resolve end - assert_match "a-1 requires c (>= 2) but it conflicted", e.message + assert_equal "detected 1 conflict with dependency 'c (>= 2)'", e.message assert_equal "c (>= 2)", e.dependency.to_s @@ -353,18 +324,4 @@ class TestGemDependencyResolver < Gem::TestCase assert_set [b1, c1, d2], r.resolve end - - def test_select_local_platforms - r = Gem::DependencyResolver.new nil, nil - - a1 = quick_spec 'a', 1 - a1_p1 = quick_spec 'a', 1 do |s| s.platform = Gem::Platform.local end - a1_p2 = quick_spec 'a', 1 do |s| s.platform = 'unknown' end - - selected = r.select_local_platforms [a1, a1_p1, a1_p2] - - assert_equal [a1, a1_p1], selected - end - end - diff --git a/test/rubygems/test_gem_ext_builder.rb b/test/rubygems/test_gem_ext_builder.rb index 8383040f88..6e34ee7e46 100644 --- a/test/rubygems/test_gem_ext_builder.rb +++ b/test/rubygems/test_gem_ext_builder.rb @@ -1,6 +1,5 @@ require 'rubygems/test_case' require 'rubygems/ext' -require 'rubygems/installer' class TestGemExtBuilder < Gem::TestCase @@ -14,10 +13,6 @@ class TestGemExtBuilder < Gem::TestCase FileUtils.mkdir_p @dest_path @orig_DESTDIR = ENV['DESTDIR'] - - @spec = quick_spec 'a' - - @builder = Gem::Ext::Builder.new @spec, '' end def teardown @@ -61,93 +56,5 @@ install: end end - def test_build_extensions_none - use_ui @ui do - @builder.build_extensions - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - - refute File.exist?('gem_make.out') - end - - def test_build_extensions_extconf_bad - @spec.extensions << 'extconf.rb' - - e = assert_raises Gem::Installer::ExtensionBuildError do - use_ui @ui do - @builder.build_extensions - end - end - - assert_match(/\AERROR: Failed to build gem native extension.$/, e.message) - - assert_equal "Building native extensions. This could take a while...\n", - @ui.output - assert_equal '', @ui.error - - gem_make_out = File.join @gemhome, 'gems', @spec.full_name, 'gem_make.out' - - assert_match %r%#{Regexp.escape Gem.ruby} extconf\.rb%, - File.read(gem_make_out) - assert_match %r%#{Regexp.escape Gem.ruby}: No such file%, - File.read(gem_make_out) - end - - def test_build_extensions_unsupported - FileUtils.mkdir_p @spec.gem_dir - gem_make_out = File.join @spec.gem_dir, 'gem_make.out' - @spec.extensions << nil - - e = assert_raises Gem::Installer::ExtensionBuildError do - use_ui @ui do - @builder.build_extensions - end - end - - assert_match(/^\s*No builder for extension ''$/, e.message) - - assert_equal "Building native extensions. This could take a while...\n", - @ui.output - assert_equal '', @ui.error - - assert_equal "No builder for extension ''\n", File.read(gem_make_out) - ensure - FileUtils.rm_f gem_make_out - end - - def test_build_extensions_with_build_args - args = ["--aa", "--bb"] - @builder.build_args = args - @spec.extensions << 'extconf.rb' - - FileUtils.mkdir_p @spec.gem_dir - - open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f| - f.write <<-'RUBY' - puts "IN EXTCONF" - extconf_args = File.join File.dirname(__FILE__), 'extconf_args' - File.open extconf_args, 'w' do |f| - f.puts ARGV.inspect - end - - File.open 'Makefile', 'w' do |f| - f.puts "default:\n\techo built" - f.puts "install:\n\techo installed" - end - RUBY - end - - use_ui @ui do - @builder.build_extensions - end - - path = File.join @spec.gem_dir, "extconf_args" - - assert_equal args.inspect, File.read(path).strip - assert File.directory? File.join(@spec.gem_dir, 'lib') - end - end diff --git a/test/rubygems/test_gem_ext_ext_conf_builder.rb b/test/rubygems/test_gem_ext_ext_conf_builder.rb index dfbf3fe1b9..33398ac6f3 100644 --- a/test/rubygems/test_gem_ext_ext_conf_builder.rb +++ b/test/rubygems/test_gem_ext_ext_conf_builder.rb @@ -120,13 +120,8 @@ checking for main\(\) in .*?nonexistent/m, error.message) extconf.puts <<-'EXTCONF' include RbConfig -ruby = - if ENV['RUBY'] then - ENV['RUBY'] - else - ruby_exe = "#{CONFIG['RUBY_INSTALL_NAME']}#{CONFIG['EXEEXT']}" - File.join CONFIG['bindir'], ruby_exe - end +ruby_exe = "#{CONFIG['RUBY_INSTALL_NAME']}#{CONFIG['EXEEXT']}" +ruby = File.join CONFIG['bindir'], ruby_exe open 'Makefile', 'w' do |io| io.write <<-Makefile diff --git a/test/rubygems/test_gem_gem_runner.rb b/test/rubygems/test_gem_gem_runner.rb index 85ff725345..6680a784c9 100644 --- a/test/rubygems/test_gem_gem_runner.rb +++ b/test/rubygems/test_gem_gem_runner.rb @@ -7,7 +7,6 @@ class TestGemGemRunner < Gem::TestCase super @orig_args = Gem::Command.build_args - @runner = Gem::GemRunner.new end def teardown @@ -42,26 +41,23 @@ class TestGemGemRunner < Gem::TestCase assert_equal %w[--commands], Gem::Command.extra_args end - def test_extract_build_args - args = %w[] - assert_equal [], @runner.extract_build_args(args) - assert_equal %w[], args + def test_build_args_are_handled + Gem.clear_paths + + cls = Class.new(Gem::Command) do + def execute + end + end - args = %w[foo] - assert_equal [], @runner.extract_build_args(args) - assert_equal %w[foo], args + test_obj = cls.new :ba_test - args = %w[--foo] - assert_equal [], @runner.extract_build_args(args) - assert_equal %w[--foo], args + cmds = Gem::CommandManager.new + cmds.register_command :ba_test, test_obj - args = %w[--foo --] - assert_equal [], @runner.extract_build_args(args) - assert_equal %w[--foo], args + runner = Gem::GemRunner.new :command_manager => cmds + runner.run(%W[ba_test -- --build_arg1 --build_arg2]) - args = %w[--foo -- --bar] - assert_equal %w[--bar], @runner.extract_build_args(args) - assert_equal %w[--foo], args + assert_equal %w[--build_arg1 --build_arg2], test_obj.options[:build_args] end end diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index d70ac35beb..18b4518b06 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -101,7 +101,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_host api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' - util_sign_in [api_key, 200, 'OK'], 'http://example.com', ['http://example.com'] + util_sign_in [api_key, 200, 'OK'], 'http://example.com', :param assert_match "Enter your http://example.com credentials.", @sign_in_ui.output @@ -112,20 +112,6 @@ class TestGemGemcutterUtilities < Gem::TestCase assert_equal api_key, credentials[:rubygems_api_key] end - def test_sign_in_with_host_nil - api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' - - util_sign_in [api_key, 200, 'OK'], nil, [nil] - - assert_match "Enter your RubyGems.org credentials.", - @sign_in_ui.output - assert @fetcher.last_request["authorization"] - assert_match %r{Signed in.}, @sign_in_ui.output - - credentials = YAML.load_file Gem.configuration.credentials_path - assert_equal api_key, credentials[:rubygems_api_key] - end - def test_sign_in_with_host_ENV api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' util_sign_in [api_key, 200, 'OK'], 'http://example.com' @@ -177,14 +163,14 @@ class TestGemGemcutterUtilities < Gem::TestCase assert_match %r{Access Denied.}, @sign_in_ui.output end - def util_sign_in response, host = nil, args = [] + def util_sign_in response, host = nil, style = :ENV skip 'Always uses $stdin on windows' if Gem.win_platform? email = 'you@example.com' password = 'secret' if host - ENV['RUBYGEMS_HOST'] = host + ENV['RUBYGEMS_HOST'] = host if style == :ENV else host = Gem.host end @@ -196,8 +182,8 @@ class TestGemGemcutterUtilities < Gem::TestCase @sign_in_ui = Gem::MockGemUi.new "#{email}\n#{password}\n" use_ui @sign_in_ui do - if args.length > 0 then - @cmd.sign_in(*args) + if style == :param then + @cmd.sign_in host else @cmd.sign_in end @@ -223,3 +209,4 @@ class TestGemGemcutterUtilities < Gem::TestCase end end + diff --git a/test/rubygems/test_gem_install_update_options.rb b/test/rubygems/test_gem_install_update_options.rb index 3f63896999..18d3569417 100644 --- a/test/rubygems/test_gem_install_update_options.rb +++ b/test/rubygems/test_gem_install_update_options.rb @@ -22,13 +22,12 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase --rdoc --ri -E + -P HighSecurity -f -i /install_to -w ] - args.concat %w[-P HighSecurity] if defined?(OpenSSL::SSL) - assert @cmd.handles?(args) end @@ -101,8 +100,6 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase end def test_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @cmd.handle_options %w[-P HighSecurity] assert_equal Gem::Security::HighSecurity, @cmd.options[:security_policy] diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 01b151c089..e513fe6da3 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -4,7 +4,6 @@ class TestGemInstaller < Gem::InstallerTestCase def setup super - common_installer_setup if __name__ =~ /^test_install(_|$)/ then FileUtils.rm_r @spec.gem_dir @@ -15,8 +14,6 @@ class TestGemInstaller < Gem::InstallerTestCase end def teardown - common_installer_teardown - super Gem.configuration = @config @@ -55,6 +52,95 @@ load Gem.bin_path('a', 'executable', version) assert_equal expected, wrapper end + def test_build_extensions_none + use_ui @ui do + @installer.build_extensions + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + refute File.exist?('gem_make.out') + end + + def test_build_extensions_extconf_bad + @installer.spec = @spec + @spec.extensions << 'extconf.rb' + + e = assert_raises Gem::Installer::ExtensionBuildError do + use_ui @ui do + @installer.build_extensions + end + end + + assert_match(/\AERROR: Failed to build gem native extension.$/, e.message) + + assert_equal "Building native extensions. This could take a while...\n", + @ui.output + assert_equal '', @ui.error + + gem_make_out = File.join @gemhome, 'gems', @spec.full_name, 'gem_make.out' + + assert_match %r%#{Regexp.escape Gem.ruby} extconf\.rb%, + File.read(gem_make_out) + assert_match %r%#{Regexp.escape Gem.ruby}: No such file%, + File.read(gem_make_out) + end + + def test_build_extensions_unsupported + @installer.spec = @spec + FileUtils.mkdir_p @spec.gem_dir + gem_make_out = File.join @spec.gem_dir, 'gem_make.out' + @spec.extensions << nil + + e = assert_raises Gem::Installer::ExtensionBuildError do + use_ui @ui do + @installer.build_extensions + end + end + + assert_match(/^\s*No builder for extension ''$/, e.message) + + assert_equal "Building native extensions. This could take a while...\n", + @ui.output + assert_equal '', @ui.error + + assert_equal "No builder for extension ''\n", File.read(gem_make_out) + ensure + FileUtils.rm_f gem_make_out + end + + def test_build_extensions_with_build_args + args = ["--aa", "--bb"] + @installer.build_args = args + @installer.spec = @spec + @spec.extensions << 'extconf.rb' + + File.open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f| + f.write <<-'RUBY' + puts "IN EXTCONF" + extconf_args = File.join File.dirname(__FILE__), 'extconf_args' + File.open extconf_args, 'w' do |f| + f.puts ARGV.inspect + end + + File.open 'Makefile', 'w' do |f| + f.puts "default:\n\techo built" + f.puts "install:\n\techo installed" + end + RUBY + end + + use_ui @ui do + @installer.build_extensions + end + + path = File.join @spec.gem_dir, "extconf_args" + + assert_equal args.inspect, File.read(path).strip + assert File.directory? File.join(@spec.gem_dir, 'lib') + end + def test_check_executable_overwrite @installer.generate_bin @@ -73,7 +159,7 @@ load Gem.bin_path('a', 'executable', version) @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert File.exist? installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper @@ -136,7 +222,7 @@ gem 'other', version @installer.generate_bin # should not raise installed_exec = File.join util_inst_bindir, 'foo-executable-bar' - assert_path_exists installed_exec + assert File.exist? installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper @@ -165,7 +251,7 @@ gem 'other', version @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert File.exist? installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper @@ -178,7 +264,7 @@ gem 'other', version @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert File.exist? installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper @@ -214,8 +300,6 @@ gem 'other', version end def test_ensure_loadable_spec_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - _, a_gem = util_gem 'a', 2 do |s| s.add_dependency 'garbage ~> 5' end @@ -252,7 +336,7 @@ gem 'other', version assert_equal true, File.directory?(util_inst_bindir) installed_exec = File.join(util_inst_bindir, 'executable') - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec @@ -287,7 +371,7 @@ gem 'other', version @installer.generate_bin assert File.directory? util_inst_bindir installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert File.exist? installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec @@ -304,7 +388,7 @@ gem 'other', version @installer.generate_bin assert_equal true, File.directory?(util_inst_bindir) installed_exec = File.join util_inst_bindir, 'foo-executable-bar' - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) ensure Gem::Installer.exec_format = nil end @@ -318,7 +402,7 @@ gem 'other', version @installer.generate_bin assert_equal true, File.directory?(util_inst_bindir) installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) ensure Gem::Installer.exec_format = nil end @@ -340,7 +424,7 @@ gem 'other', version @installer.generate_bin installed_exec = File.join("#{@gemhome}2", "bin", 'executable') - assert_path_exists installed_exec + assert File.exist? installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec @@ -353,7 +437,7 @@ gem 'other', version @installer.wrappers = true @installer.generate_bin - refute_path_exists util_inst_bindir, 'bin dir was created when not needed' + refute File.exist?(util_inst_bindir), 'bin dir was created when not needed' end def test_generate_bin_script_no_perms @@ -389,7 +473,7 @@ gem 'other', version @installer.generate_bin installed_exec = File.join @gemhome, 'bin', 'executable' - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec @@ -414,7 +498,7 @@ gem 'other', version @installer.generate_bin assert_equal true, File.directory?(util_inst_bindir) - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) assert_equal mask, File.stat(installed_exec).mode unless win_platform? assert_match %r|generated by RubyGems|, File.read(installed_exec) @@ -444,7 +528,7 @@ gem 'other', version @installer.wrappers = false @installer.generate_bin - refute_path_exists util_inst_bindir + refute File.exist?(util_inst_bindir) end def test_generate_bin_symlink_no_perms @@ -543,7 +627,7 @@ gem 'other', version @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec + assert File.exist? installed_exec @spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] @@ -580,7 +664,7 @@ gem 'other', version assert_equal true, File.directory?(util_inst_bindir) installed_exec = File.join(util_inst_bindir, 'executable') - assert_path_exists installed_exec + assert_equal true, File.exist?(installed_exec) assert_match(/Unable to use symlinks on Windows, installing wrapper/i, @ui.error) @@ -647,19 +731,19 @@ gem 'other', version rakefile = File.join gemdir, 'ext', 'a', 'Rakefile' Gem.pre_install do |installer| - refute_path_exists cache_file, 'cache file must not exist yet' + refute File.exist?(cache_file), 'cache file must not exist yet' true end Gem.post_build do |installer| - assert_path_exists gemdir, 'gem install dir must exist' - assert_path_exists rakefile, 'gem executable must exist' - refute_path_exists stub_exe, 'gem executable must not exist' + assert File.exist?(gemdir), 'gem install dir must exist' + assert File.exist?(rakefile), 'gem executable must exist' + refute File.exist?(stub_exe), 'gem executable must not exist' true end Gem.post_install do |installer| - assert_path_exists cache_file, 'cache file must exist' + assert File.exist?(cache_file), 'cache file must exist' end @newspec = nil @@ -670,23 +754,23 @@ gem 'other', version end assert_equal @spec, @newspec - assert_path_exists gemdir - assert_path_exists stub_exe, 'gem executable must exist' + assert File.exist? gemdir + assert File.exist?(stub_exe), 'gem executable must exist' exe = File.join gemdir, 'bin', 'executable' - assert_path_exists exe + assert File.exist? exe exe_mode = File.stat(exe).mode & 0111 assert_equal 0111, exe_mode, "0%o" % exe_mode unless win_platform? - assert_path_exists File.join gemdir, 'lib', 'code.rb' + assert File.exist?(File.join(gemdir, 'lib', 'code.rb')) - assert_path_exists rakefile + assert File.exist? rakefile spec_file = File.join(@gemhome, 'specifications', @spec.spec_name) assert_equal spec_file, @newspec.loaded_from - assert_path_exists spec_file + assert File.exist?(spec_file) assert_same @installer, @post_build_hook_arg assert_same @installer, @post_install_hook_arg @@ -795,7 +879,7 @@ gem 'other', version end gemdir = File.join(@gemhome, 'gems', @spec.full_name) - assert_path_exists File.join gemdir, 'lib', 'code.rb' + assert File.exist?(File.join(gemdir, 'lib', 'code.rb')) util_setup_gem # Morph spec to have lib/other.rb instead of code.rb and recreate @@ -814,9 +898,9 @@ gem 'other', version end end - assert_path_exists File.join gemdir, 'lib', 'other.rb' - refute_path_exists File.join gemdir, 'lib', 'code.rb', - "code.rb from prior install of same gem shouldn't remain here" + assert File.exist?(File.join(gemdir, 'lib', 'other.rb')) + refute(File.exist?(File.join(gemdir, 'lib', 'code.rb')), + "code.rb from prior install of same gem shouldn't remain here") end def test_install_force @@ -826,7 +910,7 @@ gem 'other', version end gem_dir = File.join(@gemhome, 'gems', 'old_ruby_required-1') - assert_path_exists gem_dir + assert File.exist?(gem_dir) end def test_install_missing_dirs @@ -842,8 +926,8 @@ gem 'other', version File.directory? File.join(Gem.dir, 'docs') File.directory? File.join(Gem.dir, 'specifications') - assert_path_exists File.join @gemhome, 'cache', @spec.file_name - assert_path_exists File.join @gemhome, 'specifications', @spec.spec_name + assert File.exist?(File.join(@gemhome, 'cache', @spec.file_name)) + assert File.exist?(File.join(@gemhome, 'specifications', @spec.spec_name)) end def test_install_post_build_false @@ -864,10 +948,10 @@ gem 'other', version end spec_file = File.join @gemhome, 'specifications', @spec.spec_name - refute_path_exists spec_file + refute File.exist? spec_file gem_dir = File.join @gemhome, 'gems', @spec.full_name - refute_path_exists gem_dir + refute File.exist? gem_dir end def test_install_post_build_nil @@ -882,10 +966,10 @@ gem 'other', version end spec_file = File.join @gemhome, 'specifications', @spec.spec_name - assert_path_exists spec_file + assert File.exist? spec_file gem_dir = File.join @gemhome, 'gems', @spec.full_name - assert_path_exists gem_dir + assert File.exist? gem_dir end def test_install_pre_install_false @@ -906,7 +990,7 @@ gem 'other', version end spec_file = File.join @gemhome, 'specifications', @spec.spec_name - refute_path_exists spec_file + refute File.exist? spec_file end def test_install_pre_install_nil @@ -921,7 +1005,7 @@ gem 'other', version end spec_file = File.join @gemhome, 'specifications', @spec.spec_name - assert_path_exists spec_file + assert File.exist? spec_file end def test_install_with_message @@ -937,31 +1021,6 @@ gem 'other', version assert_match %r|I am a shiny gem!|, @ui.output end - def test_install_extension_install_dir - gemhome2 = "#{@gemhome}2" - - @spec.extensions << "extconf.rb" - write_file File.join(@tempdir, "extconf.rb") do |io| - io.write <<-RUBY - require "mkmf" - create_makefile("#{@spec.name}") - RUBY - end - - @spec.files += %w[extconf.rb] - - use_ui @ui do - path = Gem::Package.build @spec - - installer = Gem::Installer.new path, :install_dir => gemhome2 - installer.install - end - - expected_makefile = File.join gemhome2, 'gems', @spec.full_name, 'Makefile' - - assert_path_exists expected_makefile - end - def test_install_extension_and_script @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| @@ -988,16 +1047,16 @@ gem 'other', version RUBY end - refute_path_exists File.join @spec.gem_dir, rb - refute_path_exists File.join @spec.gem_dir, rb2 + assert !File.exist?(File.join(@spec.gem_dir, rb)) + assert !File.exist?(File.join(@spec.gem_dir, rb2)) use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.new path @installer.install end - assert_path_exists File.join @spec.gem_dir, rb - assert_path_exists File.join @spec.gem_dir, rb2 + assert File.exist?(File.join(@spec.gem_dir, rb)) + assert File.exist?(File.join(@spec.gem_dir, rb2)) end def test_install_extension_flat @@ -1026,14 +1085,14 @@ gem 'other', version } so = File.join(@spec.gem_dir, "#{@spec.name}.#{RbConfig::CONFIG["DLEXT"]}") - refute_path_exists so + assert !File.exist?(so) use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.new path @installer.install end - assert_path_exists so + assert File.exist?(so) rescue puts '-' * 78 puts File.read File.join(@gemhome, 'gems', 'a-2', 'Makefile') @@ -1278,11 +1337,11 @@ gem 'other', version @installer.unpack dest - assert_path_exists File.join dest, 'lib', 'code.rb' - assert_path_exists File.join dest, 'bin', 'executable' + assert File.exist?(File.join(dest, 'lib', 'code.rb')) + assert File.exist?(File.join(dest, 'bin', 'executable')) end - def test_write_build_info_file + def test_write_build_args refute_path_exists @spec.build_info_file @installer.build_args = %w[ @@ -1298,7 +1357,7 @@ gem 'other', version assert_equal expected, File.read(@spec.build_info_file) end - def test_write_build_info_file_empty + def test_write_build_args_empty refute_path_exists @spec.build_info_file @installer.write_build_info_file @@ -1338,20 +1397,20 @@ gem 'other', version def test_write_spec FileUtils.rm @spec.spec_file - refute_path_exists @spec.spec_file + refute File.exist?(@spec.spec_file) @installer.spec = @spec @installer.gem_home = @gemhome @installer.write_spec - assert_path_exists @spec.spec_file + assert File.exist?(@spec.spec_file) assert_equal @spec, eval(File.read(@spec.spec_file)) end def test_write_spec_writes_cached_spec FileUtils.rm @spec.spec_file - refute_path_exists @spec.spec_file + refute File.exist?(@spec.spec_file) @spec.files = %w[a.rb b.rb c.rb] @@ -1370,30 +1429,6 @@ gem 'other', version assert_match %r!/gemhome/gems/a-2$!, @installer.dir end - def test_default_gem - FileUtils.rm_f File.join(Gem.dir, 'specifications') - - @installer.wrappers = true - @installer.options[:install_as_default] = true - @installer.gem_dir = util_gem_dir @spec - @installer.generate_bin - - use_ui @ui do - @installer.install - end - - assert File.directory? util_inst_bindir - installed_exec = File.join util_inst_bindir, 'executable' - assert_path_exists installed_exec - - assert File.directory? File.join(Gem.dir, 'specifications') - assert File.directory? File.join(Gem.dir, 'specifications', 'default') - - default_spec = eval File.read File.join(Gem.dir, 'specifications', 'default', 'a-2.gemspec') - assert_equal Gem::Version.new("2"), default_spec.version - assert_equal ['bin/executable'], default_spec.files - end - def old_ruby_required spec = quick_spec 'old_ruby_required', '1' do |s| s.required_ruby_version = '= 1.4.6' diff --git a/test/rubygems/test_gem_name_tuple.rb b/test/rubygems/test_gem_name_tuple.rb index 170a9c2ae0..62b4801f71 100644 --- a/test/rubygems/test_gem_name_tuple.rb +++ b/test/rubygems/test_gem_name_tuple.rb @@ -2,21 +2,6 @@ require 'rubygems/test_case' require 'rubygems/name_tuple' class TestGemNameTuple < Gem::TestCase - - def test_full_name - n = Gem::NameTuple.new "a", Gem::Version.new(0), "ruby" - assert_equal "a-0", n.full_name - - n = Gem::NameTuple.new "a", Gem::Version.new(0), nil - assert_equal "a-0", n.full_name - - n = Gem::NameTuple.new "a", Gem::Version.new(0), "" - assert_equal "a-0", n.full_name - - n = Gem::NameTuple.new "a", Gem::Version.new(0), "other" - assert_equal "a-0-other", n.full_name - end - def test_platform_normalization n = Gem::NameTuple.new "a", Gem::Version.new(0), "ruby" assert_equal "ruby", n.platform @@ -27,11 +12,4 @@ class TestGemNameTuple < Gem::TestCase n = Gem::NameTuple.new "a", Gem::Version.new(0), "" assert_equal "ruby", n.platform end - - def test_spec_name - n = Gem::NameTuple.new "a", Gem::Version.new(0), "ruby" - assert_equal "a-0.gemspec", n.spec_name - end - end - diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb index af5319a150..c77fc47ada 100644 --- a/test/rubygems/test_gem_package.rb +++ b/test/rubygems/test_gem_package.rb @@ -87,19 +87,16 @@ class TestGemPackage < Gem::Package::TarTestCase metadata_sha512 = Digest::SHA512.hexdigest s.string expected = { + 'SHA1' => { + 'metadata.gz' => metadata_sha1, + 'data.tar.gz' => Digest::SHA1.hexdigest(tar), + }, 'SHA512' => { 'metadata.gz' => metadata_sha512, 'data.tar.gz' => Digest::SHA512.hexdigest(tar), } } - if defined?(OpenSSL::Digest) then - expected['SHA1'] = { - 'metadata.gz' => metadata_sha1, - 'data.tar.gz' => Digest::SHA1.hexdigest(tar), - } - end - assert_equal expected, YAML.load(checksums) end @@ -163,57 +160,12 @@ class TestGemPackage < Gem::Package::TarTestCase end def test_build_auto_signed - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - FileUtils.mkdir_p File.join(Gem.user_home, '.gem') private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' Gem::Security.write PRIVATE_KEY, private_key_path public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' - FileUtils.cp PUBLIC_CERT_PATH, public_cert_path - - spec = Gem::Specification.new 'build', '1' - spec.summary = 'build' - spec.authors = 'build' - spec.files = ['lib/code.rb'] - - FileUtils.mkdir 'lib' - - open 'lib/code.rb', 'w' do |io| - io.write '# lib/code.rb' - end - - package = Gem::Package.new spec.file_name - package.spec = spec - - package.build - - assert_equal Gem::VERSION, spec.rubygems_version - assert_path_exists spec.file_name - - reader = Gem::Package.new spec.file_name - assert reader.verify - - assert_equal [PUBLIC_CERT.to_pem], reader.spec.cert_chain - - assert_equal %w[metadata.gz metadata.gz.sig - data.tar.gz data.tar.gz.sig - checksums.yaml.gz checksums.yaml.gz.sig], - reader.files - - assert_equal %w[lib/code.rb], reader.contents - end - - def test_build_auto_signed_encrypted_key - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - - FileUtils.mkdir_p File.join(Gem.user_home, '.gem') - - private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' - FileUtils.cp ENCRYPTED_PRIVATE_KEY_PATH, private_key_path - - public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' Gem::Security.write PUBLIC_CERT, public_cert_path spec = Gem::Specification.new 'build', '1' @@ -262,8 +214,6 @@ class TestGemPackage < Gem::Package::TarTestCase end def test_build_signed - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - spec = Gem::Specification.new 'build', '1' spec.summary = 'build' spec.authors = 'build' @@ -298,43 +248,6 @@ class TestGemPackage < Gem::Package::TarTestCase assert_equal %w[lib/code.rb], reader.contents end - def test_build_signed_encryped_key - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - - spec = Gem::Specification.new 'build', '1' - spec.summary = 'build' - spec.authors = 'build' - spec.files = ['lib/code.rb'] - spec.cert_chain = [PUBLIC_CERT.to_pem] - spec.signing_key = ENCRYPTED_PRIVATE_KEY - - FileUtils.mkdir 'lib' - - open 'lib/code.rb', 'w' do |io| - io.write '# lib/code.rb' - end - - package = Gem::Package.new spec.file_name - package.spec = spec - - package.build - - assert_equal Gem::VERSION, spec.rubygems_version - assert_path_exists spec.file_name - - reader = Gem::Package.new spec.file_name - assert reader.verify - - assert_equal spec, reader.spec - - assert_equal %w[metadata.gz metadata.gz.sig - data.tar.gz data.tar.gz.sig - checksums.yaml.gz checksums.yaml.gz.sig], - reader.files - - assert_equal %w[lib/code.rb], reader.contents - end - def test_contents package = Gem::Package.new @gem @@ -396,19 +309,6 @@ class TestGemPackage < Gem::Package::TarTestCase "#{@destination} is not allowed", e.message) end - def test_extract_tar_gz_dot_slash - package = Gem::Package.new @gem - - tgz_io = util_tar_gz do |tar| - tar.add_file './dot_slash.rb', 0644 do |io| io.write 'hi' end - end - - package.extract_tar_gz tgz_io, @destination - - extracted = File.join @destination, 'dot_slash.rb' - assert_path_exists extracted - end - def test_install_location package = Gem::Package.new @gem @@ -544,7 +444,7 @@ class TestGemPackage < Gem::Package::TarTestCase io.write metadata_gz end - digest = Digest::SHA1.new + digest = OpenSSL::Digest::SHA1.new digest << metadata_gz checksums = { @@ -576,8 +476,7 @@ class TestGemPackage < Gem::Package::TarTestCase def test_verify_corrupt Tempfile.open 'corrupt' do |io| data = Gem.gzip 'a' * 10 - io.write \ - tar_file_header('metadata.gz', "\000x", 0644, data.length, Time.now) + io.write tar_file_header('metadata.gz', "\000x", 0644, data.length) io.write data io.rewind @@ -616,8 +515,6 @@ class TestGemPackage < Gem::Package::TarTestCase end def test_verify_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - package = Gem::Package.new @gem package.security_policy = Gem::Security::HighSecurity @@ -633,8 +530,6 @@ class TestGemPackage < Gem::Package::TarTestCase end def test_verify_security_policy_low_security - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @spec.cert_chain = [PUBLIC_CERT.to_pem] @spec.signing_key = PRIVATE_KEY @@ -653,8 +548,6 @@ class TestGemPackage < Gem::Package::TarTestCase end def test_verify_security_policy_checksum_missing - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @spec.cert_chain = [PUBLIC_CERT.to_pem] @spec.signing_key = PRIVATE_KEY @@ -710,21 +603,6 @@ class TestGemPackage < Gem::Package::TarTestCase e.message end - # end #verify tests - - def test_verify_entry - entry = Object.new - def entry.full_name() raise ArgumentError, 'whatever' end - - package = Gem::Package.new @gem - - e = assert_raises Gem::Package::FormatError do - package.verify_entry entry - end - - assert_equal "package is corrupt, exception while verifying: whatever (ArgumentError) in #{@gem}", e.message - end - def test_spec package = Gem::Package.new @gem diff --git a/test/rubygems/test_gem_package_old.rb b/test/rubygems/test_gem_package_old.rb index 6236dbbaf2..05f7ae3dec 100644 --- a/test/rubygems/test_gem_package_old.rb +++ b/test/rubygems/test_gem_package_old.rb @@ -21,8 +21,6 @@ class TestGemPackageOld < Gem::TestCase end def test_contents_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @package.security_policy = Gem::Security::AlmostNoSecurity assert_raises Gem::Security::Exception do @@ -42,8 +40,6 @@ class TestGemPackageOld < Gem::TestCase end def test_extract_files_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @package.security_policy = Gem::Security::AlmostNoSecurity assert_raises Gem::Security::Exception do @@ -56,8 +52,6 @@ class TestGemPackageOld < Gem::TestCase end def test_spec_security_policy - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - @package.security_policy = Gem::Security::AlmostNoSecurity assert_raises Gem::Security::Exception do @@ -66,8 +60,6 @@ class TestGemPackageOld < Gem::TestCase end def test_verify - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - assert @package.verify @package.security_policy = Gem::Security::NoSecurity diff --git a/test/rubygems/test_gem_package_tar_reader.rb b/test/rubygems/test_gem_package_tar_reader.rb index 5e0474c253..d1af22d3be 100644 --- a/test/rubygems/test_gem_package_tar_reader.rb +++ b/test/rubygems/test_gem_package_tar_reader.rb @@ -4,8 +4,8 @@ require 'rubygems/package' class TestGemPackageTarReader < Gem::Package::TarTestCase def test_each_entry - tar = tar_dir_header "foo", "bar", 0, Time.now - tar << tar_file_header("bar", "baz", 0, 0, Time.now) + tar = tar_dir_header "foo", "bar", 0 + tar << tar_file_header("bar", "baz", 0, 0) io = TempIO.new tar @@ -25,9 +25,8 @@ class TestGemPackageTarReader < Gem::Package::TarTestCase def test_rewind content = ('a'..'z').to_a.join(" ") - str = - tar_file_header("lib/foo", "", 010644, content.size, Time.now) + - content + "\0" * (512 - content.size) + str = tar_file_header("lib/foo", "", 010644, content.size) + content + + "\0" * (512 - content.size) str << "\0" * 1024 Gem::Package::TarReader.new(TempIO.new(str)) do |tar_reader| @@ -44,8 +43,8 @@ class TestGemPackageTarReader < Gem::Package::TarTestCase end def test_seek - tar = tar_dir_header "foo", "bar", 0, Time.now - tar << tar_file_header("bar", "baz", 0, 0, Time.now) + tar = tar_dir_header "foo", "bar", 0 + tar << tar_file_header("bar", "baz", 0, 0) io = TempIO.new tar @@ -61,8 +60,8 @@ class TestGemPackageTarReader < Gem::Package::TarTestCase end def test_seek_missing - tar = tar_dir_header "foo", "bar", 0, Time.now - tar << tar_file_header("bar", "baz", 0, 0, Time.now) + tar = tar_dir_header "foo", "bar", 0 + tar << tar_file_header("bar", "baz", 0, 0) io = TempIO.new tar diff --git a/test/rubygems/test_gem_package_tar_reader_entry.rb b/test/rubygems/test_gem_package_tar_reader_entry.rb index 3c1bf7291a..92da220fa6 100644 --- a/test/rubygems/test_gem_package_tar_reader_entry.rb +++ b/test/rubygems/test_gem_package_tar_reader_entry.rb @@ -9,7 +9,7 @@ class TestGemPackageTarReaderEntry < Gem::Package::TarTestCase @contents = ('a'..'z').to_a.join * 100 @tar = '' - @tar << tar_file_header("lib/foo", "", 0, @contents.size, Time.now) + @tar << tar_file_header("lib/foo", "", 0, @contents.size) @tar << @contents @tar << "\0" * (512 - (@tar.size % 512)) diff --git a/test/rubygems/test_gem_package_tar_writer.rb b/test/rubygems/test_gem_package_tar_writer.rb index 2505d7ced1..40c6982929 100644 --- a/test/rubygems/test_gem_package_tar_writer.rb +++ b/test/rubygems/test_gem_package_tar_writer.rb @@ -1,6 +1,5 @@ require 'rubygems/package/tar_test_case' require 'rubygems/package/tar_writer' -require 'minitest/mock' class TestGemPackageTarWriter < Gem::Package::TarTestCase @@ -19,130 +18,112 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase end def test_add_file - Time.stub :now, Time.at(1458518157) do - @tar_writer.add_file 'x', 0644 do |f| f.write 'a' * 10 end + @tar_writer.add_file 'x', 0644 do |f| f.write 'a' * 10 end - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), + assert_headers_equal(tar_file_header('x', '', 0644, 10), @io.string[0, 512]) - end assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] assert_equal 1024, @io.pos end def test_add_file_digest - digest_algorithms = Digest::SHA1, Digest::SHA512 + digest_algorithms = OpenSSL::Digest::SHA1, OpenSSL::Digest::SHA512 - Time.stub :now, Time.at(1458518157) do - digests = @tar_writer.add_file_digest 'x', 0644, digest_algorithms do |io| - io.write 'a' * 10 - end + digests = @tar_writer.add_file_digest 'x', 0644, digest_algorithms do |io| + io.write 'a' * 10 + end - assert_equal '3495ff69d34671d1e15b33a63c1379fdedd3a32a', - digests['SHA1'].hexdigest - assert_equal '4714870aff6c97ca09d135834fdb58a6389a50c1' \ - '1fef8ec4afef466fb60a23ac6b7a9c92658f14df' \ - '4993d6b40a4e4d8424196afc347e97640d68de61' \ - 'e1cf14b0', - digests['SHA512'].hexdigest + assert_equal '3495ff69d34671d1e15b33a63c1379fdedd3a32a', + digests['SHA1'].hexdigest + assert_equal '4714870aff6c97ca09d135834fdb58a6389a50c1' \ + '1fef8ec4afef466fb60a23ac6b7a9c92658f14df' \ + '4993d6b40a4e4d8424196afc347e97640d68de61' \ + 'e1cf14b0', + digests['SHA512'].hexdigest - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), + assert_headers_equal(tar_file_header('x', '', 0644, 10), @io.string[0, 512]) - end assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] assert_equal 1024, @io.pos end def test_add_file_digest_multiple - digest_algorithms = [Digest::SHA1, Digest::SHA512] + digest_algorithms = [OpenSSL::Digest::SHA1, OpenSSL::Digest::SHA512] - Time.stub :now, Time.at(1458518157) do - digests = @tar_writer.add_file_digest 'x', 0644, digest_algorithms do |io| - io.write 'a' * 10 - end + digests = @tar_writer.add_file_digest 'x', 0644, digest_algorithms do |io| + io.write 'a' * 10 + end - assert_equal '3495ff69d34671d1e15b33a63c1379fdedd3a32a', - digests['SHA1'].hexdigest - assert_equal '4714870aff6c97ca09d135834fdb58a6389a50c1' \ - '1fef8ec4afef466fb60a23ac6b7a9c92658f14df' \ - '4993d6b40a4e4d8424196afc347e97640d68de61' \ - 'e1cf14b0', - digests['SHA512'].hexdigest + assert_equal '3495ff69d34671d1e15b33a63c1379fdedd3a32a', + digests['SHA1'].hexdigest + assert_equal '4714870aff6c97ca09d135834fdb58a6389a50c1' \ + '1fef8ec4afef466fb60a23ac6b7a9c92658f14df' \ + '4993d6b40a4e4d8424196afc347e97640d68de61' \ + 'e1cf14b0', + digests['SHA512'].hexdigest - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), - @io.string[0, 512]) - end + assert_headers_equal(tar_file_header('x', '', 0644, 10), + @io.string[0, 512]) assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] assert_equal 1024, @io.pos end def test_add_file_signer - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - signer = Gem::Security::Signer.new PRIVATE_KEY, [PUBLIC_CERT] - Time.stub :now, Time.at(1458518157) do - @tar_writer.add_file_signed 'x', 0644, signer do |io| - io.write 'a' * 10 - end - - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), - @io.string[0, 512]) - - - assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] + @tar_writer.add_file_signed 'x', 0644, signer do |io| + io.write 'a' * 10 + end - digest = signer.digest_algorithm.new - digest.update 'a' * 10 + assert_headers_equal(tar_file_header('x', '', 0644, 10), + @io.string[0, 512]) + assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] - signature = signer.sign digest.digest + digest = signer.digest_algorithm.new + digest.update 'a' * 10 - assert_headers_equal(tar_file_header('x.sig', '', 0444, signature.length, - Time.now), - @io.string[1024, 512]) - assert_equal "#{signature}#{"\0" * (512 - signature.length)}", - @io.string[1536, 512] + signature = signer.sign digest.digest - assert_equal 2048, @io.pos - end + assert_headers_equal(tar_file_header('x.sig', '', 0444, signature.length), + @io.string[1024, 512]) + assert_equal "#{signature}#{"\0" * (512 - signature.length)}", + @io.string[1536, 512] + assert_equal 2048, @io.pos end def test_add_file_signer_empty signer = Gem::Security::Signer.new nil, nil - Time.stub :now, Time.at(1458518157) do - - @tar_writer.add_file_signed 'x', 0644, signer do |io| - io.write 'a' * 10 - end + @tar_writer.add_file_signed 'x', 0644, signer do |io| + io.write 'a' * 10 + end - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), + assert_headers_equal(tar_file_header('x', '', 0644, 10), @io.string[0, 512]) - end assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] + digest = signer.digest_algorithm.new + digest.update 'a' * 10 + assert_equal 1024, @io.pos end def test_add_file_simple - Time.stub :now, Time.at(1458518157) do - @tar_writer.add_file_simple 'x', 0644, 10 do |io| io.write "a" * 10 end + @tar_writer.add_file_simple 'x', 0644, 10 do |io| io.write "a" * 10 end - assert_headers_equal(tar_file_header('x', '', 0644, 10, Time.now), + assert_headers_equal(tar_file_header('x', '', 0644, 10), @io.string[0, 512]) - end assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512] assert_equal 1024, @io.pos end def test_add_file_simple_padding - Time.stub :now, Time.at(1458518157) do - @tar_writer.add_file_simple 'x', 0, 100 + @tar_writer.add_file_simple 'x', 0, 100 - assert_headers_equal tar_file_header('x', '', 0, 100, Time.now), + assert_headers_equal tar_file_header('x', '', 0, 100), @io.string[0, 512] - end assert_equal "\0" * 512, @io.string[512, 512] end @@ -201,14 +182,11 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase end def test_mkdir - Time.stub :now, Time.at(1458518157) do - @tar_writer.mkdir 'foo', 0644 + @tar_writer.mkdir 'foo', 0644 - assert_headers_equal tar_dir_header('foo', '', 0644, Time.now), - @io.string[0, 512] - - assert_equal 512, @io.pos - end + assert_headers_equal tar_dir_header('foo', '', 0644), + @io.string[0, 512] + assert_equal 512, @io.pos end def test_split_name diff --git a/test/rubygems/test_gem_path_support.rb b/test/rubygems/test_gem_path_support.rb index 879cc98b5f..bffc66f7dc 100644 --- a/test/rubygems/test_gem_path_support.rb +++ b/test/rubygems/test_gem_path_support.rb @@ -64,21 +64,4 @@ class TestGemPathSupport < Gem::TestCase def util_path ENV["GEM_PATH"].split(File::PATH_SEPARATOR) end - - def test_initialize_spec - ENV["GEM_SPEC_CACHE"] = nil - - ps = Gem::PathSupport.new - assert_equal Gem.default_spec_cache_dir, ps.spec_cache_dir - - ENV["GEM_SPEC_CACHE"] = 'bar' - - ps = Gem::PathSupport.new - assert_equal ENV["GEM_SPEC_CACHE"], ps.spec_cache_dir - - ENV["GEM_SPEC_CACHE"] = File.join @tempdir, 'spec_cache' - - ps = Gem::PathSupport.new "GEM_SPEC_CACHE" => "foo" - assert_equal "foo", ps.spec_cache_dir - end end diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb index 5966710dad..1112a013f5 100644 --- a/test/rubygems/test_gem_platform.rb +++ b/test/rubygems/test_gem_platform.rb @@ -186,24 +186,6 @@ class TestGemPlatform < Gem::TestCase assert((x86_darwin8 === Gem::Platform.local), 'universal =~ x86') end - def test_equals3_cpu_arm - arm = Gem::Platform.new 'arm-linux' - armv5 = Gem::Platform.new 'armv5-linux' - armv7 = Gem::Platform.new 'armv7-linux' - - util_set_arch 'armv5-linux' - assert((arm === Gem::Platform.local), 'arm === armv5') - assert((armv5 === Gem::Platform.local), 'armv5 === armv5') - refute((armv7 === Gem::Platform.local), 'armv7 === armv5') - refute((Gem::Platform.local === arm), 'armv5 === arm') - - util_set_arch 'armv7-linux' - assert((arm === Gem::Platform.local), 'arm === armv7') - refute((armv5 === Gem::Platform.local), 'armv5 === armv7') - assert((armv7 === Gem::Platform.local), 'armv7 === armv7') - refute((Gem::Platform.local === arm), 'armv7 === arm') - end - def test_equals3_version util_set_arch 'i686-darwin8' diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index fe6da708b6..d3cc388db4 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -1,13 +1,7 @@ require 'rubygems/test_case' - +require 'ostruct' require 'webrick' -begin - require 'webrick/https' -rescue LoadError => e - raise unless (e.respond_to?(:path) && e.path == 'openssl') || - e.message =~ / -- openssl$/ -end - +require 'webrick/https' require 'rubygems/remote_fetcher' require 'rubygems/package' require 'minitest/mock' @@ -134,7 +128,19 @@ gems: refute_nil fetcher assert_kind_of Gem::RemoteFetcher, fetcher - assert_equal proxy_uri, fetcher.instance_variable_get(:@proxy).to_s + assert_equal proxy_uri, fetcher.instance_variable_get(:@proxy_uri).to_s + end + + def test_self_fetcher_with_proxy_URI + proxy_uri = URI.parse 'http://proxy.example.com' + Gem.configuration[:http_proxy] = proxy_uri + Gem::RemoteFetcher.fetcher = nil + + fetcher = Gem::RemoteFetcher.fetcher + refute_nil fetcher + + assert_kind_of Gem::RemoteFetcher, fetcher + assert_equal proxy_uri, fetcher.instance_variable_get(:@proxy_uri) end def test_fetch_size_bad_uri @@ -149,7 +155,7 @@ gems: def test_fetch_size_socket_error fetcher = Gem::RemoteFetcher.new nil - def fetcher.request(uri, request_class, last_modified = nil) + def fetcher.connection_for(uri) raise SocketError, "tarded" end @@ -408,6 +414,70 @@ gems: assert_equal @a2.file_name, File.basename(gem) end + def test_explicit_proxy + use_ui @ui do + fetcher = Gem::RemoteFetcher.new @proxy_uri + assert_equal PROXY_DATA.size, fetcher.fetch_size(@server_uri) + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + end + + def test_explicit_proxy_with_user_auth + use_ui @ui do + uri = URI.parse @proxy_uri + uri.user, uri.password = 'foo', 'bar' + fetcher = Gem::RemoteFetcher.new uri.to_s + proxy = fetcher.instance_variable_get("@proxy_uri") + assert_equal 'foo', proxy.user + assert_equal 'bar', proxy.password + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + + use_ui @ui do + uri = URI.parse @proxy_uri + uri.user, uri.password = 'domain%5Cuser', 'bar' + fetcher = Gem::RemoteFetcher.new uri.to_s + proxy = fetcher.instance_variable_get("@proxy_uri") + assert_equal 'domain\user', fetcher.unescape(proxy.user) + assert_equal 'bar', proxy.password + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + + use_ui @ui do + uri = URI.parse @proxy_uri + uri.user, uri.password = 'user', 'my%20pass' + fetcher = Gem::RemoteFetcher.new uri.to_s + proxy = fetcher.instance_variable_get("@proxy_uri") + assert_equal 'user', proxy.user + assert_equal 'my pass', fetcher.unescape(proxy.password) + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + end + + def test_explicit_proxy_with_user_auth_in_env + use_ui @ui do + ENV['http_proxy'] = @proxy_uri + ENV['http_proxy_user'] = 'foo' + ENV['http_proxy_pass'] = 'bar' + fetcher = Gem::RemoteFetcher.new nil + proxy = fetcher.instance_variable_get("@proxy_uri") + assert_equal 'foo', proxy.user + assert_equal 'bar', proxy.password + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + + use_ui @ui do + ENV['http_proxy'] = @proxy_uri + ENV['http_proxy_user'] = 'foo\user' + ENV['http_proxy_pass'] = 'my bar' + fetcher = Gem::RemoteFetcher.new nil + proxy = fetcher.instance_variable_get("@proxy_uri") + assert_equal 'foo\user', fetcher.unescape(proxy.user) + assert_equal 'my bar', fetcher.unescape(proxy.password) + assert_data_from_proxy fetcher.fetch_path(@server_uri) + end + end + def test_fetch_path_gzip fetcher = Gem::RemoteFetcher.new nil @@ -490,6 +560,22 @@ gems: assert_equal nil, fetcher.fetch_path(URI.parse(@gem_repo), Time.at(0)) end + def test_get_proxy_from_env_auto_normalizes + fetcher = Gem::RemoteFetcher.new(nil) + ENV['HTTP_PROXY'] = 'fakeurl:12345' + + assert_equal('http://fakeurl:12345', fetcher.get_proxy_from_env.to_s) + end + + def test_get_proxy_from_env_empty + ENV['HTTP_PROXY'] = '' + ENV.delete 'http_proxy' + + fetcher = Gem::RemoteFetcher.new nil + + assert_equal nil, fetcher.send(:get_proxy_from_env) + end + def test_implicit_no_proxy use_ui @ui do ENV['http_proxy'] = 'http://fakeurl:12345' @@ -525,7 +611,9 @@ gems: fetcher = Gem::RemoteFetcher.new nil url = 'http://gems.example.com/redirect' - def fetcher.request(uri, request_class, last_modified = nil) + conn = Object.new + def conn.started?() true end + def conn.request(req) url = 'http://gems.example.com/redirect' unless defined? @requested then @requested = true @@ -539,6 +627,9 @@ gems: end end + conn = { "#{Thread.current.object_id}:gems.example.com:80" => conn } + fetcher.instance_variable_set :@connections, conn + data = fetcher.fetch_http URI.parse(url) assert_equal 'real_path', data @@ -548,13 +639,18 @@ gems: fetcher = Gem::RemoteFetcher.new nil url = 'http://gems.example.com/redirect' - def fetcher.request(uri, request_class, last_modified = nil) + conn = Object.new + def conn.started?() true end + def conn.request(req) url = 'http://gems.example.com/redirect' res = Net::HTTPMovedPermanently.new nil, 301, nil res.add_field 'Location', url res end + conn = { "#{Thread.current.object_id}:gems.example.com:80" => conn } + fetcher.instance_variable_set :@connections, conn + e = assert_raises Gem::RemoteFetcher::FetchError do fetcher.fetch_http URI.parse(url) end @@ -562,6 +658,14 @@ gems: assert_equal "too many redirects (#{url})", e.message end + def test_normalize_uri + assert_equal 'FILE://example/', @fetcher.normalize_uri('FILE://example/') + assert_equal 'FTP://example/', @fetcher.normalize_uri('FTP://example/') + assert_equal 'HTTP://example/', @fetcher.normalize_uri('HTTP://example/') + assert_equal 'HTTPS://example/', @fetcher.normalize_uri('HTTPS://example/') + assert_equal 'http://example/', @fetcher.normalize_uri('example/') + end + def test_observe_no_proxy_env_single_host use_ui @ui do ENV["http_proxy"] = @proxy_uri @@ -580,15 +684,115 @@ gems: end end - def test_request_block - fetcher = Gem::RemoteFetcher.new nil + def test_request + uri = URI.parse "#{@gem_repo}/specs.#{Gem.marshal_version}" + util_stub_connection_for :body => :junk, :code => 200 - assert_throws :block_called do - fetcher.request URI('http://example'), Net::HTTP::Get do |req| - assert_kind_of Net::HTTPGenericRequest, req - throw :block_called - end - end + response = @fetcher.request uri, Net::HTTP::Get + + assert_equal 200, response.code + assert_equal :junk, response.body + end + + def test_request_head + uri = URI.parse "#{@gem_repo}/specs.#{Gem.marshal_version}" + util_stub_connection_for :body => '', :code => 200 + response = @fetcher.request uri, Net::HTTP::Head + + assert_equal 200, response.code + assert_equal '', response.body + end + + def test_request_unmodified + uri = URI.parse "#{@gem_repo}/specs.#{Gem.marshal_version}" + conn = util_stub_connection_for :body => '', :code => 304 + + t = Time.now + response = @fetcher.request uri, Net::HTTP::Head, t + + assert_equal 304, response.code + assert_equal '', response.body + + assert_equal t.rfc2822, conn.payload['if-modified-since'] + end + + def test_user_agent + ua = @fetcher.user_agent + + assert_match %r%^RubyGems/\S+ \S+ Ruby/\S+ \(.*?\)%, ua + assert_match %r%RubyGems/#{Regexp.escape Gem::VERSION}%, ua + assert_match %r% #{Regexp.escape Gem::Platform.local.to_s} %, ua + assert_match %r%Ruby/#{Regexp.escape RUBY_VERSION}%, ua + assert_match %r%\(#{Regexp.escape RUBY_RELEASE_DATE} %, ua + end + + def test_user_agent_engine + util_save_version + + Object.send :remove_const, :RUBY_ENGINE if defined?(RUBY_ENGINE) + Object.send :const_set, :RUBY_ENGINE, 'vroom' + + ua = @fetcher.user_agent + + assert_match %r%\) vroom%, ua + ensure + util_restore_version + end + + def test_user_agent_engine_ruby + util_save_version + + Object.send :remove_const, :RUBY_ENGINE if defined?(RUBY_ENGINE) + Object.send :const_set, :RUBY_ENGINE, 'ruby' + + ua = @fetcher.user_agent + + assert_match %r%\)%, ua + ensure + util_restore_version + end + + def test_user_agent_patchlevel + util_save_version + + Object.send :remove_const, :RUBY_PATCHLEVEL + Object.send :const_set, :RUBY_PATCHLEVEL, 5 + + ua = @fetcher.user_agent + + assert_match %r% patchlevel 5\)%, ua + ensure + util_restore_version + end + + def test_user_agent_revision + util_save_version + + Object.send :remove_const, :RUBY_PATCHLEVEL + Object.send :const_set, :RUBY_PATCHLEVEL, -1 + Object.send :remove_const, :RUBY_REVISION if defined?(RUBY_REVISION) + Object.send :const_set, :RUBY_REVISION, 6 + + ua = @fetcher.user_agent + + assert_match %r% revision 6\)%, ua + assert_match %r%Ruby/#{Regexp.escape RUBY_VERSION}dev%, ua + ensure + util_restore_version + end + + def test_user_agent_revision_missing + util_save_version + + Object.send :remove_const, :RUBY_PATCHLEVEL + Object.send :const_set, :RUBY_PATCHLEVEL, -1 + Object.send :remove_const, :RUBY_REVISION if defined?(RUBY_REVISION) + + ua = @fetcher.user_agent + + assert_match %r%\(#{Regexp.escape RUBY_RELEASE_DATE}\)%, ua + ensure + util_restore_version end def test_yaml_error_on_size @@ -607,42 +811,6 @@ gems: end end - def test_ssl_client_cert_auth_connection - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - - ssl_server = self.class.start_ssl_server({ - :SSLVerifyClient => - OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT}) - - temp_ca_cert = File.join(DIR, 'ca_cert.pem') - temp_client_cert = File.join(DIR, 'client.pem') - - with_configured_fetcher( - ":ssl_ca_cert: #{temp_ca_cert}\n" + - ":ssl_client_cert: #{temp_client_cert}\n") do |fetcher| - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - - def test_do_not_allow_invalid_client_cert_auth_connection - skip 'openssl is missing' unless defined?(OpenSSL::SSL) - - ssl_server = self.class.start_ssl_server({ - :SSLVerifyClient => - OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT}) - - temp_ca_cert = File.join(DIR, 'ca_cert.pem') - temp_client_cert = File.join(DIR, 'invalid_client.pem') - - with_configured_fetcher( - ":ssl_ca_cert: #{temp_ca_cert}\n" + - ":ssl_client_cert: #{temp_client_cert}\n") do |fetcher| - assert_raises Gem::RemoteFetcher::FetchError do - fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml") - end - end - end - def test_do_not_allow_insecure_ssl_connection_by_default ssl_server = self.class.start_ssl_server with_configured_fetcher do |fetcher| @@ -682,6 +850,18 @@ gems: Gem.configuration = nil end + def util_stub_connection_for hash + def @fetcher.connection= conn + @conn = conn + end + + def @fetcher.connection_for uri + @conn + end + + @fetcher.connection = Conn.new OpenStruct.new(hash) + end + def assert_error(exception_class=Exception) got_exception = false @@ -702,6 +882,20 @@ gems: assert_match(/0\.4\.2/, data, "Data is not from proxy") end + class Conn + attr_accessor :payload + + def initialize(response) + @response = response + self.payload = nil + end + + def request(req) + self.payload = req + @response + end + end + class NilLog < WEBrick::Log def log(level, data) #Do nothing end @@ -719,11 +913,9 @@ gems: end DIR = File.expand_path(File.dirname(__FILE__)) + DH_PARAM = OpenSSL::PKey::DH.new(128) def start_ssl_server(config = {}) - raise MiniTest::Skip, 'openssl not installed' unless - defined?(OpenSSL::SSL) - null_logger = NilLog.new server = WEBrick::HTTPServer.new({ :Port => 0, @@ -742,7 +934,7 @@ gems: server.mount_proc("/insecure_redirect") { |req, res| res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, req.query['to']) } - server.ssl_context.tmp_dh_callback = proc { OpenSSL::PKey::DH.new 128 } + server.ssl_context.tmp_dh_callback = proc { DH_PARAM } t = Thread.new do begin server.start @@ -761,6 +953,8 @@ gems: server end + + private def start_server(port, data) @@ -821,5 +1015,24 @@ gems: assert_equal "/home/skillet", @fetcher.correct_for_windows_path(path) end + def util_save_version + @orig_RUBY_ENGINE = RUBY_ENGINE if defined? RUBY_ENGINE + @orig_RUBY_PATCHLEVEL = RUBY_PATCHLEVEL + @orig_RUBY_REVISION = RUBY_REVISION if defined? RUBY_REVISION + end + + def util_restore_version + Object.send :remove_const, :RUBY_ENGINE if defined?(RUBY_ENGINE) + Object.send :const_set, :RUBY_ENGINE, @orig_RUBY_ENGINE if + defined?(@orig_RUBY_ENGINE) + + Object.send :remove_const, :RUBY_PATCHLEVEL + Object.send :const_set, :RUBY_PATCHLEVEL, @orig_RUBY_PATCHLEVEL + + Object.send :remove_const, :RUBY_REVISION if defined?(RUBY_REVISION) + Object.send :const_set, :RUBY_REVISION, @orig_RUBY_REVISION if + defined?(@orig_RUBY_REVISION) + end + end diff --git a/test/rubygems/test_gem_security.rb b/test/rubygems/test_gem_security.rb index b8747b79c3..737881d7bc 100644 --- a/test/rubygems/test_gem_security.rb +++ b/test/rubygems/test_gem_security.rb @@ -2,10 +2,6 @@ require 'rubygems/test_case' require 'rubygems/security' require 'rubygems/fix_openssl_warnings' if RUBY_VERSION < "1.9" -unless defined?(OpenSSL::SSL) then - warn 'Skipping Gem::Security tests. openssl not found.' -end - class TestGemSecurity < Gem::TestCase CHILD_KEY = load_key 'child' @@ -99,7 +95,7 @@ class TestGemSecurity < Gem::TestCase end def test_class_create_key - key = @SEC.create_key 1024 + key = @SEC.create_key 256 assert_kind_of OpenSSL::PKey::RSA, key end @@ -250,57 +246,5 @@ class TestGemSecurity < Gem::TestCase assert_equal expected, trust_dir.dir end - def test_class_write - key = @SEC.create_key 1024 - - path = File.join @tempdir, 'test-private_key.pem' - - @SEC.write key, path - - assert_path_exists path - - key_from_file = File.read path - - assert_equal key.to_pem, key_from_file - end - - def test_class_write_encrypted - key = @SEC.create_key 1024 - - path = File.join @tempdir, 'test-private_encrypted_key.pem' - - passphrase = 'It should be long.' - - @SEC.write key, path, 0600, passphrase - - assert_path_exists path - - key_from_file = OpenSSL::PKey::RSA.new File.read(path), passphrase - - assert_equal key.to_pem, key_from_file.to_pem - end - - def test_class_write_encrypted_cipher - key = @SEC.create_key 1024 - - path = File.join @tempdir, 'test-private_encrypted__with_non_default_cipher_key.pem' - - passphrase = 'It should be long.' - - cipher = OpenSSL::Cipher.new 'AES-192-CBC' - - @SEC.write key, path, 0600, passphrase, cipher - - assert_path_exists path - - key_file_contents = File.read(path) - - assert key_file_contents.split("\n")[2].match(cipher.name) - - key_from_file = OpenSSL::PKey::RSA.new key_file_contents, passphrase - - assert_equal key.to_pem, key_from_file.to_pem - end - -end if defined?(OpenSSL::SSL) +end diff --git a/test/rubygems/test_gem_security_policy.rb b/test/rubygems/test_gem_security_policy.rb index a2115e709a..1ce93fbd95 100644 --- a/test/rubygems/test_gem_security_policy.rb +++ b/test/rubygems/test_gem_security_policy.rb @@ -2,10 +2,6 @@ require 'rubygems/test_case' -unless defined?(OpenSSL::SSL) then - warn 'Skipping Gem::Security::Policy tests. openssl not found.' -end - class TestGemSecurityPolicy < Gem::TestCase ALTERNATE_KEY = load_key 'alternate' @@ -15,7 +11,6 @@ class TestGemSecurityPolicy < Gem::TestCase INVALIDCHILD_KEY = load_key 'invalidchild' ALTERNATE_CERT = load_cert 'alternate' - CA_CERT = load_cert 'ca' CHILD_CERT = load_cert 'child' EXPIRED_CERT = load_cert 'expired' FUTURE_CERT = load_cert 'future' @@ -290,11 +285,6 @@ class TestGemSecurityPolicy < Gem::TestCase "(root of signing cert #{CHILD_CERT.subject})", e.message end - def test_subject - assert_equal 'email:nobody@example', @no.subject(PUBLIC_CERT) - assert_equal '/C=JP/O=JIN.GR.JP/OU=RRR/CN=CA', @no.subject(CA_CERT) - end - def test_verify Gem::Security.trust_dir.trust_cert PUBLIC_CERT @@ -335,33 +325,6 @@ class TestGemSecurityPolicy < Gem::TestCase assert_equal 'missing digest for 0', e.message end - def test_verify_no_signatures - Gem::Security.trust_dir.trust_cert PUBLIC_CERT - - digests, = dummy_signatures - - use_ui @ui do - @no.verify [PUBLIC_CERT], nil, digests, {}, 'some_gem' - end - - assert_match "WARNING: some_gem is not signed\n", @ui.error - - assert_raises Gem::Security::Exception do - @almost_no.verify [PUBLIC_CERT], nil, digests, {} - end - end - - def test_verify_no_signatures_no_digests - Gem::Security.trust_dir.trust_cert PUBLIC_CERT - - use_ui @ui do - @no.verify [PUBLIC_CERT], nil, {}, {}, 'some_gem' - end - - assert_empty @ui.output - assert_empty @ui.error - end - def test_verify_not_enough_signatures Gem::Security.trust_dir.trust_cert PUBLIC_CERT @@ -378,21 +341,6 @@ class TestGemSecurityPolicy < Gem::TestCase assert_equal 'missing digest for 1', e.message end - def test_verify_no_trust - digests, signatures = dummy_signatures - - use_ui @ui do - @low.verify [PUBLIC_CERT], nil, digests, signatures, 'some_gem' - end - - assert_equal "WARNING: email:nobody@example is not trusted for some_gem\n", - @ui.error - - assert_raises Gem::Security::Exception do - @medium.verify [PUBLIC_CERT], nil, digests, signatures - end - end - def test_verify_wrong_digest_type Gem::Security.trust_dir.trust_cert PUBLIC_CERT @@ -536,5 +484,5 @@ class TestGemSecurityPolicy < Gem::TestCase return digests, signatures end -end if defined?(OpenSSL::SSL) +end diff --git a/test/rubygems/test_gem_security_signer.rb b/test/rubygems/test_gem_security_signer.rb index f077a46413..59c5089fec 100644 --- a/test/rubygems/test_gem_security_signer.rb +++ b/test/rubygems/test_gem_security_signer.rb @@ -1,9 +1,5 @@ require 'rubygems/test_case' -unless defined?(OpenSSL::SSL) then - warn 'Skipping Gem::Security::Signer tests. openssl not found.' -end - class TestGemSecuritySigner < Gem::TestCase ALTERNATE_KEY = load_key 'alternate' @@ -76,20 +72,6 @@ class TestGemSecuritySigner < Gem::TestCase assert_equal PRIVATE_KEY.to_s, signer.key.to_s end - def test_initialize_encrypted_key_path - key_file = ENCRYPTED_PRIVATE_KEY_PATH - - signer = Gem::Security::Signer.new key_file, nil, PRIVATE_KEY_PASSPHRASE - - assert_equal ENCRYPTED_PRIVATE_KEY.to_s, signer.key.to_s - end - - def test_extract_name - signer = Gem::Security::Signer.new nil, nil - - assert_equal 'child@example', signer.extract_name(CHILD_CERT) - end - def test_load_cert_chain Gem::Security.trust_dir.trust_cert PUBLIC_CERT @@ -204,5 +186,5 @@ c7NM7KZZjj7G++SXjYTEI1PHSA7aFQ/i/+qSUvx+Pg== end end -end if defined?(OpenSSL::SSL) +end diff --git a/test/rubygems/test_gem_security_trust_dir.rb b/test/rubygems/test_gem_security_trust_dir.rb index 7b0d450bd6..56c2feb44c 100644 --- a/test/rubygems/test_gem_security_trust_dir.rb +++ b/test/rubygems/test_gem_security_trust_dir.rb @@ -1,9 +1,5 @@ require 'rubygems/test_case' -unless defined?(OpenSSL::SSL) then - warn 'Skipping Gem::Security::TrustDir tests. openssl not found.' -end - class TestGemSecurityTrustDir < Gem::TestCase CHILD_CERT = load_cert 'child' @@ -94,5 +90,5 @@ class TestGemSecurityTrustDir < Gem::TestCase assert_equal mask, File.stat(@dest_dir).mode unless win_platform? end -end if defined?(OpenSSL::SSL) +end diff --git a/test/rubygems/test_gem_source.rb b/test/rubygems/test_gem_source.rb index cb43121ddd..2629f180a9 100644 --- a/test/rubygems/test_gem_source.rb +++ b/test/rubygems/test_gem_source.rb @@ -63,7 +63,7 @@ class TestGemSource < Gem::TestCase def test_cache_dir_escapes_windows_paths uri = URI.parse("file:///C:/WINDOWS/Temp/gem_repo") - root = Gem.spec_cache_dir + root = File.join Gem.user_home, '.gem', 'specs' cache_dir = @source.cache_dir(uri).gsub(root, '') assert cache_dir !~ /:/, "#{cache_dir} should not contain a :" end @@ -123,7 +123,7 @@ class TestGemSource < Gem::TestCase expected = @released assert_equal expected, @source.load_specs(:released) - cache_dir = File.join Gem.spec_cache_dir, 'gems.example.com%80' + cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80' assert File.exist?(cache_dir), "#{cache_dir} does not exist" cache_file = File.join cache_dir, "specs.#{Gem.marshal_version}" @@ -138,7 +138,7 @@ class TestGemSource < Gem::TestCase @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}"] = ' ' * Marshal.dump(@latest_specs).length - cache_dir = File.join Gem.spec_cache_dir, 'gems.example.com%80' + cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80' FileUtils.mkdir_p cache_dir @@ -160,7 +160,7 @@ class TestGemSource < Gem::TestCase @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = util_gzip(Marshal.dump(@latest_specs)) - cache_dir = File.join Gem.spec_cache_dir, 'gems.example.com%80' + cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80' FileUtils.mkdir_p cache_dir @@ -184,28 +184,5 @@ class TestGemSource < Gem::TestCase end end - def test_spaceship - remote = @source - specific = Gem::Source::SpecificFile.new(@a1.cache_file) - installed = Gem::Source::Installed.new - local = Gem::Source::Local.new - - assert_equal( 0, remote. <=>(remote), 'remote <=> remote') - - assert_equal(-1, remote. <=>(specific), 'remote <=> specific') - assert_equal( 1, specific. <=>(remote), 'specific <=> remote') - - assert_equal(-1, remote. <=>(local), 'remote <=> local') - assert_equal( 1, local. <=>(remote), 'local <=> remote') - - assert_equal(-1, remote. <=>(installed), 'remote <=> installed') - assert_equal( 1, installed.<=>(remote), 'installed <=> remote') - - no_uri = @source.dup - no_uri.instance_variable_set :@uri, nil - - assert_equal(-1, remote. <=>(no_uri), 'remote <=> no_uri') - end - end diff --git a/test/rubygems/test_gem_source_local.rb b/test/rubygems/test_gem_source_local.rb index b3b444ccde..54ce3d51be 100644 --- a/test/rubygems/test_gem_source_local.rb +++ b/test/rubygems/test_gem_source_local.rb @@ -1,5 +1,5 @@ require 'rubygems/test_case' -require 'rubygems/source/local' +require 'rubygems/source_local' require 'fileutils' @@ -66,41 +66,18 @@ class TestGemSourceLocal < Gem::TestCase assert_equal s, @a end - def test_inspect - assert_equal '#<Gem::Source::Local specs: "NOT LOADED">', @sl.inspect - - @sl.load_specs :released - - inner = [@a, @ap, @b].map { |t| t.name_tuple }.inspect - - assert_equal "#<Gem::Source::Local specs: #{inner}>", @sl.inspect - end - def test_download path = @sl.download @a assert_equal File.expand_path(@a.file_name), path end - def test_spaceship - a1 = quick_gem 'a', '1' - util_build_gem a1 + def test_compare + uri = URI.parse "http://gems.example/foo" + s = Gem::Source.new uri - remote = Gem::Source.new @gem_repo - specific = Gem::Source::SpecificFile.new a1.cache_file - installed = Gem::Source::Installed.new - local = Gem::Source::Local.new - - assert_equal( 0, local. <=>(local), 'local <=> local') - - assert_equal(-1, remote. <=>(local), 'remote <=> local') - assert_equal( 1, local. <=>(remote), 'local <=> remote') - - assert_equal( 1, installed.<=>(local), 'installed <=> local') - assert_equal(-1, local. <=>(installed), 'local <=> installed') - - assert_equal(-1, specific. <=>(local), 'specific <=> local') - assert_equal( 1, local. <=>(specific), 'local <=> specific') + assert_equal(-1, (@sl <=> s)) + assert_equal 1, (s <=> @sl) + assert_equal 0, (@sl <=> @sl) end - end diff --git a/test/rubygems/test_gem_source_specific_file.rb b/test/rubygems/test_gem_source_specific_file.rb index 8ccbe50c91..7ffcf482dc 100644 --- a/test/rubygems/test_gem_source_specific_file.rb +++ b/test/rubygems/test_gem_source_specific_file.rb @@ -1,5 +1,5 @@ require 'rubygems/test_case' -require 'rubygems/source/specific_file' +require 'rubygems/source_specific_file' class TestGemSourceSpecificFile < Gem::TestCase def setup @@ -30,42 +30,4 @@ class TestGemSourceSpecificFile < Gem::TestCase def test_download assert_equal @a_gem, @sf.download(@a) end - - def test_spaceship - a1 = quick_gem 'a', '1' - util_build_gem a1 - - remote = Gem::Source.new @gem_repo - specific = Gem::Source::SpecificFile.new a1.cache_file - installed = Gem::Source::Installed.new - local = Gem::Source::Local.new - - assert_equal( 0, specific. <=>(specific), 'specific <=> specific') - - assert_equal(-1, remote. <=>(specific), 'remote <=> specific') - assert_equal( 1, specific. <=>(remote), 'specific <=> remote') - - assert_equal(-1, specific. <=>(local), 'specific <=> local') - assert_equal( 1, local. <=>(specific), 'local <=> specific') - - assert_equal(-1, specific. <=>(installed), 'specific <=> installed') - assert_equal( 1, installed.<=>(specific), 'installed <=> specific') - - a2 = quick_gem 'a', '2' - util_build_gem a2 - - b1 = quick_gem 'b', '1' - util_build_gem b1 - - a1_source = specific - a2_source = Gem::Source::SpecificFile.new a2.cache_file - b1_source = Gem::Source::SpecificFile.new b1.cache_file - - assert_nil a1_source.<=>(b1_source), 'a1_source <=> b1_source' - - assert_equal(-1, a1_source.<=>(a2_source), 'a1_source <=> a2_source') - assert_equal( 0, a1_source.<=>(a1_source), 'a1_source <=> a1_source') - assert_equal( 1, a2_source.<=>(a1_source), 'a2_source <=> a1_source') - end - end diff --git a/test/rubygems/test_gem_spec_fetcher.rb b/test/rubygems/test_gem_spec_fetcher.rb index 8be10a30b9..a821057705 100644 --- a/test/rubygems/test_gem_spec_fetcher.rb +++ b/test/rubygems/test_gem_spec_fetcher.rb @@ -168,7 +168,7 @@ class TestGemSpecFetcher < Gem::TestCase specs, _ = @sf.available_specs(:latest) assert_equal [@source], specs.keys - assert_equal @latest_specs, specs[@source] + assert_equal @latest_specs, specs[@source].sort end def test_available_specs_released @@ -176,7 +176,7 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - assert_equal @released, specs[@source] + assert_equal @released, specs[@source].sort end def test_available_specs_complete @@ -184,9 +184,9 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - expected = (@prerelease_specs + @released).sort + comp = @prerelease_specs + @released - assert_equal expected, specs[@source] + assert_equal comp.sort, specs[@source].sort end def test_available_specs_complete_handles_no_prerelease @@ -197,9 +197,12 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - assert_equal @released, specs[@source] + comp = @released + + assert_equal comp.sort, specs[@source].sort end + def test_available_specs_cache specs, _ = @sf.available_specs(:latest) @@ -227,7 +230,7 @@ class TestGemSpecFetcher < Gem::TestCase def test_available_specs_prerelease specs, _ = @sf.available_specs(:prerelease) - assert_equal @prerelease_specs, specs[@source] + assert_equal @prerelease_specs, specs[@source].sort end def test_available_specs_with_bad_source diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index efda6f6f19..9b2ae82fe3 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -38,24 +38,6 @@ Gem::Specification.new do |s| end EOF - def make_spec_c1 - @c1 = quick_spec 'a', '1' do |s| - s.executable = 'exec' - s.extensions << 'ext/a/extconf.rb' - s.test_file = 'test/suite.rb' - s.requirements << 'A working computer' - s.rubyforge_project = 'example' - s.license = 'MIT' - - s.add_dependency 'rake', '> 0.4' - s.add_dependency 'jabber4r', '> 0.0.0' - s.add_dependency 'pqa', ['> 0.4', '<= 0.6'] - - s.mark_version - s.files = %w[lib/code.rb] - end - end - def setup super @@ -67,6 +49,10 @@ end s.rubyforge_project = 'example' s.license = 'MIT' + s.add_dependency 'rake', '> 0.4' + s.add_dependency 'jabber4r', '> 0.0.0' + s.add_dependency 'pqa', ['> 0.4', '<= 0.6'] + s.mark_version s.files = %w[lib/code.rb] end @@ -80,379 +66,6 @@ end load 'rubygems/syck_hack.rb' end - def test_self_activate - foo = util_spec 'foo', '1' - - assert_activate %w[foo-1], foo - end - - def test_self_activate_ambiguous_direct - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0" - b1 = new_spec("b", "1", { "c" => ">= 1" }, "lib/d.rb") - b2 = new_spec("b", "2", { "c" => ">= 2" }, "lib/d.rb") - c1 = new_spec "c", "1" - c2 = new_spec "c", "2" - - Gem::Specification.reset - install_specs a1, b1, b2, c1, c2 - - a1.activate - assert_equal %w(a-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - - require "d" - - assert_equal %w(a-1 b-2 c-2), loaded_spec_names - assert_equal [], unresolved_names - end - end - - def test_self_activate_ambiguous_indirect - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0" - b1 = new_spec "b", "1", "c" => ">= 1" - b2 = new_spec "b", "2", "c" => ">= 2" - c1 = new_spec "c", "1", nil, "lib/d.rb" - c2 = new_spec "c", "2", nil, "lib/d.rb" - - install_specs a1, b1, b2, c1, c2 - - a1.activate - assert_equal %w(a-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - - require "d" - - assert_equal %w(a-1 b-2 c-2), loaded_spec_names - assert_equal [], unresolved_names - end - end - - def test_self_activate_ambiguous_indirect_conflict - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0" - a2 = new_spec "a", "2", "b" => "> 0" - b1 = new_spec "b", "1", "c" => ">= 1" - b2 = new_spec "b", "2", "c" => ">= 2" - c1 = new_spec "c", "1", nil, "lib/d.rb" - c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2 - - install_specs a1, a2, b1, b2, c1, c2 - - a2.activate - assert_equal %w(a-2), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - - require "d" - - assert_equal %w(a-2 b-1 c-1), loaded_spec_names - assert_equal [], unresolved_names - end - end - - def test_self_activate_ambiguous_unrelated - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0" - b1 = new_spec "b", "1", "c" => ">= 1" - b2 = new_spec "b", "2", "c" => ">= 2" - c1 = new_spec "c", "1" - c2 = new_spec "c", "2" - d1 = new_spec "d", "1", nil, "lib/d.rb" - - install_specs a1, b1, b2, c1, c2, d1 - - a1.activate - assert_equal %w(a-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - - require "d" - - assert_equal %w(a-1 d-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - end - end - - ## - # [A] depends on - # [C] = 1.0 depends on - # [B] = 2.0 - # [B] ~> 1.0 (satisfied by 1.0) - - def test_self_activate_checks_dependencies - a, _ = util_spec 'a', '1.0' - a.add_dependency 'c', '= 1.0' - a.add_dependency 'b', '~> 1.0' - - util_spec 'b', '1.0' - util_spec 'b', '2.0' - c, _ = util_spec 'c', '1.0', 'b' => '= 2.0' - - e = assert_raises Gem::LoadError do - assert_activate nil, a, c, "b" - end - - expected = "can't satisfy 'b (~> 1.0)', already activated 'b-2.0'" - assert_equal expected, e.message - end - - ## - # [A] depends on - # [B] ~> 1.0 (satisfied by 1.0) - # [C] = 1.0 depends on - # [B] = 2.0 - - def test_self_activate_divergent - a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0' - util_spec 'b', '1.0' - util_spec 'b', '2.0' - c, _ = util_spec 'c', '1.0', 'b' => '= 2.0' - - e = assert_raises Gem::LoadError do - assert_activate nil, a, c, "b" - end - - assert_match(/Unable to activate c-1.0,/, e.message) - assert_match(/because b-1.0 conflicts with b .= 2.0/, e.message) - end - - ## - # DOC - - def test_self_activate_old_required - e1, = util_spec 'e', '1', 'd' => '= 1' - @d1 = util_spec 'd', '1' - @d2 = util_spec 'd', '2' - - assert_activate %w[d-1 e-1], e1, "d" - end - - ## - # DOC - - def test_self_activate_platform_alternate - @x1_m = util_spec 'x', '1' do |s| - s.platform = Gem::Platform.new %w[cpu my_platform 1] - end - - @x1_o = util_spec 'x', '1' do |s| - s.platform = Gem::Platform.new %w[cpu other_platform 1] - end - - @w1 = util_spec 'w', '1', 'x' => nil - - util_set_arch 'cpu-my_platform1' - - assert_activate %w[x-1-cpu-my_platform-1 w-1], @w1, @x1_m - end - - ## - # DOC - - def test_self_activate_platform_bump - @y1 = util_spec 'y', '1' - - @y1_1_p = util_spec 'y', '1.1' do |s| - s.platform = Gem::Platform.new %w[cpu my_platform 1] - end - - @z1 = util_spec 'z', '1', 'y' => nil - - assert_activate %w[y-1 z-1], @z1, @y1 - end - - ## - # [C] depends on - # [A] = 1.a - # [B] = 1.0 depends on - # [A] >= 0 (satisfied by 1.a) - - def test_self_activate_prerelease - @c1_pre = util_spec 'c', '1.a', "a" => "1.a", "b" => "1" - @a1_pre = util_spec 'a', '1.a' - @b1 = util_spec 'b', '1' do |s| - s.add_dependency 'a' - s.add_development_dependency 'aa' - end - - assert_activate %w[a-1.a b-1 c-1.a], @c1_pre, @a1_pre, @b1 - end - - def test_self_activate_via_require - a1 = new_spec "a", "1", "b" => "= 1" - b1 = new_spec "b", "1", nil, "lib/b/c.rb" - b2 = new_spec "b", "2", nil, "lib/b/c.rb" - - install_specs a1, b1, b2 - - a1.activate - save_loaded_features do - require "b/c" - end - - assert_equal %w(a-1 b-1), loaded_spec_names - end - - def test_self_activate_via_require_wtf - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0", "d" => "> 0" # this - b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/b.rb" - b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/b.rb" # this - c1 = new_spec "c", "1" - c2 = new_spec "c", "2" # this - d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb" - d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" # this - - install_specs a1, b1, b2, c1, c2, d1, d2 - - a1.activate - - assert_equal %w(a-1), loaded_spec_names - assert_equal ["b (> 0)", "d (> 0)"], unresolved_names - - require "b" - - e = assert_raises Gem::LoadError do - require "d" - end - - assert_equal "unable to find a version of 'd' to activate", e.message - - assert_equal %w(a-1 b-2 c-2), loaded_spec_names - assert_equal ["d (> 0)"], unresolved_names - end - end - - def test_self_activate_deep_unambiguous - a1 = new_spec "a", "1", "b" => "= 1" - b1 = new_spec "b", "1", "c" => "= 1" - b2 = new_spec "b", "2", "c" => "= 2" - c1 = new_spec "c", "1" - c2 = new_spec "c", "2" - - install_specs a1, b1, b2, c1, c2 - - a1.activate - assert_equal %w(a-1 b-1 c-1), loaded_spec_names - end - - def test_self_activate_loaded - foo = util_spec 'foo', '1' - - assert foo.activate - refute foo.activate - end - - ## - # [A] depends on - # [B] >= 1.0 (satisfied by 2.0) - # [C] depends on nothing - - def test_self_activate_unrelated - a = util_spec 'a', '1.0', 'b' => '>= 1.0' - util_spec 'b', '1.0' - c = util_spec 'c', '1.0' - - assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" - end - - ## - # [A] depends on - # [B] >= 1.0 (satisfied by 2.0) - # [C] = 1.0 depends on - # [B] ~> 1.0 - # - # and should resolve using b-1.0 - # TODO: move these to specification - - def test_self_activate_over - a = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '= 1.0' - util_spec 'b', '1.0' - util_spec 'b', '1.1' - util_spec 'b', '2.0' - util_spec 'c', '1.0', 'b' => '~> 1.0' - - a.activate - - assert_equal %w[a-1.0 c-1.0], loaded_spec_names - assert_equal ["b (>= 1.0, ~> 1.0)"], unresolved_names - end - - ## - # [A] depends on - # [B] ~> 1.0 (satisfied by 1.1) - # [C] = 1.0 depends on - # [B] = 1.0 - # - # and should resolve using b-1.0 - # - # TODO: this is not under, but over... under would require depth - # first resolve through a dependency that is later pruned. - - def test_self_activate_under - a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0' - util_spec 'b', '1.0' - util_spec 'b', '1.1' - c, _ = util_spec 'c', '1.0', 'b' => '= 1.0' - - assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" - end - - ## - # [A1] depends on - # [B] > 0 (satisfied by 2.0) - # [B1] depends on - # [C] > 0 (satisfied by 1.0) - # [B2] depends on nothing! - # [C1] depends on nothing - - def test_self_activate_dropped - a1, = util_spec 'a', '1', 'b' => nil - util_spec 'b', '1', 'c' => nil - util_spec 'b', '2' - util_spec 'c', '1' - - assert_activate %w[b-2 a-1], a1, "b" - end - - ## - # [A] depends on - # [B] >= 1.0 (satisfied by 1.1) depends on - # [Z] - # [C] >= 1.0 depends on - # [B] = 1.0 - # - # and should backtrack to resolve using b-1.0, pruning Z from the - # resolve. - - def test_self_activate_raggi_the_edgecase_generator - a, _ = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '>= 1.0' - util_spec 'b', '1.0' - util_spec 'b', '1.1', 'z' => '>= 1.0' - c, _ = util_spec 'c', '1.0', 'b' => '= 1.0' - - assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b" - end - - def test_self_activate_conflict - util_spec 'b', '1.0' - util_spec 'b', '2.0' - - gem "b", "= 1.0" - - assert_raises Gem::LoadError do - gem "b", "= 2.0" - end - end - - def test_self_all_equals - a = new_spec "foo", "1", nil, "lib/foo.rb" - - Gem::Specification.all = [a] - - assert_equal a, Gem::Specification.find_inactive_by_path('foo') - end - def test_self_attribute_names expected_value = %w[ authors @@ -836,25 +449,6 @@ dependencies: [] assert_equal %w[a], Gem::Specification.outdated end - def test_self_outdated_and_latest_remotes - util_clear_gems - util_setup_fake_fetcher true - - a4 = quick_gem @a1.name, '4' - util_build_gem a4 - b3 = quick_gem @b2.name, '3' - util_build_gem b3 - util_setup_spec_fetcher @a1, @a2, @a3a, a4, @b2, b3 - - Gem::Specification.remove_spec @a1 - Gem::Specification.remove_spec @a2 - Gem::Specification.remove_spec a4 - Gem::Specification.remove_spec b3 - - assert_equal [[@a3a, a4.version], [@b2, b3.version]], - Gem::Specification.outdated_and_latest_version.to_a - end - DATA_PATH = File.expand_path "../data", __FILE__ def test_handles_private_null_type @@ -1428,60 +1022,19 @@ dependencies: [] assert_equal %w[lib], @a1.require_paths end - def test_require_already_activated - save_loaded_features do - a1 = new_spec "a", "1", nil, "lib/d.rb" - - install_specs a1 # , a2, b1, b2, c1, c2 - - a1.activate - assert_equal %w(a-1), loaded_spec_names - assert_equal [], unresolved_names - - assert require "d" - - assert_equal %w(a-1), loaded_spec_names - assert_equal [], unresolved_names - end - end - - def test_require_already_activated_indirect_conflict - save_loaded_features do - a1 = new_spec "a", "1", "b" => "> 0" - a2 = new_spec "a", "2", "b" => "> 0" - b1 = new_spec "b", "1", "c" => ">= 1" - b2 = new_spec "b", "2", "c" => ">= 2" - c1 = new_spec "c", "1", nil, "lib/d.rb" - c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2 - - install_specs a1, a2, b1, b2, c1, c2 - - a1.activate - c1.activate - assert_equal %w(a-1 c-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - - assert require "d" - - assert_equal %w(a-1 c-1), loaded_spec_names - assert_equal ["b (> 0)"], unresolved_names - end - end - def test_requirements assert_equal ['A working computer'], @a1.requirements end def test_runtime_dependencies_legacy - make_spec_c1 # legacy gems don't have a type - @c1.runtime_dependencies.each do |dep| + @a1.runtime_dependencies.each do |dep| dep.instance_variable_set :@type, nil end expected = %w[rake jabber4r pqa] - assert_equal expected, @c1.runtime_dependencies.map { |d| d.name } + assert_equal expected, @a1.runtime_dependencies.map { |d| d.name } end def test_spaceship_name @@ -1535,13 +1088,11 @@ dependencies: [] @a2.add_runtime_dependency 'b', '1' @a2.dependencies.first.instance_variable_set :@type, nil @a2.required_rubygems_version = Gem::Requirement.new '> 0' - @a2.require_paths << "lib/a/ext" ruby_code = @a2.to_ruby expected = <<-SPEC # -*- encoding: utf-8 -*- -# stub: a 2 ruby lib\0lib/a/ext Gem::Specification.new do |s| s.name = "a" @@ -1554,7 +1105,7 @@ Gem::Specification.new do |s| s.email = "example@example.com" s.files = ["lib/code.rb"] s.homepage = "http://example.com" - s.require_paths = ["lib", "lib/a/ext"] + s.require_paths = ["lib"] s.rubygems_version = "#{Gem::VERSION}" s.summary = "this is a summary" @@ -1589,7 +1140,6 @@ end expected = <<-SPEC # -*- encoding: utf-8 -*- -# stub: a 2 ruby lib Gem::Specification.new do |s| s.name = "a" @@ -1629,17 +1179,14 @@ end end def test_to_ruby_fancy - make_spec_c1 - - @c1.platform = Gem::Platform.local - ruby_code = @c1.to_ruby + @a1.platform = Gem::Platform.local + ruby_code = @a1.to_ruby local = Gem::Platform.local expected_platform = "[#{local.cpu.inspect}, #{local.os.inspect}, #{local.version.inspect}]" expected = <<-SPEC # -*- encoding: utf-8 -*- -# stub: a 1 #{win_platform? ? "x86-mswin32-60" : "x86-darwin-8"} lib Gem::Specification.new do |s| s.name = "a" @@ -1687,7 +1234,7 @@ end same_spec = eval ruby_code - assert_equal @c1, same_spec + assert_equal @a1, same_spec end def test_to_ruby_legacy @@ -2339,7 +1886,6 @@ end def test_metadata_specs valid_ruby_spec = <<-EOF # -*- encoding: utf-8 -*- -# stub: m 1 ruby lib Gem::Specification.new do |s| s.name = "m" diff --git a/test/rubygems/test_gem_uninstaller.rb b/test/rubygems/test_gem_uninstaller.rb index 1739614c67..948318a5e3 100644 --- a/test/rubygems/test_gem_uninstaller.rb +++ b/test/rubygems/test_gem_uninstaller.rb @@ -5,7 +5,6 @@ class TestGemUninstaller < Gem::InstallerTestCase def setup super - common_installer_setup build_rake_in do use_ui ui do @@ -376,19 +375,6 @@ class TestGemUninstaller < Gem::InstallerTestCase assert_equal "Successfully uninstalled q-1.0", lines.shift end - def test_uninstall_doesnt_prompt_and_raises_when_abort_on_dependent_set - quick_gem 'r', '1' do |s| s.add_dependency 'q', '= 1' end - quick_gem 'q', '1' - - un = Gem::Uninstaller.new('q', :abort_on_dependent => true) - ui = Gem::MockGemUi.new("y\n") - - assert_raises Gem::DependencyRemovalException do - use_ui ui do - un.uninstall - end - end - end def test_uninstall_prompt_includes_dep_type quick_gem 'r', '1' do |s| diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb index 2ba196e48d..da3b87dbca 100644 --- a/test/rubygems/test_gem_version.rb +++ b/test/rubygems/test_gem_version.rb @@ -122,15 +122,6 @@ class TestGemVersion < Gem::TestCase assert_equal "5.2.4", v("5.2.4").to_s end - def test_semver - assert_less_than "1.0.0-alpha", "1.0.0-alpha.1" - assert_less_than "1.0.0-alpha.1", "1.0.0-beta.2" - assert_less_than "1.0.0-beta.2", "1.0.0-beta.11" - assert_less_than "1.0.0-beta.11", "1.0.0-rc.1" - assert_less_than "1.0.0-rc1", "1.0.0" - assert_less_than "1.0.0-1", "1" - end - # Asserts that +version+ is a prerelease. def assert_prerelease version @@ -170,12 +161,6 @@ class TestGemVersion < Gem::TestCase assert second.eql?(first), "#{second} is eql? #{first}" end - def assert_less_than left, right - l = v(left) - r = v(right) - assert l < r, "#{left} not less than #{right}" - end - # Refute the assumption that +version+ is a prerelease. def refute_prerelease version diff --git a/test/rubygems/test_gem_version_option.rb b/test/rubygems/test_gem_version_option.rb index d6035ab800..cbe819c22e 100644 --- a/test/rubygems/test_gem_version_option.rb +++ b/test/rubygems/test_gem_version_option.rb @@ -80,69 +80,7 @@ class TestGemVersionOption < Gem::TestCase @cmd.handle_options %w[--version >1] - expected = { - :args => [], - :explicit_prerelease => false, - :prerelease => false, - :version => Gem::Requirement.new('> 1'), - } - - assert_equal expected, @cmd.options - end - - def test_version_option_compound - @cmd.add_version_option - - @cmd.handle_options ['--version', '< 1, > 0.9'] - - expected = { - :args => [], - :explicit_prerelease => false, - :prerelease => false, - :version => Gem::Requirement.new('< 1', '> 0.9'), - } - - assert_equal expected, @cmd.options - end - - def test_version_option_explicit_prerelease - @cmd.add_prerelease_option - @cmd.add_version_option - - @cmd.handle_options %w[--pre --version >1] - - expected = { - :args => [], - :explicit_prerelease => true, - :prerelease => true, - :version => Gem::Requirement.new('> 1'), - } - - assert_equal expected, @cmd.options - end - - def test_version_option_twice - @cmd.add_version_option - - @cmd.handle_options %w[--version >1.a] - - expected = { - :args => [], - :explicit_prerelease => false, - :prerelease => true, - :version => Gem::Requirement.new('> 1.a'), - } - - assert_equal expected, @cmd.options - - @cmd.handle_options %w[--version >1] - - expected = { - :args => [], - :explicit_prerelease => false, - :prerelease => false, - :version => Gem::Requirement.new('> 1'), - } + expected = { :version => Gem::Requirement.new('> 1'), :args => [] } assert_equal expected, @cmd.options end |