From d22130922e7842226d38d59680e4bbb48a28a5f0 Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 1 Jun 2011 03:45:05 +0000 Subject: Import rubygems 1.8.5 (released @ 137c80f) git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31885 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 + lib/rubygems.rb | 444 ++-- lib/rubygems/builder.rb | 13 +- lib/rubygems/command.rb | 10 +- lib/rubygems/command_manager.rb | 18 +- lib/rubygems/commands/build_command.rb | 24 +- lib/rubygems/commands/cert_command.rb | 2 +- lib/rubygems/commands/cleanup_command.rb | 29 +- lib/rubygems/commands/contents_command.rb | 31 +- lib/rubygems/commands/dependency_command.rb | 68 +- lib/rubygems/commands/fetch_command.rb | 11 +- lib/rubygems/commands/install_command.rb | 3 +- lib/rubygems/commands/lock_command.rb | 8 +- lib/rubygems/commands/outdated_command.rb | 8 +- lib/rubygems/commands/pristine_command.rb | 50 +- lib/rubygems/commands/query_command.rb | 15 +- lib/rubygems/commands/server_command.rb | 2 +- lib/rubygems/commands/setup_command.rb | 2 +- lib/rubygems/commands/specification_command.rb | 31 +- lib/rubygems/commands/stale_command.rb | 3 +- lib/rubygems/commands/unpack_command.rb | 60 +- lib/rubygems/commands/update_command.rb | 40 +- lib/rubygems/commands/which_command.rb | 14 +- lib/rubygems/config_file.rb | 16 +- lib/rubygems/custom_require.rb | 11 +- lib/rubygems/defaults.rb | 44 +- lib/rubygems/dependency.rb | 52 +- lib/rubygems/dependency_installer.rb | 78 +- lib/rubygems/dependency_list.rb | 29 +- lib/rubygems/deprecate.rb | 74 + lib/rubygems/doc_manager.rb | 21 +- lib/rubygems/ext/builder.rb | 2 +- lib/rubygems/ext/rake_builder.rb | 4 +- lib/rubygems/gem_path_searcher.rb | 26 +- lib/rubygems/gem_runner.rb | 4 +- lib/rubygems/indexer.rb | 238 +- lib/rubygems/installer.rb | 209 +- lib/rubygems/installer_test_case.rb | 58 +- lib/rubygems/local_remote_options.rb | 4 +- lib/rubygems/mock_gem_ui.rb | 14 +- lib/rubygems/package.rb | 28 +- lib/rubygems/package/tar_input.rb | 12 +- lib/rubygems/package/tar_writer.rb | 2 +- lib/rubygems/package_task.rb | 2 +- lib/rubygems/path_support.rb | 78 + lib/rubygems/platform.rb | 14 +- lib/rubygems/remote_fetcher.rb | 114 +- lib/rubygems/requirement.rb | 12 + lib/rubygems/security.rb | 2 +- lib/rubygems/server.rb | 134 +- lib/rubygems/source_index.rb | 172 +- lib/rubygems/spec_fetcher.rb | 17 +- lib/rubygems/specification.rb | 2497 ++++++++++++-------- lib/rubygems/test_case.rb | 188 +- lib/rubygems/test_utilities.rb | 7 +- lib/rubygems/text.rb | 2 +- lib/rubygems/uninstaller.rb | 89 +- lib/rubygems/user_interaction.rb | 58 +- test/rubygems/functional.rb | 98 - test/rubygems/test_gem.rb | 277 ++- test/rubygems/test_gem_builder.rb | 19 +- test/rubygems/test_gem_command_manager.rb | 2 + test/rubygems/test_gem_commands_build_command.rb | 34 +- test/rubygems/test_gem_commands_cleanup_command.rb | 57 + .../rubygems/test_gem_commands_contents_command.rb | 49 +- .../test_gem_commands_dependency_command.rb | 29 +- test/rubygems/test_gem_commands_fetch_command.rb | 9 +- test/rubygems/test_gem_commands_help_command.rb | 64 + test/rubygems/test_gem_commands_install_command.rb | 49 +- test/rubygems/test_gem_commands_list_command.rb | 5 +- .../rubygems/test_gem_commands_outdated_command.rb | 19 +- .../rubygems/test_gem_commands_pristine_command.rb | 115 +- test/rubygems/test_gem_commands_push_command.rb | 2 +- test/rubygems/test_gem_commands_query_command.rb | 97 +- test/rubygems/test_gem_commands_sources_command.rb | 17 +- .../test_gem_commands_specification_command.rb | 16 +- test/rubygems/test_gem_commands_stale_command.rb | 8 +- test/rubygems/test_gem_commands_unpack_command.rb | 57 +- test/rubygems/test_gem_commands_update_command.rb | 69 +- test/rubygems/test_gem_commands_which_command.rb | 11 +- test/rubygems/test_gem_dependency.rb | 29 +- test/rubygems/test_gem_dependency_installer.rb | 120 +- test/rubygems/test_gem_dependency_list.rb | 12 +- test/rubygems/test_gem_doc_manager.rb | 6 +- test/rubygems/test_gem_format.rb | 2 +- test/rubygems/test_gem_gem_path_searcher.rb | 74 +- test/rubygems/test_gem_gem_runner.rb | 5 +- test/rubygems/test_gem_indexer.rb | 95 +- test/rubygems/test_gem_install_update_options.rb | 11 +- test/rubygems/test_gem_installer.rb | 102 +- test/rubygems/test_gem_package_tar_output.rb | 1 + test/rubygems/test_gem_path_support.rb | 64 + test/rubygems/test_gem_platform.rb | 2 +- test/rubygems/test_gem_remote_fetcher.rb | 194 +- test/rubygems/test_gem_requirement.rb | 13 + test/rubygems/test_gem_server.rb | 38 +- test/rubygems/test_gem_silent_ui.rb | 4 +- test/rubygems/test_gem_source_index.rb | 463 ++-- test/rubygems/test_gem_spec_fetcher.rb | 91 +- test/rubygems/test_gem_specification.rb | 437 ++-- test/rubygems/test_gem_text.rb | 15 + test/rubygems/test_gem_uninstaller.rb | 66 +- test/rubygems/test_kernel.rb | 3 +- 103 files changed, 4722 insertions(+), 3431 deletions(-) create mode 100644 lib/rubygems/deprecate.rb create mode 100644 lib/rubygems/path_support.rb delete mode 100644 test/rubygems/functional.rb create mode 100644 test/rubygems/test_gem_commands_cleanup_command.rb create mode 100644 test/rubygems/test_gem_commands_help_command.rb create mode 100644 test/rubygems/test_gem_path_support.rb diff --git a/ChangeLog b/ChangeLog index 003d346cc2..74535f3827 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Jun 1 12:35:50 2011 Ryan Davis + + * lib/rubygems*: Import rubygems 1.8.5 (released @ 137c80f) + * test/rubygems: Ditto + Wed Jun 1 12:34:00 2011 Kenta Murata * NEWS: add new features of bigdecimal. diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 429dfda69c..0f3a07329e 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -33,7 +33,9 @@ end require 'rubygems/defaults' require "rubygems/dependency_list" +require 'rubygems/path_support' require 'rbconfig' +require "rubygems/deprecate" ## # RubyGems is the Ruby standard for publishing and managing third party @@ -124,7 +126,7 @@ require 'rbconfig' # -The RubyGems Team module Gem - VERSION = '1.6.2' + VERSION = '1.8.5' ## # Raised when RubyGems is unable to load or activate a gem. Contains the @@ -160,11 +162,6 @@ module Gem end end - ## - # Default directories in a gem repository - - DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES) - RubyGemsPackageVersion = VERSION RUBYGEMS_DIR = File.dirname File.expand_path(__FILE__) @@ -188,16 +185,17 @@ module Gem @configuration = nil @loaded_specs = {} - @loaded_stacks = {} @platforms = [] @ruby = nil - @sources = [] + @sources = nil @post_build_hooks ||= [] @post_install_hooks ||= [] @post_uninstall_hooks ||= [] @pre_uninstall_hooks ||= [] @pre_install_hooks ||= [] + @pre_reset_hooks ||= [] + @post_reset_hooks ||= [] ## # Try to activate a gem containing +path+. Returns true if @@ -205,17 +203,18 @@ module Gem # activated. Returns false if it can't find the path in a gem. def self.try_activate path + # TODO: deprecate when 1.9.3 comes out. # finds the _latest_ version... regardless of loaded specs and their deps # TODO: use find_all and bork if ambiguous - spec = Gem.searcher.find path + spec = Gem::Specification.find_by_path path return false unless spec begin - Gem.activate spec.name, "= #{spec.version}" + spec.activate rescue Gem::LoadError # this could fail due to gem dep collisions, go lax - Gem.activate spec.name + Gem::Specification.find_by_name(spec.name).activate end return true @@ -238,94 +237,18 @@ module Gem # Gem::Requirement and Gem::Version documentation. def self.activate(dep, *requirements) - # TODO: remove options entirely - if requirements.last.is_a?(Hash) - options = requirements.pop - else - options = {} - end - - requirements = Gem::Requirement.default if requirements.empty? - dep = Gem::Dependency.new(dep, requirements) unless Gem::Dependency === dep - - # TODO: remove sources entirely - sources = options[:sources] || [] - matches = Gem.source_index.search dep, true - report_activate_error(dep) if matches.empty? - - if @loaded_specs[dep.name] then - # This gem is already loaded. If the currently loaded gem is not in the - # list of candidate gems, then we have a version conflict. - existing_spec = @loaded_specs[dep.name] - - # TODO: unless dep.matches_spec? existing_spec then - unless matches.any? { |spec| spec.version == existing_spec.version } then - sources_message = sources.map { |spec| spec.full_name } - stack_message = @loaded_stacks[dep.name].map { |spec| spec.full_name } - - msg = "can't activate #{dep} for #{sources_message.inspect}, " - msg << "already activated #{existing_spec.full_name} for " - msg << "#{stack_message.inspect}" - - e = Gem::LoadError.new msg - e.name = dep.name - e.requirement = dep.requirement - - raise e - end - - return false - end - - spec = matches.last - - conf = spec.conflicts - unless conf.empty? then - why = conf.map { |act,con| - "#{act.full_name} conflicts with #{con.join(", ")}" - }.join ", " - - # TODO: improve message by saying who activated `con` - - raise LoadError, "Unable to activate #{spec.full_name}, because #{why}" - end - - return false if spec.loaded? - - spec.loaded = true - @loaded_specs[spec.name] = spec - @loaded_stacks[spec.name] = sources.dup - - spec.runtime_dependencies.each do |spec_dep| - next if Gem.loaded_specs.include? spec_dep.name - specs = Gem.source_index.search spec_dep, true - - if specs.size == 1 then - self.activate spec_dep - else - name = spec_dep.name - unresolved_deps[name] = unresolved_deps[name].merge spec_dep - end - end - - unresolved_deps.delete spec.name + raise ArgumentError, "Deprecated use of Gem.activate(dep)" if + Gem::Dependency === dep - require_paths = spec.require_paths.map do |path| - File.join spec.full_gem_path, path - end - - # gem directories must come after -I and ENV['RUBYLIB'] - insert_index = load_path_insert_index + Gem::Specification.find_by_name(dep, *requirements).activate + end - if insert_index then - # gem directories must come after -I and ENV['RUBYLIB'] - $LOAD_PATH.insert(insert_index, *require_paths) - else - # we are probably testing in core, -I and RUBYLIB don't apply - $LOAD_PATH.unshift(*require_paths) - end + def self.activate_dep dep, *requirements # :nodoc: + dep.to_spec.activate + end - return true + def self.activate_spec spec # :nodoc: + spec.activate end def self.unresolved_deps @@ -341,7 +264,7 @@ module Gem Gem.path.each do |gemdir| each_load_path all_partials(gemdir) do |load_path| - result << load_path + result << gemdir.add(load_path).expand_path end end @@ -352,7 +275,7 @@ module Gem # Return all the partial paths in +gemdir+. def self.all_partials(gemdir) - Dir[File.join(gemdir, 'gems/*')] + Dir[File.join(gemdir, "gems/*")] end private_class_method :all_partials @@ -360,15 +283,14 @@ module Gem ## # See if a given gem is available. - def self.available?(gem, *requirements) + def self.available?(dep, *requirements) requirements = Gem::Requirement.default if requirements.empty? - unless gem.respond_to?(:name) and - gem.respond_to?(:requirement) then - gem = Gem::Dependency.new gem, requirements + unless dep.respond_to?(:name) and dep.respond_to?(:requirement) then + dep = Gem::Dependency.new dep, requirements end - !Gem.source_index.search(gem).empty? + not dep.matching_specs(true).empty? end ## @@ -378,30 +300,29 @@ module Gem # you to specify specific gem versions. def self.bin_path(name, exec_name = nil, *requirements) + # TODO: fails test_self_bin_path_bin_file_gone_in_latest + # Gem::Specification.find_by_name(name, *requirements).bin_file exec_name + + raise ArgumentError, "you must supply exec_name" unless exec_name + requirements = Gem::Requirement.default if requirements.empty? - specs = Gem.source_index.find_name(name, requirements) + + specs = Gem::Dependency.new(name, requirements).matching_specs(true) raise Gem::GemNotFoundException, "can't find gem #{name} (#{requirements})" if specs.empty? - specs = specs.find_all do |spec| - spec.executables.include?(exec_name) - end if exec_name + specs = specs.find_all { |spec| + spec.executables.include? exec_name + } if exec_name unless spec = specs.last msg = "can't find gem #{name} (#{requirements}) with executable #{exec_name}" raise Gem::GemNotFoundException, msg end - exec_name ||= spec.default_executable - - unless exec_name - msg = "no default executable for #{spec.full_name} and none given" - raise Gem::Exception, msg - end - - File.join(spec.full_gem_path, spec.bindir, exec_name) + spec.bin_file exec_name end ## @@ -415,8 +336,9 @@ module Gem # The path where gem executables are to be installed. def self.bindir(install_dir=Gem.dir) - return File.join(install_dir, 'bin') unless - install_dir.to_s == Gem.default_dir + # TODO: move to Gem::Dirs + return File.join install_dir, 'bin' unless + install_dir.to_s == Gem.default_dir.to_s Gem.default_bindir end @@ -426,20 +348,18 @@ module Gem # mainly used by the unit tests to provide test isolation. def self.clear_paths - @gem_home = nil - @gem_path = nil - @user_home = nil - @@source_index = nil - - @searcher = nil + @paths = nil + @user_home = nil + @searcher = nil + Gem::Specification.reset end ## # The path to standard location of the user's .gemrc file. def self.config_file - File.join Gem.user_home, '.gemrc' + @config_file ||= File.join Gem.user_home, '.gemrc' end ## @@ -462,9 +382,10 @@ module Gem # package is not available as a gem, return nil. def self.datadir(gem_name) +# TODO: deprecate spec = @loaded_specs[gem_name] return nil if spec.nil? - File.join(spec.full_gem_path, 'data', gem_name) + File.join spec.full_gem_path, "data", gem_name end ## @@ -475,13 +396,29 @@ module Gem Zlib::Deflate.deflate data end + def self.paths + @paths ||= Gem::PathSupport.new + end + + def self.paths=(env) + clear_paths + @paths = Gem::PathSupport.new env + Gem::Specification.dirs = @paths.path # FIX: home is at end + end + ## # The path where gems are to be installed. + #-- + # FIXME deprecate these once everything else has been done -ebh def self.dir - @gem_home ||= nil - set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home - @gem_home + # TODO: raise "no" + paths.home + end + + def self.path + # TODO: raise "no" + paths.path end ## @@ -490,33 +427,35 @@ module Gem def self.each_load_path(partials) partials.each do |gp| - base = File.basename(gp) - specfn = File.join(dir, "specifications", base + ".gemspec") - if File.exist?(specfn) - spec = eval(File.read(specfn)) + base = File.basename gp + specfn = dir.specifications.add(base + ".gemspec") + if specfn.exist? + spec = eval(specfn.read) spec.require_paths.each do |rp| - yield(File.join(gp, rp)) + yield(gp.add(rp)) end else - filename = File.join(gp, 'lib') - yield(filename) if File.exist?(filename) + filename = dir.add(gp, 'lib') + yield(filename) if filename.exist? end end end private_class_method :each_load_path + ## # Quietly ensure the named Gem directory contains all the proper # subdirectories. If we can't create a directory due to a permission # problem, then we will silently continue. - def self.ensure_gem_subdirectories(gemdir) + def self.ensure_gem_subdirectories dir = Gem.dir require 'fileutils' - Gem::DIRECTORIES.each do |filename| - fn = File.join gemdir, filename - FileUtils.mkdir_p fn rescue nil unless File.exist? fn + %w[cache doc gems specifications].each do |name| + subdir = File.join dir, name + next if File.exist? subdir + FileUtils.mkdir_p subdir rescue nil # in case of perms issues -- lame end end @@ -541,11 +480,9 @@ module Gem }.flatten.select { |file| File.file? file.untaint } end - specs = searcher.find_all glob - - specs.each do |spec| - files.concat searcher.matching_files(spec, glob) - end + files.concat Gem::Specification.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. @@ -565,25 +502,30 @@ module Gem # it should fallback to USERPROFILE and HOMEDRIVE + HOMEPATH (at # least on Win32). #++ + #-- + # + # FIXME move to pathsupport + # + #++ def self.find_home - unless RUBY_VERSION > '1.9' then - ['HOME', 'USERPROFILE'].each do |homekey| - return File.expand_path(ENV[homekey]) if ENV[homekey] + windows = File::ALT_SEPARATOR + if not windows or RUBY_VERSION >= '1.9' then + File.expand_path "~" + else + ['HOME', 'USERPROFILE'].each do |key| + return File.expand_path ENV[key] if ENV[key] end if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then - return File.expand_path("#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}") + File.expand_path "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}" end end - - File.expand_path "~" rescue - if File::ALT_SEPARATOR then - drive = ENV['HOMEDRIVE'] || ENV['SystemDrive'] - File.join(drive.to_s, '/') + if windows then + File.expand_path File.join(ENV['HOMEDRIVE'] || ENV['SystemDrive'], '/') else - "/" + File.expand_path "/" end end @@ -593,6 +535,7 @@ module Gem # Zlib::GzipReader wrapper that unzips +data+. def self.gunzip(data) + # TODO: move to utils require 'stringio' require 'zlib' data = StringIO.new data @@ -604,6 +547,7 @@ module Gem # Zlib::GzipWriter wrapper that zips +data+. def self.gzip(data) + # TODO: move to utils require 'stringio' require 'zlib' zipped = StringIO.new @@ -617,6 +561,7 @@ module Gem # A Zlib::Inflate#inflate wrapper def self.inflate(data) + # TODO: move to utils require 'zlib' Zlib::Inflate.inflate data end @@ -626,12 +571,14 @@ module Gem # https://rubygems.org. def self.host + # TODO: move to utils @host ||= "https://rubygems.org" end ## Set the default RubyGems API host. def self.host= host + # TODO: move to utils @host = host end @@ -644,7 +591,7 @@ module Gem Gem.path.each do |gemdir| each_load_path(latest_partials(gemdir)) do |load_path| - result << load_path + result << gemdir.add(load_path).expand_path end end @@ -657,8 +604,9 @@ module Gem def self.latest_partials(gemdir) latest = {} all_partials(gemdir).each do |gp| - base = File.basename(gp) - if base =~ /(.*)-((\d+\.)*\d+)/ then + base = File.basename gp + + if base.to_s =~ /(.*)-((\d+\.)*\d+)/ then name, version = $1, $2 ver = Gem::Version.new(version) if latest[name].nil? || ver > latest[name][0] @@ -712,6 +660,7 @@ module Gem file = $1 lineno = $2.to_i + # TODO: it is ALWAYS joined! STUPID! [file, lineno] end @@ -722,25 +671,6 @@ module Gem "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" end - ## - # Array of paths to search for Gems. - - def self.path - @gem_path ||= nil - - unless @gem_path then - paths = [ENV['GEM_PATH'] || default_path] - - if defined?(APPLE_GEM_HOME) and not ENV['GEM_PATH'] then - paths << APPLE_GEM_HOME - end - - set_paths paths.compact.join(File::PATH_SEPARATOR) - end - - @gem_path - end - ## # Get the appropriate cache path. # @@ -749,7 +679,7 @@ module Gem # def self.cache_dir(custom_dir=false) - File.join(custom_dir ? custom_dir : Gem.dir, 'cache') + File.join(custom_dir || Gem.dir, "cache") end ## @@ -759,7 +689,7 @@ module Gem # nil/false (default) for Gem.dir. def self.cache_gem(filename, user_dir=false) - File.join(cache_dir(user_dir), filename) + cache_dir(user_dir).add(filename) end ## @@ -799,6 +729,14 @@ module Gem @post_install_hooks << hook end + ## + # Adds a hook that will get run after Gem::Specification.reset is + # run. + + def self.post_reset(&hook) + @post_reset_hooks << hook + end + ## # Adds a post-uninstall hook that will be passed a Gem::Uninstaller instance # and the spec that was uninstalled when Gem::Uninstaller#uninstall is @@ -817,6 +755,14 @@ module Gem @pre_install_hooks << hook end + ## + # Adds a hook that will get run before Gem::Specification.reset is + # run. + + def self.pre_reset(&hook) + @pre_reset_hooks << hook + end + ## # Adds a pre-uninstall hook that will be passed an Gem::Uninstaller instance # and the spec that will be uninstalled when Gem::Uninstaller#uninstall is @@ -853,10 +799,10 @@ module Gem raise ArgumentError, "gem #{gem_name} is not activated" if gem.nil? raise ArgumentError, "gem #{over_name} is not activated" if over.nil? - last_gem_path = File.join gem.full_gem_path, gem.require_paths.last + last_gem_path = Gem::Path.path(gem.full_gem_path).add(gem.require_paths.last) over_paths = over.require_paths.map do |path| - File.join over.full_gem_path, path + Gem::Path.path(over.full_gem_path).add(path).to_s end over_paths.each do |path| @@ -872,8 +818,8 @@ module Gem # Refresh source_index from disk and clear searcher. def self.refresh - source_index.refresh! - + Gem::Specification.reset + @source_index = nil @searcher = nil end @@ -890,7 +836,7 @@ module Gem # any version by the requested name. def self.report_activate_error(gem) - matches = Gem.source_index.find_name(gem.name) + matches = Gem::Specification.find_by_name(gem.name) if matches.empty? then error = Gem::LoadError.new( @@ -915,14 +861,14 @@ module Gem def self.required_location(gemname, libfile, *requirements) requirements = Gem::Requirement.default if requirements.empty? - matches = Gem.source_index.find_name gemname, requirements + matches = Gem::Specification.find_all_by_name gemname, *requirements return nil if matches.empty? spec = matches.last spec.require_paths.each do |path| - result = File.join spec.full_gem_path, path, libfile - return result if File.exist? result + result = Gem::Path.path(spec.full_gem_path).add(path, libfile) + return result if result.exist? end nil @@ -934,11 +880,9 @@ module Gem def self.ruby if @ruby.nil? then @ruby = File.join(ConfigMap[:bindir], - ConfigMap[:ruby_install_name]) - @ruby << ConfigMap[:EXEEXT] + "#{ConfigMap[:ruby_install_name]}#{ConfigMap[:EXEEXT]}") - # escape string in case path to ruby executable contain spaces. - @ruby.sub!(/.*\s.*/m, '"\&"') + @ruby = "\"#{@ruby}\"" if @ruby =~ /\s/ end @ruby @@ -990,45 +934,13 @@ module Gem @searcher ||= Gem::GemPathSearcher.new end - ## - # Set the Gem home directory (as reported by Gem.dir). - - def self.set_home(home) - home = home.gsub File::ALT_SEPARATOR, File::SEPARATOR if File::ALT_SEPARATOR - @gem_home = home - end - - private_class_method :set_home - - ## - # Set the Gem search path (as reported by Gem.path). - - def self.set_paths(gpaths) - if gpaths - @gem_path = gpaths.split(File::PATH_SEPARATOR) - - if File::ALT_SEPARATOR then - @gem_path.map! do |path| - path.gsub File::ALT_SEPARATOR, File::SEPARATOR - end - end - - @gem_path << Gem.dir - else - # TODO: should this be Gem.default_path instead? - @gem_path = [Gem.dir] - end - - @gem_path.uniq! - end - - private_class_method :set_paths - ## # Returns the Gem::SourceIndex of specifications that are in the Gem.path def self.source_index - @@source_index ||= SourceIndex.from_installed_gems + @@source_index ||= Deprecate.skip_during do + SourceIndex.new Gem::Specification.dirs + end end ## @@ -1037,23 +949,14 @@ module Gem # default_sources if it is not installed. def self.sources - if @sources.empty? then - begin - gem 'sources', '> 0.0.1' - require 'sources' - rescue LoadError - @sources = default_sources - end - end - - @sources + @sources ||= default_sources end ## # Need to be able to set the sources without calling # Gem.sources.replace since that would cause an infinite loop. - def self.sources=(new_sources) + def self.sources= new_sources @sources = new_sources end @@ -1115,9 +1018,8 @@ module Gem # by the unit tests to provide environment isolation. def self.use_paths(home, paths=[]) - clear_paths - set_home(home) if home - set_paths(paths.join(File::PATH_SEPARATOR)) if paths + self.paths = { "GEM_HOME" => home, "GEM_PATH" => paths } + # TODO: self.paths = home, paths end ## @@ -1201,6 +1103,11 @@ module Gem attr_reader :post_install_hooks + ## + # The list of hooks to be run after Gem::Specification.reset is run. + + attr_reader :post_reset_hooks + ## # The list of hooks to be run before Gem::Uninstall#uninstall does any # work @@ -1212,19 +1119,18 @@ module Gem attr_reader :pre_install_hooks + ## + # The list of hooks to be run before Gem::Specification.reset is run. + + attr_reader :pre_reset_hooks + ## # The list of hooks to be run after Gem::Uninstall#uninstall is finished attr_reader :pre_uninstall_hooks - end def self.cache # :nodoc: - warn "#{Gem.location_of_caller.join ':'}:Warning: " \ - "Gem::cache is deprecated and will be removed on or after " \ - "August 2011. " \ - "Use Gem::source_index." - source_index end @@ -1233,17 +1139,17 @@ module Gem MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/" - autoload :Version, 'rubygems/version' - autoload :Requirement, 'rubygems/requirement' - autoload :Dependency, 'rubygems/dependency' + autoload :Version, 'rubygems/version' + autoload :Requirement, 'rubygems/requirement' + autoload :Dependency, 'rubygems/dependency' autoload :GemPathSearcher, 'rubygems/gem_path_searcher' - autoload :SpecFetcher, 'rubygems/spec_fetcher' - autoload :Specification, 'rubygems/specification' - autoload :Cache, 'rubygems/source_index' - autoload :SourceIndex, 'rubygems/source_index' - autoload :Platform, 'rubygems/platform' - autoload :Builder, 'rubygems/builder' - autoload :ConfigFile, 'rubygems/config_file' + autoload :SpecFetcher, 'rubygems/spec_fetcher' + autoload :Specification, 'rubygems/specification' + autoload :Cache, 'rubygems/source_index' + autoload :SourceIndex, 'rubygems/source_index' + autoload :Platform, 'rubygems/platform' + autoload :Builder, 'rubygems/builder' + autoload :ConfigFile, 'rubygems/config_file' end module Kernel @@ -1279,7 +1185,8 @@ module Kernel def gem(gem_name, *requirements) # :doc: skip_list = (ENV['GEM_SKIP'] || "").split(/:/) raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name - Gem.activate(gem_name, *requirements) + spec = Gem::Dependency.new(gem_name, *requirements).to_spec + spec.activate if spec end private :gem @@ -1300,8 +1207,7 @@ def RbConfig.datadir(package_name) require 'rbconfig/datadir' - Gem.datadir(package_name) || - File.join(Gem::ConfigMap[:datadir], package_name) + Gem.datadir(package_name) || File.join(Gem::ConfigMap[:datadir], package_name) end require 'rubygems/exceptions' @@ -1334,3 +1240,25 @@ require 'rubygems/custom_require' Gem.clear_paths +module Gem + class << self + extend Deprecate + deprecate :activate_dep, "Specification#activate", 2011, 6 + deprecate :activate_spec, "Specification#activate", 2011, 6 + deprecate :cache, "Gem::source_index", 2011, 8 + deprecate :activate, "Specification#activate", 2011, 10 + deprecate :all_load_paths, :none, 2011, 10 + deprecate :all_partials, :none, 2011, 10 + deprecate :latest_load_paths, :none, 2011, 10 + deprecate :promote_load_path, :none, 2011, 10 + deprecate :available?, "Specification::find_by_name", 2011, 11 + deprecate :cache_dir, "Specification#cache_dir", 2011, 11 + deprecate :cache_gem, "Specification#cache_file", 2011, 11 + deprecate :default_system_source_cache_dir, :none, 2011, 11 + deprecate :default_user_source_cache_dir, :none, 2011, 11 + deprecate :report_activate_error, :none, 2011, 11 + deprecate :required_location, :none, 2011, 11 + deprecate :searcher, "Specification", 2011, 11 + deprecate :source_index, "Specification", 2011, 11 + end +end diff --git a/lib/rubygems/builder.rb b/lib/rubygems/builder.rb index c07369f256..ea4e13ec4d 100644 --- a/lib/rubygems/builder.rb +++ b/lib/rubygems/builder.rb @@ -44,7 +44,7 @@ class Gem::Builder @signer = sign write_package say success if Gem.configuration.verbose - @spec.file_name + File.basename @spec.cache_file end def success @@ -52,7 +52,7 @@ class Gem::Builder Successfully built RubyGem Name: #{@spec.name} Version: #{@spec.version} - File: #{@spec.file_name} + File: #{File.basename @spec.cache_file} EOM end @@ -79,16 +79,17 @@ EOM end def write_package - open @spec.file_name, 'wb' do |gem_io| + file_name = File.basename @spec.cache_file + open file_name, 'wb' do |gem_io| Gem::Package.open gem_io, 'w', @signer do |pkg| yaml = @spec.to_yaml pkg.metadata = yaml @spec.files.each do |file| - next if File.directory? file - next if file == @spec.file_name # Don't add gem onto itself + next if File.directory?(file) + next if file == file_name # Don't add gem onto itself - stat = File.stat file + stat = File.stat(file) mode = stat.mode & 0777 size = stat.size diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index 98503cb40f..fd6cb01811 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -410,10 +410,12 @@ class Gem::Command end end - @parser.separator nil - @parser.separator " Summary:" - wrap(@summary, 80 - 4).split("\n").each do |line| - @parser.separator " #{line.strip}" + if @summary then + @parser.separator nil + @parser.separator " Summary:" + wrap(@summary, 80 - 4).split("\n").each do |line| + @parser.separator " #{line.strip}" + end end if description then diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 60d82c865e..3665f31d0f 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -43,6 +43,13 @@ class Gem::CommandManager @command_manager ||= new end + ## + # Reset the authoritative instance of the command manager. + + def self.reset + @command_manager = nil + end + ## # Register all the subcommands supported by the gem command. @@ -86,6 +93,13 @@ class Gem::CommandManager @commands[command] = false end + ## + # Unregister the Symbol +command+ as a gem command. + + def unregister_command(command) + @commands.delete command + end + ## # Return the registered command from the command name. @@ -166,7 +180,7 @@ class Gem::CommandManager retried = false begin - commands.const_get const_name + commands.const_get(const_name).new rescue NameError raise if retried @@ -179,7 +193,7 @@ class Gem::CommandManager Gem.configuration.backtrace end retry - end.new + end end end diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb index 5aac489459..cdae367365 100644 --- a/lib/rubygems/commands/build_command.rb +++ b/lib/rubygems/commands/build_command.rb @@ -23,32 +23,34 @@ class Gem::Commands::BuildCommand < Gem::Command def execute gemspec = get_one_gem_name - if File.exist?(gemspec) - specs = load_gemspecs(gemspec) - specs.each do |spec| + + if File.exist? gemspec + spec = load_gemspec gemspec + + if spec then Gem::Builder.new(spec).build + else + alert_error "Error loading gemspec. Aborting." + terminate_interaction 1 end else alert_error "Gemspec file not found: #{gemspec}" + terminate_interaction 1 end end - def load_gemspecs(filename) + def load_gemspec filename if yaml?(filename) - result = [] open(filename) do |f| begin - while not f.eof? and spec = Gem::Specification.from_yaml(f) - result << spec - end + Gem::Specification.from_yaml(f) rescue Gem::EndOfYAMLException - # OK + nil end end else - result = [Gem::Specification.load(filename)] + Gem::Specification.load(filename) # can return nil end - result end def yaml?(filename) diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb index 17eaaa113f..d667f5c3a3 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -56,7 +56,7 @@ class Gem::Commands::CertCommand < Gem::Command 'Build private key and self-signed', 'certificate for EMAIL_ADDR.') do |value, options| vals = Gem::Security.build_self_signed_cert(value) - File.chmod 0600, vals[:key_path] + FileUtils.chmod 0600, vals[:key_path] say "Public Cert: #{vals[:cert_path]}" say "Private Key: #{vals[:key_path]}" say "Don't forget to move the key file to somewhere private..." diff --git a/lib/rubygems/commands/cleanup_command.rb b/lib/rubygems/commands/cleanup_command.rb index 0cdf50433e..2d8d8ff4fc 100644 --- a/lib/rubygems/commands/cleanup_command.rb +++ b/lib/rubygems/commands/cleanup_command.rb @@ -5,7 +5,6 @@ ###################################################################### require 'rubygems/command' -require 'rubygems/source_index' require 'rubygems/dependency_list' require 'rubygems/uninstaller' @@ -44,28 +43,20 @@ installed elsewhere in GEM_PATH the cleanup command won't touch it. say "Cleaning up installed gems..." primary_gems = {} - Gem.source_index.each do |name, spec| + Gem::Specification.each do |spec| if primary_gems[spec.name].nil? or primary_gems[spec.name].version < spec.version then primary_gems[spec.name] = spec end end - gems_to_cleanup = [] - - unless options[:args].empty? then - options[:args].each do |gem_name| - dep = Gem::Dependency.new gem_name, Gem::Requirement.default - specs = Gem.source_index.search dep - specs.each do |spec| - gems_to_cleanup << spec - end - end - else - Gem.source_index.each do |name, spec| - gems_to_cleanup << spec - end - end + gems_to_cleanup = unless options[:args].empty? then + options[:args].map do |gem_name| + Gem::Specification.find_all_by_name gem_name + end.flatten + else + Gem::Specification.to_a + end gems_to_cleanup = gems_to_cleanup.select { |spec| primary_gems[spec.name].version != spec.version @@ -89,8 +80,8 @@ installed elsewhere in GEM_PATH the cleanup command won't touch it. :version => "= #{spec.version}", } - if Gem.user_dir == spec.installation_path then - uninstall_options[:install_dir] = spec.installation_path + if Gem.user_dir == spec.base_dir then + uninstall_options[:install_dir] = spec.base_dir end uninstaller = Gem::Uninstaller.new spec.name, uninstall_options diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb index 42ae913b01..8e015ae9da 100644 --- a/lib/rubygems/commands/contents_command.rb +++ b/lib/rubygems/commands/contents_command.rb @@ -58,24 +58,24 @@ class Gem::Commands::ContentsCommand < Gem::Command end.flatten path_kind = if spec_dirs.empty? then - spec_dirs = Gem::SourceIndex.installed_spec_directories + spec_dirs = Gem::Specification.dirs "default gem paths" else "specified path" end - si = Gem::SourceIndex.from_gems_in(*spec_dirs) - gem_names = if options[:all] then - si.map { |_, spec| spec.name } + Gem::Specification.map(&:name) else get_all_gem_names end gem_names.each do |name| - gem_spec = si.find_name(name, version).last + # 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 gem_spec then + unless spec then say "Unable to find gem '#{name}' in #{path_kind}" if Gem.configuration.verbose then @@ -86,16 +86,19 @@ class Gem::Commands::ContentsCommand < Gem::Command terminate_interaction 1 if gem_names.length == 1 end - files = options[:lib_only] ? gem_spec.lib_files : gem_spec.files + gem_path = spec.full_gem_path + extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only] + glob = "#{gem_path}#{extra}/**/*" + files = Dir[glob] + + gem_path = File.join gem_path, '' # add trailing / if missing + + files.sort.each do |file| + next if File.directory? file - files.each do |f| - path = if options[:prefix] then - File.join gem_spec.full_gem_path, f - else - f - end + file = file.sub gem_path, '' unless options[:prefix] - say path + say file end end end diff --git a/lib/rubygems/commands/dependency_command.rb b/lib/rubygems/commands/dependency_command.rb index b6840c35d4..209fdebd50 100644 --- a/lib/rubygems/commands/dependency_command.rb +++ b/lib/rubygems/commands/dependency_command.rb @@ -49,13 +49,13 @@ class Gem::Commands::DependencyCommand < Gem::Command end def execute - options[:args] << '' if options[:args].empty? - specs = {} - - source_indexes = Hash.new do |h, source_uri| - h[source_uri] = Gem::SourceIndex.new + if options[:reverse_dependencies] and remote? and not local? then + alert_error 'Only reverse dependencies for local gems are supported.' + terminate_interaction 1 end + options[:args] << '' if options[:args].empty? + pattern = if options[:args].length == 1 and options[:args].first =~ /\A\/(.*)\/(i)?\z/m then flags = $2 ? Regexp::IGNORECASE : nil @@ -64,34 +64,30 @@ class Gem::Commands::DependencyCommand < Gem::Command /\A#{Regexp.union(*options[:args])}/ end - dependency = Gem::Dependency.new pattern, options[:version] + # TODO: deprecate for real damnit + dependency = Deprecate.skip_during { + Gem::Dependency.new pattern, options[:version] + } dependency.prerelease = options[:prerelease] - if options[:reverse_dependencies] and remote? and not local? then - alert_error 'Only reverse dependencies for local gems are supported.' - terminate_interaction 1 - end + specs = [] - if local? then - Gem.source_index.search(dependency).each do |spec| - source_indexes[:local].add_spec spec - end - end + specs.concat dependency.matching_specs if local? if remote? and not options[:reverse_dependencies] then fetcher = Gem::SpecFetcher.fetcher - specs_and_sources = fetcher.find_matching(dependency, false, true, + # REFACTOR: fetcher.find_specs_matching => specs + specs_and_sources = fetcher.find_matching(dependency, + dependency.specific?, true, dependency.prerelease?) - specs_and_sources.each do |spec_tuple, source_uri| - spec = fetcher.fetch_spec spec_tuple, URI.parse(source_uri) - - source_indexes[source_uri].add_spec spec - end + specs.concat specs_and_sources.map { |spec_tuple, source_uri| + fetcher.fetch_spec spec_tuple, URI.parse(source_uri) + } end - if source_indexes.empty? then + if specs.empty? then patterns = options[:args].join ',' say "No gems found matching #{patterns} (#{options[:version]})" if Gem.configuration.verbose @@ -99,24 +95,18 @@ class Gem::Commands::DependencyCommand < Gem::Command terminate_interaction 1 end - specs = {} - - source_indexes.values.each do |source_index| - source_index.gems.each do |name, spec| - specs[spec.full_name] = [source_index, spec] - end - end + specs = specs.uniq.sort reverse = Hash.new { |h, k| h[k] = [] } if options[:reverse_dependencies] then - specs.values.each do |_, spec| + specs.each do |spec| reverse[spec.full_name] = find_reverse_dependencies spec end end if options[:pipe_format] then - specs.values.sort_by { |_, spec| spec }.each do |_, spec| + specs.each do |spec| unless spec.dependencies.empty? spec.dependencies.sort_by { |dep| dep.name }.each do |dep| say "#{dep.name} --version '#{dep.requirement}'" @@ -126,7 +116,7 @@ class Gem::Commands::DependencyCommand < Gem::Command else response = '' - specs.values.sort_by { |_, spec| spec }.each do |_, spec| + specs.each do |spec| response << print_dependencies(spec) unless reverse[spec.full_name].empty? then response << " Used by\n" @@ -158,7 +148,7 @@ class Gem::Commands::DependencyCommand < Gem::Command def find_reverse_dependencies(spec) result = [] - Gem.source_index.each do |name, sp| + Gem::Specification.each do |sp| sp.dependencies.each do |dep| dep = Gem::Dependency.new(*dep) unless Gem::Dependency === dep @@ -172,17 +162,5 @@ class Gem::Commands::DependencyCommand < Gem::Command result end - def find_gems(name, source_index) - specs = {} - - spec_list = source_index.search name, options[:version] - - spec_list.each do |spec| - specs[spec.full_name] = [source_index, spec] - end - - specs - end - end diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb index c0fdc83e46..7d99276506 100644 --- a/lib/rubygems/commands/fetch_command.rb +++ b/lib/rubygems/commands/fetch_command.rb @@ -41,19 +41,22 @@ class Gem::Commands::FetchCommand < Gem::Command version = options[:version] || Gem::Requirement.default all = Gem::Requirement.default != version + platform = Gem.platforms.last gem_names = get_all_gem_names gem_names.each do |gem_name| dep = Gem::Dependency.new gem_name, version dep.prerelease = options[:prerelease] - specs_and_sources = Gem::SpecFetcher.fetcher.fetch(dep, all, true, - dep.prerelease?) - specs_and_sources, errors = Gem::SpecFetcher.fetcher.fetch_with_errors(dep, all, true, dep.prerelease?) + if platform then + filtered = specs_and_sources.select { |s,| s.platform == platform } + specs_and_sources = filtered unless filtered.empty? + end + spec, source_uri = specs_and_sources.sort_by { |s,| s.version }.last if spec.nil? then @@ -62,7 +65,7 @@ class Gem::Commands::FetchCommand < Gem::Command end path = Gem::RemoteFetcher.fetcher.download spec, source_uri - FileUtils.mv path, spec.file_name + FileUtils.mv path, File.basename(spec.cache_file) say "Downloaded #{spec.full_name}" end diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index 530f746e89..fff41cf6e0 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -120,7 +120,8 @@ to write the specification by hand. For example: get_all_gem_names.each do |gem_name| begin - next if options[:conservative] && Gem.available?(gem_name, options[:version]) + next if options[:conservative] and + not Gem::Dependency.new(gem_name, options[:version]).matching_specs.empty? inst = Gem::DependencyInstaller.new options inst.install gem_name, options[:version] diff --git a/lib/rubygems/commands/lock_command.rb b/lib/rubygems/commands/lock_command.rb index a17dd36d7a..9ce9da6899 100644 --- a/lib/rubygems/commands/lock_command.rb +++ b/lib/rubygems/commands/lock_command.rb @@ -93,7 +93,7 @@ lock it down to the exact version. spec.runtime_dependencies.each do |dep| next if locked[dep.name] - candidates = Gem.source_index.search dep + candidates = dep.matching_specs if candidates.empty? then complain "Unable to satisfy '#{dep}' from currently installed gems" @@ -105,11 +105,11 @@ lock it down to the exact version. end def spec_path(gem_full_name) - gemspecs = Gem.path.map do |path| + gemspecs = Gem.path.map { |path| File.join path, "specifications", "#{gem_full_name}.gemspec" - end + } - gemspecs.find { |gemspec| File.exist? gemspec } + gemspecs.find { |path| File.exist? path } end end diff --git a/lib/rubygems/commands/outdated_command.rb b/lib/rubygems/commands/outdated_command.rb index 7b6e1cfe8e..8b7dda6c7d 100644 --- a/lib/rubygems/commands/outdated_command.rb +++ b/lib/rubygems/commands/outdated_command.rb @@ -22,10 +22,8 @@ class Gem::Commands::OutdatedCommand < Gem::Command end def execute - locals = Gem::SourceIndex.from_installed_gems - - locals.outdated.sort.each do |name| - local = locals.find_name(name).last + 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.fetch dep @@ -35,6 +33,4 @@ class Gem::Commands::OutdatedCommand < Gem::Command say "#{local.name} (#{local.version} < #{remote.version})" end end - end - diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index 9a0b2e9f11..99722756ee 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -16,7 +16,8 @@ class Gem::Commands::PristineCommand < Gem::Command def initialize super 'pristine', 'Restores installed gems to pristine condition from files located in the gem cache', - :version => Gem::Requirement.default + :version => Gem::Requirement.default, :extensions => true, + :all => false add_option('--all', 'Restore all installed gems to pristine', @@ -24,6 +25,11 @@ class Gem::Commands::PristineCommand < Gem::Command options[:all] = value end + add_option('--[no-]extensions', + 'Restore gems with extensions') do |value, options| + options[:extensions] = value + end + add_version_option('restore to', 'pristine condition') end @@ -32,7 +38,7 @@ class Gem::Commands::PristineCommand < Gem::Command end def defaults_str # :nodoc: - "--all" + "--all --extensions" end def description # :nodoc: @@ -46,6 +52,9 @@ for the gem are regenerated. If the cached gem cannot be found, you will need to use `gem install` to revert the gem. + +If --no-extensions is provided pristine will not attempt to restore gems with +extensions. EOF end @@ -54,21 +63,17 @@ revert the gem. end def execute - gem_name = nil - specs = if options[:all] then - Gem::SourceIndex.from_installed_gems.map do |name, spec| - spec - end + Gem::Specification.map else - gem_name = get_one_gem_name - Gem::SourceIndex.from_installed_gems.find_name(gem_name, - options[:version]) + get_all_gem_names.map do |gem_name| + Gem::Specification.find_all_by_name gem_name, options[:version] + end.flatten end - if specs.empty? then + if specs.to_a.empty? then raise Gem::Exception, - "Failed to find gem #{gem_name} #{options[:version]}" + "Failed to find gems #{options[:args]} #{options[:version]}" end install_dir = Gem.dir # TODO use installer option @@ -76,25 +81,32 @@ revert the gem. raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir) - say "Restoring gem(s) to pristine condition..." + say "Restoring gems to pristine condition..." specs.each do |spec| - gem = spec.cache_gem + unless spec.extensions.empty? or options[:extensions] then + say "Skipped #{spec.full_name}, it needs to compile an extension" + next + end + + gem = spec.cache_file + + unless File.exist? gem then + require 'rubygems/remote_fetcher' - if gem.nil? then say "Cached gem for #{spec.full_name} not found, attempting to fetch..." dep = Gem::Dependency.new spec.name, spec.version Gem::RemoteFetcher.fetcher.download_to_cache dep - gem = spec.cache_gem end # TODO use installer options - installer = Gem::Installer.new gem, :wrappers => true, :force => true + installer = Gem::Installer.new(gem, + :wrappers => true, + :force => true, + :install_dir => spec.base_dir) installer.install say "Restored #{spec.full_name}" end end - end - diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb index 29e53065e7..d82f8aea60 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -80,10 +80,12 @@ class Gem::Commands::QueryCommand < Gem::Command exit_code |= 1 end - raise Gem::SystemExitException, exit_code + terminate_interaction exit_code end - dep = Gem::Dependency.new name, Gem::Requirement.default + req = Gem::Requirement.default + # TODO: deprecate for real + dep = Deprecate.skip_during { Gem::Dependency.new name, req } if local? then if prerelease and not both? then @@ -96,7 +98,9 @@ class Gem::Commands::QueryCommand < Gem::Command say end - specs = Gem.source_index.search dep + specs = Gem::Specification.find_all { |s| + s.name =~ name and req =~ s.version + } spec_tuples = specs.map do |spec| [[spec.name, spec.version, spec.original_platform, spec], :local] @@ -129,9 +133,8 @@ class Gem::Commands::QueryCommand < Gem::Command ## # Check if gem +name+ version +version+ is installed. - def installed?(name, version = Gem::Requirement.default) - dep = Gem::Dependency.new name, version - !Gem.source_index.search(dep).empty? + def installed?(name, req = Gem::Requirement.default) + Gem::Specification.any? { |s| s.name =~ name and req =~ s.version } end def output_query_results(spec_tuples) diff --git a/lib/rubygems/commands/server_command.rb b/lib/rubygems/commands/server_command.rb index c59f216262..0d18a82201 100644 --- a/lib/rubygems/commands/server_command.rb +++ b/lib/rubygems/commands/server_command.rb @@ -50,7 +50,7 @@ class Gem::Commands::ServerCommand < Gem::Command options[:addresses].push(*address) end - add_option '-l', '--launch[=COMMAND]', + add_option '-l', '--launch[=COMMAND]', 'launches a browser window', "COMMAND defaults to 'start' on Windows", "and 'open' on all other platforms" do |launch, options| diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index cf844c6674..6aa80054a0 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -338,7 +338,7 @@ abort "#{deprecation_message}" args << '--main' << 'README.rdoc' << '--quiet' args << '.' args << 'README.rdoc' << 'UPGRADING.rdoc' - args << 'LICENSE.txt' << 'GPL.txt' << 'History.txt' + args << 'LICENSE.txt' << 'MIT.txt' << 'History.txt' r = RDoc::RDoc.new r.document args diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb index 987e401042..e4036aea78 100644 --- a/lib/rubygems/commands/specification_command.rb +++ b/lib/rubygems/commands/specification_command.rb @@ -72,18 +72,8 @@ FIELD name of gemspec field to show field = get_one_optional_argument - if field then - field = field.intern - - if options[:format] == :ruby then - raise Gem::CommandLineError, "--ruby and FIELD are mutually exclusive" - end - - unless Gem::Specification.attribute_names.include? field then - raise Gem::CommandLineError, - "no field %p on Gem::Specification" % field.to_s - end - end + raise Gem::CommandLineError, "--ruby and FIELD are mutually exclusive" if + field and options[:format] == :ruby if local? then if File.exist? gem then @@ -91,7 +81,7 @@ FIELD name of gemspec field to show end if specs.empty? then - specs.push(*Gem.source_index.search(dep)) + specs.push(*dep.matching_specs) end end @@ -106,7 +96,11 @@ FIELD name of gemspec field to show terminate_interaction 1 end - output = lambda do |s| + unless options[:all] then + specs = [specs.sort_by { |s| s.version }.last] + end + + specs.each do |s| s = s.send field if field say case options[:format] @@ -117,14 +111,5 @@ FIELD name of gemspec field to show say "\n" end - - if options[:all] then - specs.each(&output) - else - spec = specs.sort_by { |s| s.version }.last - output[spec] - end end - end - diff --git a/lib/rubygems/commands/stale_command.rb b/lib/rubygems/commands/stale_command.rb index 9a024faa6d..712e62aa22 100644 --- a/lib/rubygems/commands/stale_command.rb +++ b/lib/rubygems/commands/stale_command.rb @@ -17,7 +17,8 @@ class Gem::Commands::StaleCommand < Gem::Command def execute gem_to_atime = {} - Gem.source_index.each do |name, spec| + Gem::Specification.each do |spec| + name = spec.full_name Dir["#{spec.full_gem_path}/**/*.*"].each do |file| next if File.directory?(file) stat = File.stat(file) diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb index ef0d65e073..b0fa2bfb05 100644 --- a/lib/rubygems/commands/unpack_command.rb +++ b/lib/rubygems/commands/unpack_command.rb @@ -25,6 +25,10 @@ class Gem::Commands::UnpackCommand < Gem::Command options[:target] = value end + add_option('--spec', 'unpack the gem specification') do |value, options| + options[:spec] = true + end + add_version_option end @@ -50,14 +54,30 @@ class Gem::Commands::UnpackCommand < Gem::Command dependency = Gem::Dependency.new name, options[:version] path = get_path dependency - if path then + unless path then + alert_error "Gem '#{name}' not installed nor fetchable." + next + end + + if @options[:spec] then + spec, metadata = get_metadata path + + if metadata.nil? then + alert_error "--spec is unsupported on '#{name}' (old format gem)" + next + end + + spec_file = File.basename spec.spec_file + + open spec_file, 'w' do |io| + io.write metadata + end + else basename = File.basename path, '.gem' target_dir = File.expand_path basename, options[:target] FileUtils.mkdir_p target_dir Gem::Installer.new(path, :unpack => true).unpack target_dir say "Unpacked gem: '#{target_dir}'" - else - alert_error "Gem '#{name}' not installed." end end end @@ -70,9 +90,8 @@ class Gem::Commands::UnpackCommand < Gem::Command # TODO: see comments in get_path() about general service. def find_in_cache(filename) - Gem.path.each do |path| - this_path = Gem.cache_gem(filename, path) + this_path = File.join(path, "cache", filename) return this_path if File.exist? this_path end @@ -99,9 +118,9 @@ class Gem::Commands::UnpackCommand < Gem::Command def get_path dependency return dependency.name if dependency.name =~ /\.gem$/i - specs = Gem.source_index.search dependency + specs = dependency.matching_specs - selected = specs.sort_by { |s| s.version }.last + selected = specs.sort_by { |s| s.version }.last # HACK: hunt last down return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless selected @@ -111,12 +130,37 @@ class Gem::Commands::UnpackCommand < Gem::Command # We expect to find (basename).gem in the 'cache' directory. Furthermore, # the name match must be exact (ignoring case). - path = find_in_cache selected.file_name + path = find_in_cache File.basename selected.cache_file return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless path path end + ## + # Extracts the Gem::Specification and raw metadata from the .gem file at + # +path+. + + def get_metadata path + format = Gem::Format.from_file_by_path path + spec = format.spec + + metadata = nil + + open path, Gem.binary_mode do |io| + tar = Gem::Package::TarReader.new io + tar.each_entry do |entry| + case entry.full_name + when 'metadata' then + metadata = entry.read + when 'metadata.gz' then + metadata = Gem.gunzip entry.read + end + end + end + + return spec, metadata + end + end diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index b7c65eb2a4..2d7da445cb 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -71,14 +71,14 @@ class Gem::Commands::UpdateCommand < Gem::Command hig = {} # highest installed gems - Gem.source_index.each do |name, spec| + 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] + gems_to_update = which_to_update hig, options[:args].uniq updated = update_gems gems_to_update @@ -123,8 +123,8 @@ class Gem::Commands::UpdateCommand < Gem::Command end def update_gems gems_to_update - gems_to_update.uniq.sort.each do |name| - update_gem name + gems_to_update.uniq.sort.each do |(name, version)| + update_gem name, version end @updated @@ -141,6 +141,9 @@ class Gem::Commands::UpdateCommand < Gem::Command options[:user_install] = false + # TODO: rename version and other variable name conflicts + # TODO: get rid of all this indirection on name and other BS + version = options[:system] if version == true then version = Gem::Version.new Gem::VERSION @@ -158,18 +161,25 @@ class Gem::Commands::UpdateCommand < Gem::Command 'rubygems-update' => rubygems_update } - gems_to_update = which_to_update hig, options[:args] + gems_to_update = which_to_update hig, options[:args], :system + name, up_ver = gems_to_update.first + current_ver = Gem::Version.new Gem::VERSION + + target = if options[:system] == true then + up_ver + else + version + end - if gems_to_update.empty? then + if current_ver == target then + # if options[:system] != true and version == current_ver then say "Latest version currently installed. Aborting." terminate_interaction end - update_gem gems_to_update.first, requirement + update_gem name, target - Gem.source_index.refresh! - - installed_gems = Gem.source_index.find_name 'rubygems-update', requirement + installed_gems = Gem::Specification.find_all_by_name 'rubygems-update', requirement version = installed_gems.last.version args = [] @@ -193,7 +203,7 @@ class Gem::Commands::UpdateCommand < Gem::Command end end - def which_to_update(highest_installed_gems, gem_names) + def which_to_update highest_installed_gems, gem_names, system = false result = [] highest_installed_gems.each do |l_name, l_spec| @@ -213,9 +223,11 @@ class Gem::Commands::UpdateCommand < Gem::Command version end.last - if highest_remote_gem and - l_spec.version < highest_remote_gem.first[1] then - result << l_name + highest_remote_gem ||= [[nil, Gem::Version.new(0), nil]] # "null" object + highest_remote_ver = highest_remote_gem.first[1] + + if system or (l_spec.version < highest_remote_ver) then + result << [l_spec.name, [l_spec.version, highest_remote_ver].max] end end diff --git a/lib/rubygems/commands/which_command.rb b/lib/rubygems/commands/which_command.rb index aeb91f203c..2962491bde 100644 --- a/lib/rubygems/commands/which_command.rb +++ b/lib/rubygems/commands/which_command.rb @@ -5,12 +5,8 @@ ###################################################################### require 'rubygems/command' -require 'rubygems/gem_path_searcher' class Gem::Commands::WhichCommand < Gem::Command - - EXT = %w[.rb .rbw .so .dll .bundle] # HACK - def initialize super 'which', 'Find the location of a library file you can require', :search_gems_first => false, :show_all => false @@ -34,14 +30,13 @@ class Gem::Commands::WhichCommand < Gem::Command end def execute - searcher = Gem::GemPathSearcher.new - found = false options[:args].each do |arg| - arg = arg.sub(/#{Regexp.union(*EXT)}$/, '') + arg = arg.sub(/#{Regexp.union(*Gem.suffixes)}$/, '') dirs = $LOAD_PATH - spec = searcher.find arg + + spec = Gem::Specification.find_by_path arg if spec then if options[:search_gems_first] then @@ -51,6 +46,7 @@ class Gem::Commands::WhichCommand < Gem::Command end end + # TODO: this is totally redundant and stupid paths = find_paths arg, dirs if paths.empty? then @@ -68,7 +64,7 @@ class Gem::Commands::WhichCommand < Gem::Command result = [] dirs.each do |dir| - EXT.each do |ext| + Gem.suffixes.each do |ext| full_path = File.join dir, "#{package_name}#{ext}" if File.exist? full_path then result << full_path diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 1d16cd90ce..d005755f48 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -207,11 +207,15 @@ class Gem::ConfigFile # Location of RubyGems.org credentials def credentials_path - File.join(Gem.user_home, '.gem', 'credentials') + File.join Gem.user_home, '.gem', 'credentials' end def load_api_keys - @api_keys = File.exists?(credentials_path) ? load_file(credentials_path) : @hash + @api_keys = if File.exist? credentials_path then + load_file(credentials_path) + else + @hash + end if @api_keys.key? :rubygems_api_key then @rubygems_api_key = @api_keys[:rubygems_api_key] @api_keys[:rubygems] = @api_keys.delete :rubygems_api_key unless @api_keys.key? :rubygems @@ -221,8 +225,8 @@ class Gem::ConfigFile def rubygems_api_key=(api_key) config = load_file(credentials_path).merge(:rubygems_api_key => api_key) - dirname = File.dirname(credentials_path) - Dir.mkdir(dirname) unless File.exists?(dirname) + dirname = File.dirname credentials_path + Dir.mkdir(dirname) unless File.exist? dirname Gem.load_yaml @@ -236,7 +240,7 @@ class Gem::ConfigFile def load_file(filename) Gem.load_yaml - return {} unless filename and File.exists?(filename) + return {} unless filename and File.exist? filename begin YAML.load(File.read(filename)) rescue ArgumentError @@ -360,6 +364,4 @@ class Gem::ConfigFile protected attr_reader :hash - end - diff --git a/lib/rubygems/custom_require.rb b/lib/rubygems/custom_require.rb index eaa04b31c3..f32d1007c9 100644 --- a/lib/rubygems/custom_require.rb +++ b/lib/rubygems/custom_require.rb @@ -41,19 +41,20 @@ module Kernel if Gem.unresolved_deps.empty? or Gem.loaded_path? path then gem_original_require path else - spec = Gem.searcher.find_active path + spec = Gem::Specification.find { |s| + s.activated? and s.contains_requirable_file? path + } unless spec then - found_specs = Gem.searcher.find_in_unresolved path + found_specs = Gem::Specification.find_in_unresolved path unless found_specs.empty? then found_specs = [found_specs.last] else - found_specs = Gem.searcher.find_in_unresolved_tree path + found_specs = Gem::Specification.find_in_unresolved_tree path end found_specs.each do |found_spec| - # FIX: this is dumb, activate a spec instead of name/version - Gem.activate found_spec.name, found_spec.version + found_spec.activate end end diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb index 63ccd85e2a..714dc4fb2f 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb @@ -6,6 +6,8 @@ module Gem + # TODO: move this whole file back into rubygems.rb + @post_install_hooks ||= [] @post_uninstall_hooks ||= [] @pre_uninstall_hooks ||= [] @@ -23,16 +25,28 @@ module Gem # specified in the environment def self.default_dir - if defined? RUBY_FRAMEWORK_VERSION then - File.join File.dirname(ConfigMap[:sitedir]), 'Gems', - ConfigMap[:ruby_version] - elsif ConfigMap[:rubylibprefix] then - File.join(ConfigMap[:rubylibprefix], 'gems', - ConfigMap[:ruby_version]) - else - File.join(ConfigMap[:libdir], ruby_engine, 'gems', - ConfigMap[:ruby_version]) - end + path = if defined? RUBY_FRAMEWORK_VERSION then + [ + File.dirname(ConfigMap[:sitedir]), + 'Gems', + ConfigMap[:ruby_version] + ] + elsif ConfigMap[:rubylibprefix] then + [ + ConfigMap[:rubylibprefix], + 'gems', + ConfigMap[:ruby_version] + ] + else + [ + ConfigMap[:libdir], + ruby_engine, + 'gems', + ConfigMap[:ruby_version] + ] + end + + @default_dir ||= File.join(*path) end ## @@ -82,14 +96,18 @@ module Gem # The default system-wide source info cache directory def self.default_system_source_cache_dir - File.join Gem.dir, 'source_cache' + File.join(Gem.dir, 'source_cache') end ## # The default user-specific source info cache directory def self.default_user_source_cache_dir - File.join Gem.user_home, '.gem', 'source_cache' + # + # NOTE Probably an argument for moving this to per-ruby supported dirs like + # user_dir + # + File.join(Gem.user_home, '.gem', 'source_cache') end ## @@ -102,6 +120,4 @@ module Gem 'ruby' end end - end - diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index e4d1bfffe8..1261154fe9 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -38,6 +38,12 @@ class Gem::Dependency # :runtime. def initialize name, *requirements + if Regexp === name then + msg = ["NOTE: Dependency.new w/ a regexp is deprecated.", + "Dependency.new called from #{Gem.location_of_caller.join(":")}"] + warn msg.join("\n") unless Deprecate.skip + end + type = Symbol === requirements.last ? requirements.pop : :runtime requirements = requirements.first if 1 == requirements.length # unpack @@ -212,5 +218,49 @@ class Gem::Dependency self.class.new name, self_req.as_list.concat(other_req.as_list) end -end + def matching_specs platform_only = false + matches = Gem::Specification.find_all { |spec| + self.name === spec.name and # TODO: == instead of === + requirement.satisfied_by? spec.version + } + + if platform_only + matches.reject! { |spec| + not Gem::Platform.match spec.platform + } + end + + matches = matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed + end + + ## + # True if the dependency will not always match the latest version. + + def specific? + @requirement.specific? + end + def to_specs + matches = matching_specs true + + # TODO: check Gem.activated_spec[self.name] in case matches falls outside + + if matches.empty? then + specs = Gem::Specification.all_names.join ", " + error = Gem::LoadError.new "Could not find #{name} (#{requirement}) amongst [#{specs}]" + error.name = self.name + error.requirement = self.requirement + raise error + end + + # TODO: any other resolver validations should go here + + matches + end + + def to_spec + matches = self.to_specs + + matches.find { |spec| spec.activated? } or matches.last + end +end diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index 5afb1bfa0d..29e8b21643 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -21,14 +21,14 @@ class Gem::DependencyInstaller attr_reader :installed_gems DEFAULT_OPTIONS = { - :env_shebang => false, - :domain => :both, # HACK dup - :force => false, - :format_executable => false, # HACK dup + :env_shebang => false, + :domain => :both, # HACK dup + :force => false, + :format_executable => false, # HACK dup :ignore_dependencies => false, - :prerelease => false, - :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low? - :wrappers => true, + :prerelease => false, + :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low? + :wrappers => true, } ## @@ -51,25 +51,26 @@ class Gem::DependencyInstaller def initialize(options = {}) if options[:install_dir] then - spec_dir = options[:install_dir], 'specifications' - @source_index = Gem::SourceIndex.from_gems_in spec_dir - else - @source_index = Gem.source_index + @gem_home = options[:install_dir] + + Gem::Specification.dirs = @gem_home + Gem.ensure_gem_subdirectories @gem_home + options[:install_dir] = @gem_home # FIX: because we suck and reuse below end options = DEFAULT_OPTIONS.merge options - @bin_dir = options[:bin_dir] - @development = options[:development] - @domain = options[:domain] - @env_shebang = options[:env_shebang] - @force = options[:force] - @format_executable = options[:format_executable] + @bin_dir = options[:bin_dir] + @development = options[:development] + @domain = options[:domain] + @env_shebang = options[:env_shebang] + @force = options[:force] + @format_executable = options[:format_executable] @ignore_dependencies = options[:ignore_dependencies] - @prerelease = options[:prerelease] - @security_policy = options[:security_policy] - @user_install = options[:user_install] - @wrappers = options[:wrappers] + @prerelease = options[:prerelease] + @security_policy = options[:security_policy] + @user_install = options[:user_install] + @wrappers = options[:wrappers] @installed_gems = [] @@ -101,6 +102,7 @@ class Gem::DependencyInstaller if @domain == :both or @domain == :remote then begin + # REFACTOR: all = dep.requirement.needs_all? requirements = dep.requirement.requirements.map do |req, ver| req end @@ -146,8 +148,8 @@ class Gem::DependencyInstaller add_found_dependencies to_do, dependency_list unless @ignore_dependencies dependency_list.specs.reject! { |spec| - ! keep_names.include? spec.full_name and - @source_index.any? { |n,_| n == spec.full_name } + not keep_names.include?(spec.full_name) and + Gem::Specification.include?(spec) } unless dependency_list.ok? or @ignore_dependencies or @force then @@ -181,7 +183,7 @@ class Gem::DependencyInstaller to_do.push dep_spec # already locally installed - @source_index.any? do |_, installed_spec| + Gem::Specification.any? do |installed_spec| dep.name == installed_spec.name and dep.requirement.satisfied_by? installed_spec.version end @@ -216,23 +218,20 @@ class Gem::DependencyInstaller local_gems = Dir["#{glob}*"].sort.reverse - unless local_gems.empty? then - local_gems.each do |gem_file| - next unless gem_file =~ /gem$/ - begin - spec = Gem::Format.from_file_by_path(gem_file).spec - spec_and_source = [spec, gem_file] - break - rescue SystemCallError, Gem::Package::FormatError - end + local_gems.each do |gem_file| + next unless gem_file =~ /gem$/ + begin + spec = Gem::Format.from_file_by_path(gem_file).spec + spec_and_source = [spec, gem_file] + break + rescue SystemCallError, Gem::Package::FormatError end end - if spec_and_source.nil? then + unless spec_and_source then dep = Gem::Dependency.new gem_name, version dep.prerelease = true if prerelease spec_and_sources = find_gems_with_sources(dep).reverse - spec_and_source = spec_and_sources.find { |spec, source| Gem::Platform.match spec.platform } @@ -273,9 +272,9 @@ class Gem::DependencyInstaller gather_dependencies - @gems_to_install.each do |spec| - last = spec == @gems_to_install.last - next if @source_index.any? { |n,_| n == spec.full_name } and not last + last = @gems_to_install.size - 1 + @gems_to_install.each_with_index do |spec, index| + 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 @@ -298,7 +297,6 @@ class Gem::DependencyInstaller :ignore_dependencies => @ignore_dependencies, :install_dir => @install_dir, :security_policy => @security_policy, - :source_index => @source_index, :user_install => @user_install, :wrappers => @wrappers @@ -309,6 +307,4 @@ class Gem::DependencyInstaller @installed_gems end - end - diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb index a3db1d6829..232f83c68c 100644 --- a/lib/rubygems/dependency_list.rb +++ b/lib/rubygems/dependency_list.rb @@ -11,6 +11,7 @@ #++ require 'tsort' +require 'rubygems/deprecate' ## # Gem::DependencyList is used for installing and uninstalling gems in the @@ -28,16 +29,21 @@ class Gem::DependencyList attr_accessor :development ## - # Creates a DependencyList from a Gem::SourceIndex +source_index+ + # Creates a DependencyList from the current specs. - def self.from_source_index(source_index) + def self.from_specs list = new + list.add(*Gem::Specification.map) + list + end - source_index.each do |full_name, spec| - list.add spec - end + ## + # Creates a DependencyList from a Gem::SourceIndex +source_index+ - list + def self.from_source_index(ignored=nil) + warn "NOTE: DependencyList.from_source_index ignores it's arg" if ignored + + from_specs end ## @@ -120,10 +126,9 @@ class Gem::DependencyList def why_not_ok? quick = false unsatisfied = Hash.new { |h,k| h[k] = [] } - source_index = Gem.source_index each do |spec| spec.runtime_dependencies.each do |dep| - inst = source_index.any? { |_, installed_spec| + inst = Gem::Specification.any? { |installed_spec| dep.name == installed_spec.name and dep.requirement.satisfied_by? installed_spec.version } @@ -134,6 +139,7 @@ class Gem::DependencyList end end end + unsatisfied end @@ -242,6 +248,11 @@ class Gem::DependencyList def active_count(specs, ignored) specs.count { |spec| ignored[spec.full_name].nil? } end - end +class Gem::DependencyList + class << self + extend Deprecate + deprecate :from_source_index, "from_specs", 2011, 11 + end +end diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb new file mode 100644 index 0000000000..948538da96 --- /dev/null +++ b/lib/rubygems/deprecate.rb @@ -0,0 +1,74 @@ +###################################################################### +# This file is imported from the rubygems project. +# DO NOT make modifications in this repo. They _will_ be reverted! +# File a patch instead and assign it to Ryan Davis or Eric Hodel. +###################################################################### + +## +# Provides a single method +deprecate+ to be used to declare when +# something is going away. +# +# class Legacy +# def self.klass_method +# # ... +# end +# +# def instance_method +# # ... +# end +# +# extend Deprecate +# deprecate :instance_method, "X.z", 2011, 4 +# +# class << self +# extend Deprecate +# deprecate :klass_method, :none, 2011, 4 +# end +# end + +module Deprecate + + def self.skip # :nodoc: + @skip ||= false + end + + def self.skip= v # :nodoc: + @skip = v + end + + ## + # Temporarily turn off warnings. Intended for tests only. + + def skip_during + Deprecate.skip, original = true, Deprecate.skip + yield + ensure + Deprecate.skip = original + end + + ## + # Simple deprecation method that deprecates +name+ by wrapping it up + # in a dummy method. It warns on each call to the dummy method + # telling the user of +repl+ (unless +repl+ is :none) and the + # year/month that it is planned to go away. + + def deprecate name, repl, year, month + class_eval { + old = "_deprecated_#{name}" + alias_method old, name + define_method name do |*args, &block| # TODO: really works on 1.8.7? + klass = self.kind_of? Module + target = klass ? "#{self}." : "#{self.class}#" + msg = [ "NOTE: #{target}#{name} is deprecated", + repl == :none ? " with no replacement" : ", use #{repl}", + ". It will be removed on or after %4d-%02d-01." % [year, month], + "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}", + ] + warn "#{msg.join}." unless Deprecate.skip + send old, *args, &block + end + } + end + + module_function :deprecate, :skip_during +end diff --git a/lib/rubygems/doc_manager.rb b/lib/rubygems/doc_manager.rb index 9cfa31a0a0..20c5281231 100644 --- a/lib/rubygems/doc_manager.rb +++ b/lib/rubygems/doc_manager.rb @@ -92,7 +92,7 @@ class Gem::DocManager def initialize(spec, rdoc_args="") require 'fileutils' @spec = spec - @doc_dir = File.join(spec.installation_path, "doc", spec.full_name) + @doc_dir = spec.doc_dir @rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split end @@ -224,25 +224,24 @@ class Gem::DocManager # Remove RDoc and RI documentation def uninstall_doc - raise Gem::FilePermissionError.new(@spec.installation_path) unless - File.writable? @spec.installation_path + base_dir = @spec.base_dir + raise Gem::FilePermissionError.new base_dir unless File.writable? base_dir - original_name = [ + # TODO: ok... that's twice... ugh + old_name = [ @spec.name, @spec.version, @spec.original_platform].join '-' - doc_dir = File.join @spec.installation_path, 'doc', @spec.full_name + doc_dir = @spec.doc_dir unless File.directory? doc_dir then - doc_dir = File.join @spec.installation_path, 'doc', original_name + doc_dir = File.join File.dirname(doc_dir), old_name end - FileUtils.rm_rf doc_dir - - ri_dir = File.join @spec.installation_path, 'ri', @spec.full_name - + ri_dir = @spec.ri_dir unless File.directory? ri_dir then - ri_dir = File.join @spec.installation_path, 'ri', original_name + ri_dir = File.join File.dirname(ri_dir), old_name end + FileUtils.rm_rf doc_dir FileUtils.rm_rf ri_dir end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 2a147d59f2..29d5af5b12 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -19,7 +19,7 @@ class Gem::Ext::Builder def self.make(dest_path, results) unless File.exist? 'Makefile' then - raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}" + raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}" end mf = File.read('Makefile') diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index ba9fa8a94c..6b7086ce82 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -23,12 +23,12 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder end # Deal with possible spaces in the path, e.g. C:/Program Files - dest_path = '"' + dest_path + '"' if dest_path.include?(' ') + dest_path = '"' + dest_path.to_s + '"' if dest_path.to_s.include?(' ') rake = ENV['rake'] rake ||= begin - "\"#{Gem.ruby}\" -rubygems #{Gem.bin_path('rake')}" + "\"#{Gem.ruby}\" -rubygems #{Gem.bin_path('rake', 'rake')}" rescue Gem::Exception end diff --git a/lib/rubygems/gem_path_searcher.rb b/lib/rubygems/gem_path_searcher.rb index 79c3b0f6c9..36a86dec0a 100644 --- a/lib/rubygems/gem_path_searcher.rb +++ b/lib/rubygems/gem_path_searcher.rb @@ -4,6 +4,9 @@ # File a patch instead and assign it to Ryan Davis or Eric Hodel. ###################################################################### +require "rubygems" +require "rubygems/deprecate" + ## # GemPathSearcher has the capability to find loadable files inside # gems. It generates data up front to speed up searches later. @@ -56,6 +59,15 @@ class Gem::GemPathSearcher end end + # Looks through the available gemspecs and finds the first + # one that contains +file+ as a requirable file. + + def find_spec_for_file(file) + @gemspecs.find do |spec| + return spec if spec.contains_requirable_file?(file) + end + end + def find_active(glob) # HACK violation of encapsulation @gemspecs.find do |spec| @@ -138,9 +150,7 @@ class Gem::GemPathSearcher # in reverse version order. (bar-2, bar-1, foo-2) def init_gemspecs - specs = Gem.source_index.map { |_, spec| spec } - - specs.sort { |a, b| + Gem::Specification.sort { |a, b| names = a.name <=> b.name next names if names.nonzero? b.version <=> a.version @@ -156,5 +166,13 @@ class Gem::GemPathSearcher spec.require_paths end -end + extend Deprecate + deprecate :initialize, :none, 2011, 10 + deprecate :find, :none, 2011, 10 + deprecate :find_active, :none, 2011, 10 + deprecate :find_all, :none, 2011, 10 + deprecate :find_in_unresolved, :none, 2011, 10 + deprecate :find_in_unresolved_tree, :none, 2011, 10 + deprecate :find_spec_for_file, :none, 2011, 10 +end diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb index 1c432ba494..6b5aef3fa7 100644 --- a/lib/rubygems/gem_runner.rb +++ b/lib/rubygems/gem_runner.rb @@ -10,6 +10,7 @@ # See LICENSE.txt for permissions. #++ +require "rubygems" require 'rubygems/command_manager' require 'rubygems/config_file' require 'rubygems/doc_manager' @@ -31,6 +32,7 @@ Gem.load_env_plugins rescue nil class Gem::GemRunner def initialize(options={}) + # TODO: nuke these options @command_manager_class = options[:command_manager] || Gem::CommandManager @config_file_class = options[:config_file] || Gem::ConfigFile @doc_manager_class = options[:doc_manager] || Gem::DocManager @@ -80,7 +82,7 @@ class Gem::GemRunner def do_configuration(args) Gem.configuration = @config_file_class.new(args) - Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath]) + Gem.use_paths Gem.configuration[:gemhome], Gem.configuration[:gempath] Gem::Command.extra_args = Gem.configuration[:gem] @doc_manager_class.configured_args = Gem.configuration[:rdoc] end diff --git a/lib/rubygems/indexer.rb b/lib/rubygems/indexer.rb index 6e481c6790..c367532c43 100644 --- a/lib/rubygems/indexer.rb +++ b/lib/rubygems/indexer.rb @@ -79,7 +79,7 @@ class Gem::Indexer @rss_gems_host = options[:rss_gems_host] @dest_directory = directory - @directory = File.join Dir.tmpdir, "gem_generate_index_#{$$}" + @directory = File.join(Dir.tmpdir, "gem_generate_index_#{$$}") marshal_name = "Marshal.#{Gem.marshal_version}" @@ -87,24 +87,23 @@ class Gem::Indexer @marshal_index = File.join @directory, marshal_name @quick_dir = File.join @directory, 'quick' - @quick_marshal_dir = File.join @quick_dir, marshal_name + @quick_marshal_dir_base = File.join "quick", marshal_name # FIX: UGH @quick_index = File.join @quick_dir, 'index' @latest_index = File.join @quick_dir, 'latest_index' @specs_index = File.join @directory, "specs.#{Gem.marshal_version}" - @latest_specs_index = File.join @directory, - "latest_specs.#{Gem.marshal_version}" - @prerelease_specs_index = File.join(@directory, - "prerelease_specs.#{Gem.marshal_version}") - - @dest_specs_index = File.join @dest_directory, - "specs.#{Gem.marshal_version}" - @dest_latest_specs_index = File.join @dest_directory, - "latest_specs.#{Gem.marshal_version}" - @dest_prerelease_specs_index = File.join @dest_directory, - "prerelease_specs.#{Gem.marshal_version}" + @latest_specs_index = + File.join(@directory, "latest_specs.#{Gem.marshal_version}") + @prerelease_specs_index = + File.join(@directory, "prerelease_specs.#{Gem.marshal_version}") + @dest_specs_index = + File.join(@dest_directory, "specs.#{Gem.marshal_version}") + @dest_latest_specs_index = + File.join(@dest_directory, "latest_specs.#{Gem.marshal_version}") + @dest_prerelease_specs_index = + File.join(@dest_directory, "prerelease_specs.#{Gem.marshal_version}") @rss_index = File.join @directory, 'index.rss' @@ -129,12 +128,16 @@ class Gem::Indexer ## # Build various indicies - def build_indicies(index) + def build_indicies # Marshal gemspecs are used by both modern and legacy RubyGems - build_marshal_gemspecs index - build_legacy_indicies index if @build_legacy - build_modern_indicies index if @build_modern - build_rss index + + Gem::Specification.dirs = [] + Gem::Specification.add_specs(*map_gems_to_specs(gem_file_list)) + + build_marshal_gemspecs + build_legacy_indicies if @build_legacy + build_modern_indicies if @build_modern + build_rss compress_indicies end @@ -142,7 +145,9 @@ class Gem::Indexer ## # Builds indicies for RubyGems older than 1.2.x - def build_legacy_indicies(index) + def build_legacy_indicies + index = collect_specs + say "Generating Marshal master index" Gem.time 'Generated Marshal master index' do @@ -158,16 +163,17 @@ class Gem::Indexer ## # Builds Marshal quick index gemspecs. - def build_marshal_gemspecs(index) - progress = ui.progress_reporter index.size, - "Generating Marshal quick index gemspecs for #{index.size} gems", + def build_marshal_gemspecs + count = Gem::Specification.count + progress = ui.progress_reporter count, + "Generating Marshal quick index gemspecs for #{count} gems", "Complete" files = [] Gem.time 'Generated Marshal quick index gemspecs' do - index.gems.each do |original_name, spec| - spec_file_name = "#{original_name}.gemspec.rz" + Gem::Specification.each do |spec| + spec_file_name = "#{spec.original_name}.gemspec.rz" marshal_name = File.join @quick_marshal_dir, spec_file_name marshal_zipped = Gem.deflate Marshal.dump(spec) @@ -175,7 +181,7 @@ class Gem::Indexer files << marshal_name - progress.updated original_name + progress.updated spec.original_name end progress.done @@ -195,8 +201,8 @@ class Gem::Indexer Gem.time "Generated #{name} index" do open(file, 'wb') do |io| specs = index.map do |*spec| - # We have to splat here because latest_specs is an array, - # while the others are hashes. See the TODO in source_index.rb + # We have to splat here because latest_specs is an array, while the + # others are hashes. spec = spec.flatten.last platform = spec.original_platform @@ -219,13 +225,15 @@ class Gem::Indexer ## # Builds indicies for RubyGems 1.2 and newer. Handles full, latest, prerelease - def build_modern_indicies(index) - build_modern_index(index.released_specs.sort, @specs_index, 'specs') - build_modern_index(index.latest_specs.sort, - @latest_specs_index, - 'latest specs') - build_modern_index(index.prerelease_specs.sort, - @prerelease_specs_index, + def build_modern_indicies + prerelease, released = Gem::Specification.partition { |s| + s.version.prerelease? + } + latest_specs = Gem::Specification.latest_specs + + build_modern_index(released.sort, @specs_index, 'specs') + build_modern_index(latest_specs.sort, @latest_specs_index, 'latest specs') + build_modern_index(prerelease.sort, @prerelease_specs_index, 'prerelease specs') @files += [@specs_index, @@ -240,7 +248,7 @@ class Gem::Indexer # Builds an RSS feed for past two days gem releases according to the gem's # date. - def build_rss(index) + def build_rss if @rss_host.nil? or @rss_gems_host.nil? then if Gem.configuration.really_verbose then alert_warning "no --rss-host or --rss-gems-host, RSS generation disabled" @@ -272,31 +280,18 @@ class Gem::Indexer today = Gem::Specification::TODAY yesterday = today - 86400 - index = index.select do |_, spec| - spec_date = spec.date - - case spec_date - when Date - Time.parse(spec_date.to_s) >= yesterday - when Time - spec_date >= yesterday - end - end - - index = index.select do |_, spec| + index = Gem::Specification.select do |spec| spec_date = spec.date + # TODO: remove this and make YAML based specs properly normalized + spec_date = Time.parse(spec_date.to_s) if Date === spec_date - case spec_date - when Date - Time.parse(spec_date.to_s) <= today - when Time - spec_date <= today - end + spec_date >= yesterday && spec_date <= today end - index.sort_by { |_, spec| [-spec.date.to_i, spec] }.each do |_, spec| - gem_path = CGI.escapeHTML "http://#{@rss_gems_host}/gems/#{spec.file_name}" - size = File.stat(spec.loaded_from).size rescue next + index.sort_by { |spec| [-spec.date.to_i, spec] }.each do |spec| + file_name = File.basename spec.cache_file + gem_path = CGI.escapeHTML "http://#{@rss_gems_host}/gems/#{file_name}" + size = File.stat(spec.loaded_from).size # rescue next description = spec.description || spec.summary || '' authors = Array spec.authors @@ -347,54 +342,56 @@ class Gem::Indexer @files << @rss_index end + def map_gems_to_specs gems + gems.map { |gemfile| + if File.size(gemfile) == 0 then + alert_warning "Skipping zero-length gem: #{gemfile}" + next + end + + begin + spec = Gem::Format.from_file_by_path(gemfile).spec + spec.loaded_from = gemfile + + # HACK: fuck this shit - borks all tests that use pl1 + # if File.basename(gemfile, ".gem") != spec.original_name then + # exp = spec.full_name + # exp << " (#{spec.original_name})" if + # spec.original_name != spec.full_name + # msg = "Skipping misnamed gem: #{gemfile} should be named #{exp}" + # alert_warning msg + # next + # end + + abbreviate spec + sanitize spec + + spec + rescue SignalException => e + alert_error "Received signal, exiting" + raise + rescue Exception => e + msg = ["Unable to process #{gemfile}", + "#{e.message} (#{e.class})", + "\t#{e.backtrace.join "\n\t"}"].join("\n") + alert_error msg + end + }.compact + end + ## # Collect specifications from .gem files from the gem directory. def collect_specs(gems = gem_file_list) - index = Gem::SourceIndex.new - - progress = ui.progress_reporter gems.size, - "Loading #{gems.size} gems from #{@dest_directory}", - "Loaded all gems" + Deprecate.skip_during do + index = Gem::SourceIndex.new - Gem.time 'loaded' do - gems.each do |gemfile| - if File.size(gemfile.to_s) == 0 then - alert_warning "Skipping zero-length gem: #{gemfile}" - next - end - - begin - spec = Gem::Format.from_file_by_path(gemfile).spec - spec.loaded_from = gemfile - - unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then - expected_name = spec.full_name - expected_name << " (#{spec.original_name})" if - spec.original_name != spec.full_name - alert_warning "Skipping misnamed gem: #{gemfile} should be named #{expected_name}" - next - end - - abbreviate spec - sanitize spec - - index.add_spec spec, spec.original_name - - progress.updated spec.original_name - - rescue SignalException => e - alert_error "Received signal, exiting" - raise - rescue Exception => e - alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}" - end + map_gems_to_specs(gems).each do |spec| + index.add_spec spec, spec.original_name end - progress.done + index end - - index end ## @@ -454,7 +451,7 @@ class Gem::Indexer # List of gem file names to index. def gem_file_list - Dir.glob(File.join(@dest_directory, "gems", "*.gem")) + Dir[File.join(@dest_directory, "gems", '*.gem')] end ## @@ -462,8 +459,7 @@ class Gem::Indexer def generate_index make_temp_directories - index = collect_specs - build_indicies index + build_indicies install_indicies rescue SignalException ensure @@ -487,24 +483,22 @@ class Gem::Indexer say "Moving index into production dir #{@dest_directory}" if verbose - files = @files.dup + files = @files files.delete @quick_marshal_dir if files.include? @quick_dir - if files.include? @quick_marshal_dir and - not files.include? @quick_dir then + if files.include? @quick_marshal_dir and not files.include? @quick_dir then files.delete @quick_marshal_dir - quick_marshal_dir = @quick_marshal_dir.sub @directory, '' - dst_name = File.join @dest_directory, quick_marshal_dir + dst_name = File.join(@dest_directory, @quick_marshal_dir_base) FileUtils.mkdir_p File.dirname(dst_name), :verbose => verbose FileUtils.rm_rf dst_name, :verbose => verbose - FileUtils.mv @quick_marshal_dir, dst_name, :verbose => verbose, - :force => true + FileUtils.mv(@quick_marshal_dir, dst_name, + :verbose => verbose, :force => true) end files = files.map do |path| - path.sub @directory, '' + path.sub(/^#{Regexp.escape @directory}\/?/, '') # HACK? end files.each do |file| @@ -512,8 +506,8 @@ class Gem::Indexer dst_name = File.join @dest_directory, file FileUtils.rm_rf dst_name, :verbose => verbose - FileUtils.mv src_name, @dest_directory, :verbose => verbose, - :force => true + FileUtils.mv(src_name, @dest_directory, + :verbose => verbose, :force => true) end end @@ -544,10 +538,10 @@ class Gem::Indexer # be replaced by their XML entity equivalent. def sanitize(spec) - spec.summary = sanitize_string(spec.summary) - spec.description = sanitize_string(spec.description) + spec.summary = sanitize_string(spec.summary) + spec.description = sanitize_string(spec.description) spec.post_install_message = sanitize_string(spec.post_install_message) - spec.authors = spec.authors.collect { |a| sanitize_string(a) } + spec.authors = spec.authors.collect { |a| sanitize_string(a) } spec end @@ -593,14 +587,16 @@ class Gem::Indexer terminate_interaction 0 end - index = collect_specs updated_gems + specs = map_gems_to_specs updated_gems + prerelease, released = specs.partition { |s| s.version.prerelease? } - files = build_marshal_gemspecs index + files = build_marshal_gemspecs Gem.time 'Updated indexes' do - update_specs_index index.released_gems, @dest_specs_index, @specs_index - update_specs_index index.released_gems, @dest_latest_specs_index, @latest_specs_index - update_specs_index(index.prerelease_gems, @dest_prerelease_specs_index, + update_specs_index released, @dest_specs_index, @specs_index + update_specs_index released, @dest_latest_specs_index, @latest_specs_index + update_specs_index(prerelease, + @dest_prerelease_specs_index, @prerelease_specs_index) end @@ -618,12 +614,12 @@ class Gem::Indexer files << "#{@prerelease_specs_index}.gz" files = files.map do |path| - path.sub @directory, '' + path.sub(/^#{Regexp.escape @directory}\/?/, '') # HACK? end files.each do |file| src_name = File.join @directory, file - dst_name = File.join @dest_directory, File.dirname(file) + dst_name = File.join @dest_directory, file # REFACTOR: duped above FileUtils.mv src_name, dst_name, :verbose => verbose, :force => true @@ -639,7 +635,7 @@ class Gem::Indexer def update_specs_index(index, source, dest) specs_index = Marshal.load Gem.read_binary(source) - index.each do |_, spec| + index.each do |spec| platform = spec.original_platform platform = Gem::Platform::RUBY if platform.nil? or platform.empty? specs_index << [spec.name, spec.version, platform] @@ -651,6 +647,4 @@ class Gem::Indexer Marshal.dump specs_index, io end end - end - diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 8c6aeb44c7..7ef96ddb0d 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -47,6 +47,8 @@ class Gem::Installer include Gem::RequirePathsBuilder if Gem::QUICKLOADER_SUCKAGE + attr_reader :gem + ## # The directory a gem's executables will be installed into @@ -57,11 +59,6 @@ class Gem::Installer attr_reader :gem_home - ## - # The Gem::Specification for the gem being installed - - attr_reader :spec - ## # The options passed when the Gem::Installer was instantiated. @@ -106,18 +103,36 @@ class Gem::Installer @gem = gem @options = options process_options - load_gem_file if options[:user_install] and not options[:unpack] then @gem_home = Gem.user_dir check_that_user_bin_dir_is_in_path end + end - verify_gem_home(options[:unpack]) + ## + # Lazy accessor for the spec's gem directory. + + def gem_dir + @gem_dir ||= spec.gem_dir.dup.untaint + end + + ## + # Lazy accessor for the installer's Gem::Format instance. + + def format + begin + @format ||= Gem::Format.from_file_by_path gem, @security_policy + rescue Gem::Package::FormatError + raise Gem::InstallError, "invalid gem format for #{gem}" + end + end - @spec = @format.spec + ## + # Lazy accessor for the installer's spec. - @gem_dir = File.join(@gem_home, "gems", @spec.full_name).untaint + def spec + @spec ||= format.spec end ## @@ -132,6 +147,12 @@ class Gem::Installer # specifications/.gemspec #=> the Gem::Specification def install + current_home = Gem.dir + current_path = Gem.paths.path + + verify_gem_home(options[:unpack]) + Gem.use_paths gem_home, current_path # HACK: shouldn't need Gem.paths.path + # If we're forcing the install then disable security unless the security # policy says that we only install signed gems. @security_policy = nil if @force and @security_policy and @@ -149,17 +170,17 @@ class Gem::Installer if result == false then location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ - message = "pre-install hook#{location} failed for #{@spec.full_name}" + message = "pre-install hook#{location} failed for #{spec.full_name}" raise Gem::InstallError, message end end - Gem.ensure_gem_subdirectories @gem_home + Gem.ensure_gem_subdirectories gem_home # Completely remove any previous gem files - FileUtils.rm_rf(@gem_dir) if File.exist?(@gem_dir) + FileUtils.rm_rf(gem_dir) if File.exist? gem_dir - FileUtils.mkdir_p @gem_dir + FileUtils.mkdir_p gem_dir extract_files build_extensions @@ -168,11 +189,11 @@ class Gem::Installer result = hook.call self if result == false then - FileUtils.rm_rf @gem_dir + FileUtils.rm_rf gem_dir location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ - message = "post-build hook#{location} failed for #{@spec.full_name}" + message = "post-build hook#{location} failed for #{spec.full_name}" raise Gem::InstallError, message end end @@ -182,24 +203,27 @@ class Gem::Installer write_require_paths_file_if_needed if Gem::QUICKLOADER_SUCKAGE - cached_gem = Gem.cache_gem(File.basename(@gem), @gem_home) - unless File.exist? cached_gem then - FileUtils.cp @gem, Gem.cache_dir(@gem_home) - end + cache_file = spec.cache_file + FileUtils.cp gem, cache_file unless File.exist? cache_file - say @spec.post_install_message unless @spec.post_install_message.nil? + say spec.post_install_message unless spec.post_install_message.nil? - @spec.loaded_from = File.join(@gem_home, 'specifications', @spec.spec_name) + spec.loaded_from = spec.spec_file - @source_index.add_spec @spec + Gem::Specification.add_spec spec unless Gem::Specification.include? spec Gem.post_install_hooks.each do |hook| hook.call self end - return @spec + return spec rescue Zlib::GzipFile::Error - raise Gem::InstallError, "gzip error installing #{@gem}" + raise Gem::InstallError, "gzip error installing #{gem}" + ensure + # conditional since we might be here because we're erroring out early. + if current_path + Gem.use_paths current_home, current_path + end end ## @@ -220,7 +244,7 @@ class Gem::Installer # True if the gems in the source_index satisfy +dependency+. def installation_satisfies_dependency?(dependency) - @source_index.find_name(dependency.name, dependency.requirement).size > 0 + not dependency.matching_specs.empty? end ## @@ -228,7 +252,7 @@ class Gem::Installer def unpack(directory) @gem_dir = directory - @format = Gem::Format.from_file_by_path @gem, @security_policy + @format = Gem::Format.from_file_by_path gem, @security_policy extract_files end @@ -237,14 +261,10 @@ class Gem::Installer # specifications directory. def write_spec - rubycode = @spec.to_ruby_for_cache - - file_name = File.join @gem_home, 'specifications', @spec.spec_name - - file_name.untaint + file_name = spec.spec_file.untaint File.open(file_name, "w") do |file| - file.puts rubycode + file.puts spec.to_ruby_for_cache end end @@ -264,24 +284,28 @@ class Gem::Installer end def generate_bin - return if @spec.executables.nil? or @spec.executables.empty? + return if spec.executables.nil? or spec.executables.empty? # If the user has asked for the gem to be installed in a directory that is # the system gem directory, then use the system bin directory, else create # (or use) a new bin dir under the gem_home. - bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home) + bindir = @bin_dir || Gem.bindir(gem_home) Dir.mkdir bindir unless File.exist? bindir raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir - @spec.executables.each do |filename| + spec.executables.each do |filename| filename.untaint - bin_path = File.expand_path "#{@spec.bindir}/#{filename}", @gem_dir - if File.exist?(bin_path) - mode = File.stat(bin_path).mode | 0111 - File.chmod mode, bin_path + bin_path = File.expand_path File.join(gem_dir, spec.bindir, filename) + + unless File.exist? bin_path + warn "Hey?!?! Where did #{bin_path} go??" + next end + mode = File.stat(bin_path).mode | 0111 + FileUtils.chmod mode, bin_path + if @wrappers then generate_bin_script filename, bindir else @@ -322,14 +346,14 @@ class Gem::Installer return end - src = File.join @gem_dir, 'bin', filename + src = File.join gem_dir, spec.bindir, filename dst = File.join bindir, formatted_program_filename(filename) if File.exist? dst then if File.symlink? dst then link = File.readlink(dst).split File::SEPARATOR cur_version = Gem::Version.create(link[-3].sub(/^.*-/, '')) - return if @spec.version < cur_version + return if spec.version < cur_version end File.unlink dst end @@ -343,7 +367,7 @@ class Gem::Installer def shebang(bin_file_name) ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang - path = File.join @gem_dir, @spec.bindir, bin_file_name + path = spec.bin_file bin_file_name first_line = File.open(path, "rb") {|file| file.gets} if /\A#!/ =~ first_line then @@ -365,29 +389,29 @@ class Gem::Installer end def ensure_required_ruby_version_met - if rrv = @spec.required_ruby_version then + if rrv = spec.required_ruby_version then unless rrv.satisfied_by? Gem.ruby_version then - raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}." + raise Gem::InstallError, "#{spec.name} requires Ruby version #{rrv}." end end end def ensure_required_rubygems_version_met - if rrgv = @spec.required_rubygems_version then + if rrgv = spec.required_rubygems_version then unless rrgv.satisfied_by? Gem::Version.new(Gem::VERSION) then raise Gem::InstallError, - "#{@spec.name} requires RubyGems version #{rrgv}. " + + "#{spec.name} requires RubyGems version #{rrgv}. " + "Try 'gem update --system' to update RubyGems itself." end end end def ensure_dependencies_met - deps = @spec.runtime_dependencies - deps |= @spec.development_dependencies if @development + deps = spec.runtime_dependencies + deps |= spec.development_dependencies if @development deps.each do |dep_gem| - ensure_dependency @spec, dep_gem + ensure_dependency spec, dep_gem end end @@ -398,32 +422,24 @@ class Gem::Installer :exec_format => false, :force => false, :install_dir => Gem.dir, - :source_index => Gem.source_index, }.merge options @env_shebang = options[:env_shebang] @force = options[:force] - gem_home = options[:install_dir] - @gem_home = File.expand_path(gem_home) + @gem_home = options[:install_dir] @ignore_dependencies = options[:ignore_dependencies] @format_executable = options[:format_executable] @security_policy = options[:security_policy] @wrappers = options[:wrappers] @bin_dir = options[:bin_dir] @development = options[:development] - @source_index = options[:source_index] - end - def load_gem_file - begin - @format = Gem::Format.from_file_by_path @gem, @security_policy - rescue Gem::Package::FormatError - raise Gem::InstallError, "invalid gem format for #{@gem}" - end + raise "NOTE: Installer option :source_index is dead" if + options[:source_index] end def check_that_user_bin_dir_is_in_path - user_bin_dir = File.join(@gem_home, 'bin') + user_bin_dir = File.join gem_home, "bin" unless ENV['PATH'].split(File::PATH_SEPARATOR).include? user_bin_dir then unless self.class.path_warning then alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run." @@ -433,21 +449,21 @@ class Gem::Installer end def verify_gem_home(unpack = false) - FileUtils.mkdir_p @gem_home - raise Gem::FilePermissionError, @gem_home unless - unpack or File.writable? @gem_home + FileUtils.mkdir_p gem_home + raise Gem::FilePermissionError, gem_home unless + unpack or File.writable?(gem_home) end ## # Return the text for an application file. def app_script_text(bin_file_name) - <<-TEXT + return <<-TEXT #{shebang bin_file_name} # # This file was generated by RubyGems. # -# The application '#{@spec.name}' is installed as part of a gem, and +# The application '#{spec.name}' is installed as part of a gem, and # this file is here to facilitate running it. # @@ -460,8 +476,8 @@ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then ARGV.shift end -gem '#{@spec.name}', version -load Gem.bin_path('#{@spec.name}', '#{bin_file_name}', version) +gem '#{spec.name}', version +load Gem.bin_path('#{spec.name}', '#{bin_file_name}', version) TEXT end @@ -469,14 +485,16 @@ TEXT # return the stub script text used to launch the true ruby script def windows_stub_script(bindir, bin_file_name) - <<-TEXT + ruby = File.basename(Gem.ruby).chomp('"') + return <<-TEXT @ECHO OFF IF NOT "%~f0" == "~f0" GOTO :WinNT -@"#{File.basename(Gem.ruby).chomp('"')}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9 +@"#{ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9 GOTO :EOF :WinNT -@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %* +@"#{ruby}" "%~dpn0" %* TEXT + end ## @@ -484,12 +502,12 @@ TEXT # configure scripts and rakefiles or mkrf_conf files. def build_extensions - return if @spec.extensions.empty? + return if spec.extensions.empty? say "Building native extensions. This could take a while..." - dest_path = File.join @gem_dir, @spec.require_paths.first + dest_path = File.join gem_dir, spec.require_paths.first ran_rake = false # only run rake once - @spec.extensions.each do |extension| + spec.extensions.each do |extension| break if ran_rake results = [] @@ -508,15 +526,15 @@ TEXT extension_dir = begin - File.join @gem_dir, File.dirname(extension) + File.join gem_dir, File.dirname(extension) rescue TypeError # extension == nil - @gem_dir + gem_dir end begin Dir.chdir extension_dir do - results = builder.build(extension, @gem_dir, dest_path, results) + results = builder.build(extension, gem_dir, dest_path, results) say results.join("\n") if Gem.configuration.really_verbose end @@ -532,7 +550,7 @@ ERROR: Failed to build gem native extension. #{results} -Gem files will remain installed in #{@gem_dir} for inspection. +Gem files will remain installed in #{gem_dir} for inspection. Results logged to #{gem_make_out} EOF @@ -547,35 +565,27 @@ EOF # Ensures that files can't be installed outside the gem directory. def extract_files - @gem_dir = File.expand_path @gem_dir - raise ArgumentError, "format required to extract from" if @format.nil? - dirs = [] - @format.file_entries.each do |entry, file_data| path = entry['path'].untaint - if path =~ /\A\// then # for extra sanity - raise Gem::InstallError, - "attempt to install file into #{entry['path'].inspect}" + if path.start_with? "/" then # for extra sanity + raise Gem::InstallError, "attempt to install file into #{entry['path']}" end - path = File.expand_path File.join(@gem_dir, path) + path = File.expand_path File.join(gem_dir, path) - if path !~ /\A#{Regexp.escape @gem_dir}/ then - msg = "attempt to install file into %p under %p" % - [entry['path'], @gem_dir] + unless path.start_with? gem_dir then + msg = "attempt to install file into %p under %s" % + [entry['path'], gem_dir] raise Gem::InstallError, msg end - FileUtils.rm_rf(path) if File.exists?(path) + FileUtils.rm_rf(path) if File.exist? path - dir = File.dirname(path) - if !dirs.include?(dir) - dirs << dir - FileUtils.mkdir_p dir - end + dir = File.dirname path + FileUtils.mkdir_p dir unless File.exist? dir File.open(path, "wb") do |out| out.write file_data @@ -598,5 +608,14 @@ EOF end end + ## + # + # Return the target directory where the gem is to be installed. This + # directory is not guaranteed to be populated. + # + + def dir + gem_dir.to_s + end end diff --git a/lib/rubygems/installer_test_case.rb b/lib/rubygems/installer_test_case.rb index 26b590786b..a548bd55f8 100644 --- a/lib/rubygems/installer_test_case.rb +++ b/lib/rubygems/installer_test_case.rb @@ -12,7 +12,7 @@ class Gem::Installer ## # Available through requiring rubygems/installer_test_case - attr_accessor :gem_dir + attr_writer :gem_dir ## # Available through requiring rubygems/installer_test_case @@ -63,29 +63,38 @@ class Gem::InstallerTestCase < Gem::TestCase def setup super - @spec = quick_gem 'a' - util_make_exec @spec + @installer_tmp = File.join @tempdir, 'installer' + FileUtils.mkdir_p @installer_tmp - @gem = File.join @tempdir, @spec.file_name + Gem.use_paths @installer_tmp + Gem.ensure_gem_subdirectories @installer_tmp - @installer = util_installer @spec, @gem, @gemhome + @spec = quick_gem 'a' + util_make_exec @spec + util_build_gem @spec + @gem = @spec.cache_file @user_spec = quick_gem 'b' util_make_exec @user_spec + util_build_gem @user_spec + @user_gem = @user_spec.cache_file + + Gem.use_paths @gemhome - @user_gem = File.join @tempdir, @user_spec.file_name + @installer = util_installer @spec, @gemhome + @user_installer = util_installer @user_spec, Gem.user_dir, :user - @user_installer = util_installer @user_spec, @user_gem, Gem.user_dir - @user_installer.gem_dir = File.join(Gem.user_dir, 'gems', - @user_spec.full_name) + Gem.use_paths @gemhome end def util_gem_bindir spec = @spec - File.join util_gem_dir(spec), "bin" + # TODO: deprecate + spec.bin_dir end def util_gem_dir spec = @spec - File.join @gemhome, "gems", spec.full_name + # TODO: deprecate + spec.gem_dir end def util_inst_bindir @@ -96,16 +105,13 @@ class Gem::InstallerTestCase < Gem::TestCase spec.executables = %w[executable] spec.files << 'bin/executable' - bindir = util_gem_bindir spec - FileUtils.mkdir_p bindir - exec_path = File.join bindir, 'executable' - open exec_path, 'w' do |io| + exec_path = spec.bin_file "executable" + write_file exec_path do |io| io.puts shebang end - temp_bin = File.join(@tempdir, 'bin') - FileUtils.mkdir_p temp_bin - open File.join(temp_bin, 'executable'), 'w' do |io| + bin_path = File.join @tempdir, "bin", "executable" + write_file bin_path do |io| io.puts shebang end end @@ -128,23 +134,15 @@ class Gem::InstallerTestCase < Gem::TestCase use_ui ui do FileUtils.rm @gem - Gem::Builder.new(@spec).build + + @gem = Gem::Builder.new(@spec).build end end @installer = Gem::Installer.new @gem end - def util_installer(spec, gem_path, gem_home) - util_build_gem spec - FileUtils.mv Gem.cache_gem(spec.file_name), @tempdir - installer = Gem::Installer.new gem_path - installer.gem_dir = util_gem_dir - installer.gem_home = gem_home - installer.spec = spec - - installer + def util_installer(spec, gem_home, user=false) + Gem::Installer.new spec.cache_file, :user_install => user end - end - diff --git a/lib/rubygems/local_remote_options.rb b/lib/rubygems/local_remote_options.rb index b752423845..77a8006f18 100644 --- a/lib/rubygems/local_remote_options.rb +++ b/lib/rubygems/local_remote_options.rb @@ -82,7 +82,7 @@ module Gem::LocalRemoteOptions add_option(:"Local/Remote", '--clear-sources', 'Clear the gem sources') do |value, options| - Gem.sources.clear + Gem.sources = nil options[:sources_cleared] = true end end @@ -123,7 +123,7 @@ module Gem::LocalRemoteOptions # Add the --update-sources option def add_update_sources_option - add_option(:"Local/Remote", '-u', '--[no-]update-sources', + add_option(:Deprecated, '-u', '--[no-]update-sources', 'Update local source cache') do |value, options| Gem.configuration.update_sources = value end diff --git a/lib/rubygems/mock_gem_ui.rb b/lib/rubygems/mock_gem_ui.rb index 4450cc97a6..88c36627c7 100644 --- a/lib/rubygems/mock_gem_ui.rb +++ b/lib/rubygems/mock_gem_ui.rb @@ -12,7 +12,15 @@ require 'rubygems/user_interaction' # retrieval during tests. class Gem::MockGemUi < Gem::StreamUI - class TermError < RuntimeError; end + class TermError < RuntimeError + attr_reader :exit_code + + def initialize exit_code + super + @exit_code = exit_code + end + end + class SystemExitException < RuntimeError; end module TTY @@ -61,8 +69,8 @@ class Gem::MockGemUi < Gem::StreamUI def terminate_interaction(status=0) @terminated = true - raise TermError unless status == 0 - raise Gem::SystemExitException, status + raise TermError, status if status != 0 + raise SystemExitException end end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 3a50ca118e..2e108bf550 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -12,32 +12,6 @@ require 'rubygems/specification' -## -# Wrapper for FileUtils meant to provide logging and additional operations if -# needed. - -class Gem::FileOperations - - def initialize(logger = nil) - require 'fileutils' - @logger = logger - end - - def method_missing(meth, *args, &block) - case - when FileUtils.respond_to?(meth) - @logger.log "#{meth}: #{args}" if @logger - FileUtils.send meth, *args, &block - when Gem::FileOperations.respond_to?(meth) - @logger.log "#{meth}: #{args}" if @logger - Gem::FileOperations.send meth, *args, &block - else - super - end - end - -end - module Gem::Package class Error < StandardError; end @@ -63,6 +37,8 @@ module Gem::Package class TarInvalidError < Error; end + # FIX: zenspider said: does it really take an IO? + # passed to a method called open?!? that seems stupid. def self.open(io, mode = "r", signer = nil, &block) tar_type = case mode when 'r' then TarInput diff --git a/lib/rubygems/package/tar_input.rb b/lib/rubygems/package/tar_input.rb index 401df80a83..92c190c56a 100644 --- a/lib/rubygems/package/tar_input.rb +++ b/lib/rubygems/package/tar_input.rb @@ -55,6 +55,7 @@ class Gem::Package::TarInput sio.rewind end + # TODO use Gem.gunzip gzis = Zlib::GzipReader.new(sio || entry) # YAML wants an instance of IO @metadata = load_gemspec(gzis) @@ -115,7 +116,6 @@ class Gem::Package::TarInput end @tarreader.rewind - @fileops = Gem::FileOperations.new unless has_meta then path = io.path if io.respond_to? :path @@ -151,9 +151,9 @@ class Gem::Package::TarInput dest = File.join destdir, entry.full_name if File.directory? dest then - @fileops.chmod entry.header.mode, dest, :verbose => false + FileUtils.chmod entry.header.mode, dest, :verbose => false else - @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false + FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false end fsync_dir dest @@ -165,9 +165,9 @@ class Gem::Package::TarInput # it's a file md5 = Digest::MD5.new if expected_md5sum destdir = File.join destdir, File.dirname(entry.full_name) - @fileops.mkdir_p destdir, :mode => 0755, :verbose => false + FileUtils.mkdir_p destdir, :mode => 0755, :verbose => false destfile = File.join destdir, File.basename(entry.full_name) - @fileops.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT + FileUtils.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT open destfile, "wb", entry.header.mode do |os| loop do @@ -181,7 +181,7 @@ class Gem::Package::TarInput os.fsync end - @fileops.chmod entry.header.mode, destfile, :verbose => false + FileUtils.chmod entry.header.mode, destfile, :verbose => false fsync_dir File.dirname(destfile) fsync_dir File.join(File.dirname(destfile), "..") diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb index 823f20c88c..aeb11ad6ce 100644 --- a/lib/rubygems/package/tar_writer.rb +++ b/lib/rubygems/package/tar_writer.rb @@ -236,7 +236,7 @@ class Gem::Package::TarWriter name = newname if name.size > 100 or prefix.size > 155 then - raise Gem::Package::TooLongFileName + raise Gem::Package::TooLongFileName end end diff --git a/lib/rubygems/package_task.rb b/lib/rubygems/package_task.rb index ae4f2019ae..5b6b381121 100644 --- a/lib/rubygems/package_task.rb +++ b/lib/rubygems/package_task.rb @@ -106,7 +106,7 @@ class Gem::PackageTask < Rake::PackageTask task :package => [:gem] - gem_file = gem_spec.file_name + gem_file = File.basename gem_spec.cache_file gem_path = File.join package_dir, gem_file gem_dir = File.join package_dir, gem_spec.full_name diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb new file mode 100644 index 0000000000..0809f8ab40 --- /dev/null +++ b/lib/rubygems/path_support.rb @@ -0,0 +1,78 @@ +###################################################################### +# This file is imported from the rubygems project. +# DO NOT make modifications in this repo. They _will_ be reverted! +# File a patch instead and assign it to Ryan Davis or Eric Hodel. +###################################################################### + +## +# +# Gem::PathSupport facilitates the GEM_HOME and GEM_PATH environment settings +# to the rest of RubyGems. +# +class Gem::PathSupport + ## + # The default system path for managing Gems. + attr_reader :home + + ## + # Array of paths to search for Gems. + attr_reader :path + + ## + # + # Constructor. Takes a single argument which is to be treated like a + # hashtable, or defaults to ENV, the system environment. + # + def initialize(env=ENV) + @env = env + + # note 'env' vs 'ENV'... + @home = env["GEM_HOME"] || ENV["GEM_HOME"] || Gem.default_dir + self.path = env["GEM_PATH"] || ENV["GEM_PATH"] + end + + private + + ## + # Set the Gem home directory (as reported by Gem.dir). + + def home=(home) + @home = home.to_s + end + + ## + # Set the Gem search path (as reported by Gem.path). + + def path=(gpaths) + # FIX: it should be [home, *path], not [*path, home] + + gem_path = [] + + # FIX: I can't tell wtf this is doing. + gpaths ||= (ENV['GEM_PATH'] || "").empty? ? nil : ENV["GEM_PATH"] + + if gpaths + if gpaths.kind_of?(Array) + gem_path = gpaths.dup + else + gem_path = gpaths.split(File::PATH_SEPARATOR) + end + + if File::ALT_SEPARATOR then + gem_path.map! do |this_path| + this_path.gsub File::ALT_SEPARATOR, File::SEPARATOR + end + end + + gem_path << @home + else + gem_path = Gem.default_path + [@home] + + if defined?(Gem::APPLE_GEM_HOME) + gem_path << Gem::APPLE_GEM_HOME + end + end + + @path = gem_path.uniq + end +end diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index b6608c7814..cf6db7c16d 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -4,6 +4,8 @@ # File a patch instead and assign it to Ryan Davis or Eric Hodel. ###################################################################### +require "rubygems/deprecate" + ## # Available list of platforms for targeting Gem installations. @@ -121,8 +123,13 @@ class Gem::Platform # the same CPU, OS and version. def ==(other) - self.class === other and - @cpu == other.cpu and @os == other.os and @version == other.version + self.class === other and to_a == other.to_a + end + + alias :eql? :== + + def hash # :nodoc: + to_a.hash end ## @@ -185,5 +192,8 @@ class Gem::Platform CURRENT = 'current' + extend Deprecate + + deprecate :empty?, :none, 2011, 11 end diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index 520adb5827..4613bffbfa 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -75,6 +75,7 @@ class Gem::RemoteFetcher when URI::HTTP then proxy else URI.parse(proxy) end + @user_agent = user_agent end ## @@ -85,7 +86,8 @@ class Gem::RemoteFetcher # larger, more emcompassing effort. -erikh def download_to_cache dependency - found = Gem::SpecFetcher.fetcher.fetch dependency + found = Gem::SpecFetcher.fetcher.fetch dependency, true, true, + dependency.prerelease? return if found.empty? @@ -103,12 +105,12 @@ class Gem::RemoteFetcher Gem.ensure_gem_subdirectories(install_dir) rescue nil if File.writable?(install_dir) - cache_dir = Gem.cache_dir(install_dir) + cache_dir = File.join install_dir, "cache" else - cache_dir = Gem.cache_dir(Gem.user_dir) + cache_dir = File.join Gem.user_dir, "cache" end - gem_file_name = spec.file_name + gem_file_name = File.basename spec.cache_file local_gem_path = File.join cache_dir, gem_file_name FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir @@ -116,8 +118,8 @@ class Gem::RemoteFetcher # Always escape URI's to deal with potential spaces and such unless URI::Generic === source_uri source_uri = URI.parse(URI.const_defined?(:DEFAULT_PARSER) ? - URI::DEFAULT_PARSER.escape(source_uri) : - URI.escape(source_uri)) + URI::DEFAULT_PARSER.escape(source_uri.to_s) : + URI.escape(source_uri.to_s)) end scheme = source_uri.scheme @@ -192,19 +194,55 @@ class Gem::RemoteFetcher local_gem_path end + ## + # File Fetcher. Dispatched by +fetch_path+. Use it instead. + + def fetch_file uri, *_ + Gem.read_binary correct_for_windows_path uri.path + end + + ## + # HTTP Fetcher. Dispatched by +fetch_path+. Use it instead. + + def fetch_http uri, last_modified = nil, head = false, depth = 0 + fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get + response = request uri, fetch_type, last_modified + + case response + when Net::HTTPOK, Net::HTTPNotModified then + head ? response : response.body + when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, + Net::HTTPTemporaryRedirect then + raise FetchError.new('too many redirects', uri) if depth > 10 + + location = URI.parse response['Location'] + fetch_http(location, last_modified, head, depth + 1) + else + raise FetchError.new("bad response #{response.message} #{response.code}", uri) + end + end + + alias :fetch_https :fetch_http + ## # Downloads +uri+ and returns it as a String. def fetch_path(uri, mtime = nil, head = false) - data = open_uri_or_path uri, mtime, head + uri = URI.parse uri unless URI::Generic === uri + + raise ArgumentError, "bad uri: #{uri}" unless uri + raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" unless + uri.scheme + + data = send "fetch_#{uri.scheme}", uri, mtime, head data = Gem.gunzip data if data and not head and uri.to_s =~ /gz$/ data rescue FetchError raise rescue Timeout::Error - raise FetchError.new('timed out', uri) + raise FetchError.new('timed out', uri.to_s) rescue IOError, SocketError, SystemCallError => e - raise FetchError.new("#{e.class}: #{e}", uri) + raise FetchError.new("#{e.class}: #{e}", uri.to_s) end ## @@ -306,36 +344,8 @@ class Gem::RemoteFetcher # read from the filesystem instead. def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0) - raise "block is dead" if block_given? - - uri = URI.parse uri unless URI::Generic === uri - - # This check is redundant unless Gem::RemoteFetcher is likely - # to be used directly, since the scheme is checked elsewhere. - # - Daniel Berger - unless ['http', 'https', 'file'].include?(uri.scheme) - raise ArgumentError, 'uri scheme is invalid' - end - - if uri.scheme == 'file' - path = correct_for_windows_path(uri.path) - return Gem.read_binary(path) - end - - fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get - response = request uri, fetch_type, last_modified - - case response - when Net::HTTPOK, Net::HTTPNotModified then - head ? response : response.body - when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, - Net::HTTPTemporaryRedirect then - raise FetchError.new('too many redirects', uri) if depth > 10 - - open_uri_or_path(response['Location'], last_modified, head, depth + 1) - else - raise FetchError.new("bad response #{response.message} #{response.code}", uri) - end + raise "NO: Use fetch_path instead" + # TODO: deprecate for fetch_path end ## @@ -350,12 +360,7 @@ class Gem::RemoteFetcher request.basic_auth uri.user, uri.password end - ua = "RubyGems/#{Gem::VERSION} #{Gem::Platform.local}" - ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}" - ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - ua << ")" - - request.add_field 'User-Agent', ua + request.add_field 'User-Agent', @user_agent request.add_field 'Connection', 'keep-alive' request.add_field 'Keep-Alive', '30' @@ -447,5 +452,24 @@ class Gem::RemoteFetcher 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 + end diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb index 35f7d0809a..f7bda10cf7 100644 --- a/lib/rubygems/requirement.rb +++ b/lib/rubygems/requirement.rb @@ -141,6 +141,18 @@ class Gem::Requirement requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv } end + alias :=== :satisfied_by? + alias :=~ :satisfied_by? + + ## + # True if the requirement will not always match the latest version. + + def specific? + return true if @requirements.length > 1 # GIGO, > 1, > 2 is silly + + not %w[> >=].include? @requirements.first.first # grab the operator + end + def to_s # :nodoc: as_list.join ", " end diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb index 1ff375dc4a..2709279542 100644 --- a/lib/rubygems/security.rb +++ b/lib/rubygems/security.rb @@ -393,7 +393,7 @@ module Gem::Security :munge_re => Regexp.new(/[^a-z0-9_.-]+/), # output directory for trusted certificate checksums - :trust_dir => File::join(Gem.user_home, '.gem', 'trust'), + :trust_dir => File.join(Gem.user_home, '.gem', 'trust'), # default permissions for trust directory and certs :perms => { diff --git a/lib/rubygems/server.rb b/lib/rubygems/server.rb index 76cb22f252..95ca292fa7 100644 --- a/lib/rubygems/server.rb +++ b/lib/rubygems/server.rb @@ -81,47 +81,47 @@ class Gem::Server
<% values["specs"].each do |spec| %> -
- <% if spec["first_name_entry"] then %> - "> - <% end %> - - <%=spec["name"]%> <%=spec["version"]%> - - <% if spec["rdoc_installed"] then %> - ">[rdoc] - <% else %> - [rdoc] - <% end %> - - <% if spec["homepage"] then %> - " title="<%=spec["homepage"]%>">[www] - <% else %> - [www] - <% end %> - - <% if spec["has_deps"] then %> - - depends on - <%= spec["dependencies"].map { |v| "#{v["name"]}" }.join ', ' %>. - <% end %> -
-
- <%=spec["summary"]%> - <% if spec["executables"] then %> -
- - <% if spec["only_one_executable"] then %> - Executable is - <% else %> - Executables are - <%end%> - - <%= spec["executables"].map { |v| "#{v["executable"]}"}.join ', ' %>. - - <%end%> -
-
-
+
+ <% if spec["first_name_entry"] then %> + "> + <% end %> + + <%=spec["name"]%> <%=spec["version"]%> + + <% if spec["rdoc_installed"] then %> + ">[rdoc] + <% else %> + [rdoc] + <% end %> + + <% if spec["homepage"] then %> + " title="<%=spec["homepage"]%>">[www] + <% else %> + [www] + <% end %> + + <% if spec["has_deps"] then %> + - depends on + <%= spec["dependencies"].map { |v| "#{v["name"]}" }.join ', ' %>. + <% end %> +
+
+ <%=spec["summary"]%> + <% if spec["executables"] then %> +
+ + <% if spec["only_one_executable"] then %> + Executable is + <% else %> + Executables are + <%end%> + + <%= spec["executables"].map { |v| "#{v["executable"]}"}.join ', ' %>. + + <%end%> +
+
+
<% end %>
@@ -460,15 +460,15 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } spec_dir end - @source_index = Gem::SourceIndex.from_gems_in(*@spec_dirs) + Gem::Specification.dirs = @gem_dirs end def Marshal(req, res) - @source_index.refresh! + Gem::Specification.reset add_date res - index = Marshal.dump @source_index + index = Deprecate.skip_during { Marshal.dump Gem.source_index } if req.request_method == 'HEAD' then res['content-length'] = index.length @@ -492,15 +492,16 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } end def latest_specs(req, res) - @source_index.refresh! + Gem::Specification.reset res['content-type'] = 'application/x-gzip' add_date res - specs = @source_index.latest_specs.sort.map do |spec| - platform = spec.original_platform - platform = Gem::Platform::RUBY if platform.nil? + latest_specs = Gem::Specification.latest_specs + + specs = latest_specs.sort.map do |spec| + platform = spec.original_platform || Gem::Platform::RUBY [spec.name, spec.version, platform] end @@ -552,21 +553,20 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } end def quick(req, res) - @source_index.refresh! + Gem::Specification.reset res['content-type'] = 'text/plain' add_date res case req.request_uri.path when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then - dep = Gem::Dependency.new $2, $3 - specs = @source_index.search dep - marshal_format = $1 + marshal_format, name, version, platform = $1, $2, $3, $4 + specs = Gem::Specification.find_all_by_name name, version - selector = [$2, $3, $4].map { |s| s.inspect }.join ' ' + selector = [name, version, platform].map(&:inspect).join ' ' - platform = if $4 then - Gem::Platform.new $4.sub(/^-/, '') + platform = if platform then + Gem::Platform.new platform.sub(/^-/, '') else Gem::Platform::RUBY end @@ -589,7 +589,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } end def root(req, res) - @source_index.refresh! + Gem::Specification.reset add_date res raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless @@ -598,13 +598,15 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } specs = [] total_file_count = 0 - @source_index.each do |path, spec| + Gem::Specification.each do |spec| total_file_count += spec.files.size - deps = spec.dependencies.map do |dep| - { "name" => dep.name, + deps = spec.dependencies.map { |dep| + { + "name" => dep.name, "type" => dep.type, - "version" => dep.requirement.to_s, } - end + "version" => dep.requirement.to_s, + } + } deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] } deps.last["is_last"] = true unless deps.empty? @@ -798,13 +800,12 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } end def specs(req, res) - @source_index.refresh! + Gem::Specification.reset add_date res - specs = @source_index.sort.map do |_, spec| - platform = spec.original_platform - platform = Gem::Platform::RUBY if platform.nil? + specs = Gem::Specification.sort_by(&:sort_obj).map do |spec| + platform = spec.original_platform || Gem::Platform::RUBY [spec.name, spec.version, platform] end @@ -827,12 +828,11 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } def launch listeners = @server.listeners.map{|l| l.addr[2] } + # TODO: 0.0.0.0 == any, not localhost. host = listeners.any?{|l| l == '0.0.0.0'} ? 'localhost' : listeners.first say "Launching browser to http://#{host}:#{@port}" system("#{@launch} http://#{host}:#{@port}") end - end - diff --git a/lib/rubygems/source_index.rb b/lib/rubygems/source_index.rb index a6733fac31..74ad5476d4 100644 --- a/lib/rubygems/source_index.rb +++ b/lib/rubygems/source_index.rb @@ -11,6 +11,7 @@ #++ require 'rubygems/specification' +require 'rubygems/deprecate' ## # The SourceIndex object indexes all the gems available from a @@ -34,79 +35,86 @@ class Gem::SourceIndex attr_accessor :spec_dirs - class << self - ## - # Factory method to construct a source index instance for a given - # path. - # - # deprecated:: - # If supplied, from_installed_gems will act just like - # +from_gems_in+. This argument is deprecated and is provided - # just for backwards compatibility, and should not generally - # be used. - # - # return:: - # SourceIndex instance - - def from_installed_gems(*deprecated) - if deprecated.empty? - from_gems_in(*installed_spec_directories) - else - from_gems_in(*deprecated) # HACK warn - end + ## + # Factory method to construct a source index instance for a given + # path. + # + # deprecated:: + # If supplied, from_installed_gems will act just like + # +from_gems_in+. This argument is deprecated and is provided + # just for backwards compatibility, and should not generally + # be used. + # + # return:: + # SourceIndex instance + + def self.from_installed_gems(*deprecated) + if deprecated.empty? + from_gems_in(*installed_spec_directories) + else + warn "NOTE: from_installed_gems(arg) is deprecated. From #{caller.first}" + from_gems_in(*deprecated) # HACK warn end + end - ## - # Returns a list of directories from Gem.path that contain specifications. + ## + # Returns a list of directories from Gem.path that contain specifications. - def installed_spec_directories - Gem.path.collect { |dir| File.join(dir, "specifications") } - end + def self.installed_spec_directories + # TODO: move to Gem::Utils + Gem.path.collect { |dir| File.join(dir, "specifications") } + end - ## - # Creates a new SourceIndex from the ruby format gem specifications in - # +spec_dirs+. + ## + # Creates a new SourceIndex from the ruby format gem specifications in + # +spec_dirs+. - def from_gems_in(*spec_dirs) - source_index = new - source_index.spec_dirs = spec_dirs - source_index.refresh! - end + def self.from_gems_in(*spec_dirs) + new spec_dirs + end - ## - # Loads a ruby-format specification from +file_name+ and returns the - # loaded spec. + ## + # Loads a ruby-format specification from +file_name+ and returns the + # loaded spec. - def load_specification(file_name) - Gem::Specification.load file_name + def self.load_specification(file_name) + Deprecate.skip_during do + Gem::Specification.load Gem::Path.new(file_name) end - end ## # Constructs a source index instance from the provided specifications, which # is a Hash of gem full names and Gem::Specifications. - #-- - # TODO merge @gems and @prerelease_gems and provide a separate method - # #prerelease_gems - def initialize(specifications={}) + def initialize specs_or_dirs = [] @gems = {} - specifications.each{ |full_name, spec| add_spec spec } @spec_dirs = nil + + case specs_or_dirs + when Hash then + specs_or_dirs.each do |full_name, spec| + add_spec spec + end + when Array, String then + self.spec_dirs = Array(specs_or_dirs) + refresh! + else + arg = specs_or_dirs.inspect + warn "NOTE: SourceIndex.new(#{arg}) is deprecated; From #{caller.first}." + end end - # TODO: remove method def all_gems - @gems + gems end def prerelease_gems - @gems.reject{ |name, gem| !gem.version.prerelease? } + @gems.reject { |name, gem| !gem.version.prerelease? } end def released_gems - @gems.reject{ |name, gem| gem.version.prerelease? } + @gems.reject { |name, gem| gem.version.prerelease? } end ## @@ -116,10 +124,12 @@ class Gem::SourceIndex @gems.clear spec_dirs.reverse_each do |spec_dir| - spec_files = Dir.glob File.join(spec_dir, '*.gemspec') + spec_files = Dir[File.join(spec_dir, "*.gemspec")] spec_files.each do |spec_file| - gemspec = Gem::Specification.load spec_file + gemspec = Deprecate.skip_during do + Gem::Specification.load spec_file + end add_spec gemspec if gemspec end end @@ -159,8 +169,6 @@ class Gem::SourceIndex result[name] << spec end - # TODO: why is this a hash while @gems is an array? Seems like - # structural similarity would be good. result.values.flatten end @@ -246,7 +254,10 @@ class Gem::SourceIndex def find_name(gem_name, requirement = Gem::Requirement.default) dep = Gem::Dependency.new gem_name, requirement - search dep + + Deprecate.skip_during do + search dep + end end ## @@ -258,9 +269,9 @@ class Gem::SourceIndex # +gem_pattern+, and a Gem::Requirement for +platform_only+. This # behavior is deprecated and will be removed. - def search(gem_pattern, platform_only = false) + def search(gem_pattern, platform_or_requirement = false) requirement = nil - only_platform = false + only_platform = false # FIX: WTF is this?!? # TODO - Remove support and warning for legacy arguments after 2008/11 unless Gem::Dependency === gem_pattern @@ -269,9 +280,9 @@ class Gem::SourceIndex case gem_pattern when Regexp then - requirement = platform_only || Gem::Requirement.default + requirement = platform_or_requirement || Gem::Requirement.default when Gem::Dependency then - only_platform = platform_only + only_platform = platform_or_requirement requirement = gem_pattern.requirement gem_pattern = if Regexp === gem_pattern.name then @@ -282,7 +293,7 @@ class Gem::SourceIndex /^#{Regexp.escape gem_pattern.name}$/ end else - requirement = platform_only || Gem::Requirement.default + requirement = platform_or_requirement || Gem::Requirement.default gem_pattern = /#{gem_pattern}/i end @@ -290,7 +301,7 @@ class Gem::SourceIndex requirement = Gem::Requirement.create requirement end - specs = all_gems.values.select do |spec| + specs = @gems.values.select do |spec| spec.name =~ gem_pattern and requirement.satisfied_by? spec.version end @@ -343,7 +354,6 @@ class Gem::SourceIndex def dump Marshal.dump(self) end - end # :stopdoc: @@ -356,5 +366,45 @@ module Gem Cache = SourceIndex end -# :startdoc: +class Gem::SourceIndex + extend Deprecate + + deprecate :all_gems, :none, 2011, 10 + + deprecate :==, :none, 2011, 11 # noisy + deprecate :add_specs, :none, 2011, 11 # noisy + deprecate :each, :none, 2011, 11 + deprecate :gems, :none, 2011, 11 + deprecate :load_gems_in, :none, 2011, 11 + deprecate :refresh!, :none, 2011, 11 + deprecate :spec_dirs=, "Specification.dirs=", 2011, 11 # noisy + deprecate :add_spec, "Specification.add_spec", 2011, 11 + deprecate :find_name, "Specification.find_by_name", 2011, 11 + deprecate :gem_signature, :none, 2011, 11 + deprecate :index_signature, :none, 2011, 11 + deprecate :initialize, :none, 2011, 11 + deprecate :latest_specs, "Specification.latest_specs", 2011, 11 + deprecate :length, "Specification.all.length", 2011, 11 + deprecate :outdated, :none, 2011, 11 + deprecate :prerelease_gems, :none, 2011, 11 + deprecate :prerelease_specs, :none, 2011, 11 + deprecate :released_gems, :none, 2011, 11 + deprecate :released_specs, :none, 2011, 11 + deprecate :remove_spec, "Specification.remove_spec", 2011, 11 + deprecate :search, :none, 2011, 11 + deprecate :size, "Specification.all.size", 2011, 11 + deprecate :spec_dirs, "Specification.dirs", 2011, 11 + deprecate :specification, "Specification.find", 2011, 11 + + class << self + extend Deprecate + + deprecate :from_gems_in, :none, 2011, 10 + deprecate :from_installed_gems, :none, 2011, 10 + deprecate :installed_spec_directories, "Specification.dirs", 2011, 11 + deprecate :load_specification, :none, 2011, 10 + end +end + +# :startdoc: diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 6c71ee63aa..3823dbd8f3 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -91,6 +91,7 @@ class Gem::SpecFetcher all = false, matching_platform = true, prerelease = false) + specs_and_sources, errors = find_matching_with_errors(dependency, all, matching_platform, @@ -144,7 +145,10 @@ class Gem::SpecFetcher # matching released versions are returned. If +matching_platform+ # is false, gems for all platforms are returned. - def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) + def find_matching_with_errors(dependency, + all = false, + matching_platform = true, + prerelease = false) found = {} rejected_specs = {} @@ -257,13 +261,12 @@ class Gem::SpecFetcher loaded = false if File.exist? local_file then - spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file) + spec_dump = + @fetcher.fetch_path(spec_path, File.mtime(local_file)) rescue nil - if spec_dump.nil? then - spec_dump = Gem.read_binary local_file - else - loaded = true - end + loaded = true if spec_dump + + spec_dump ||= Gem.read_binary local_file else spec_dump = @fetcher.fetch_path spec_path loaded = true diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index a5e250a5df..0d3cb4e0cc 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -13,6 +13,7 @@ require 'rubygems/version' require 'rubygems/requirement' require 'rubygems/platform' +require "rubygems/deprecate" # :stopdoc: class Date; end # for ruby_code if date.rb wasn't required @@ -33,11 +34,6 @@ class Date; end # for ruby_code if date.rb wasn't required class Gem::Specification - ## - # Allows deinstallation of gems with legacy platforms. - - attr_accessor :original_platform # :nodoc: - ## # The the version number of a specification that does not specify one # (i.e. RubyGems 0.7 or earlier). @@ -48,6 +44,17 @@ class Gem::Specification # The specification version applied to any new Specification instances # created. This should be bumped whenever something in the spec format # changes. + # + # Specification Version History: + # + # spec ruby + # ver ver yyyy-mm-dd description + # -1 <0.8.0 pre-spec-version-history + # 1 0.8.0 2004-08-01 Deprecated "test_suite_file" for "test_files" + # "test_file=x" is a shortcut for "test_files=[x]" + # 2 0.9.5 2007-10-01 Added "required_rubygems_version" + # Now forward-compatible with future versions + # 3 1.3.2 2009-01-03 Added Fixnum validation to specification_version #-- # When updating this number, be sure to also update #to_ruby. # @@ -55,432 +62,432 @@ class Gem::Specification CURRENT_SPECIFICATION_VERSION = 3 - ## - # An informal list of changes to the specification. The highest-valued - # key should be equal to the CURRENT_SPECIFICATION_VERSION. - - SPECIFICATION_VERSION_HISTORY = { - -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'], - 1 => [ - 'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"', - '"test_file=x" is a shortcut for "test_files=[x]"' - ], - 2 => [ - 'Added "required_rubygems_version"', - 'Now forward-compatible with future versions', - ], - 3 => [ - 'Added Fixnum validation to the specification_version' - ] - } - # :stopdoc: + + # version => # of fields MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 } - now = Time.at(Time.now.to_i) - TODAY = now - ((now.to_i + now.gmt_offset) % 86400) + today = Time.now.utc + TODAY = Time.utc(today.year, today.month, today.day) + # :startdoc: ## - # Optional block used to gather newly defined instances. + # List of attribute names: [:name, :version, ...] - @@gather = nil + @@required_attributes = [:rubygems_version, + :specification_version, + :name, + :version, + :date, + :summary, + :require_paths] ## - # List of attribute names: [:name, :version, ...] + # Map of attribute names to default values. + + @@default_value = { + :authors => [], + :autorequire => nil, + :bindir => 'bin', + :cert_chain => [], + :date => TODAY, + :dependencies => [], + :description => nil, + :email => nil, + :executables => [], + :extensions => [], + :extra_rdoc_files => [], + :files => [], + :homepage => nil, + :licenses => [], + :name => nil, + :platform => Gem::Platform::RUBY, + :post_install_message => nil, + :rdoc_options => [], + :require_paths => ['lib'], + :required_ruby_version => Gem::Requirement.default, + :required_rubygems_version => Gem::Requirement.default, + :requirements => [], + :rubyforge_project => nil, + :rubygems_version => Gem::VERSION, + :signing_key => nil, + :specification_version => CURRENT_SPECIFICATION_VERSION, + :summary => nil, + :test_files => [], + :version => nil, + } + + @@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| + @@default_value[k].nil? + } - @@required_attributes = [] + ###################################################################### + # :section: Required gemspec attributes ## - # List of _all_ attributes and default values: - # - # [[:name, nil], - # [:bindir, 'bin'], - # ...] + # This gem's name - @@attributes = [] + attr_accessor :name + + ## + # This gem's version - @@nil_attributes = [] - @@non_nil_attributes = [:@original_platform] + attr_reader :version ## - # List of array attributes + # Paths in the gem to add to $LOAD_PATH when this gem is activated. + # + # The default ['lib'] is typically sufficient. - @@array_attributes = [] + attr_accessor :require_paths ## - # Map of attribute names to default values. + # The version of RubyGems used to create this gem. + # + # Do not set this, it is set automatically when the gem is packaged. - @@default_value = {} + attr_accessor :rubygems_version ## - # Names of all specification attributes + # The Gem::Specification version of this gemspec. + # + # Do not set this, it is set automatically when the gem is packaged. - def self.attribute_names - @@attributes.map { |name, default| name } - end + attr_accessor :specification_version ## - # Default values for specification attributes + # A short summary of this gem's description. Displayed in `gem list -d`. + # + # The description should be more detailed than the summary. For example, + # you might wish to copy the entire README into the description. - def self.attribute_defaults - @@attributes.dup - end + attr_reader :summary + + ###################################################################### + # :section: Optional gemspec attributes ## - # The default value for specification attribute +name+ + # Autorequire was used by old RubyGems to automatically require a file. + # + # Deprecated: It is neither supported nor functional. - def self.default_value(name) - @@default_value[name] - end + attr_accessor :autorequire ## - # Required specification attributes + # The path in the gem for executable scripts. Usually 'bin' - def self.required_attributes - @@required_attributes.dup - end + attr_accessor :bindir ## - # Is +name+ a required attribute? + # The certificate chain used to sign this gem. See Gem::Security for + # details. - def self.required_attribute?(name) - @@required_attributes.include? name.to_sym - end + attr_accessor :cert_chain ## - # Specification attributes that are arrays (appendable and so-forth) + # A long description of this gem - def self.array_attributes - @@array_attributes.dup - end + attr_reader :description ## - # Specifies the +name+ and +default+ for a specification attribute, and - # creates a reader and writer method like Module#attr_accessor. + # Sets the default executable for this gem. # - # The reader method returns the default if the value hasn't been set. + # Deprecated: You must now specify the executable name to Gem.bin_path. - def self.attribute(name, default=nil) - ivar_name = "@#{name}".intern - if default.nil? then - @@nil_attributes << ivar_name - else - @@non_nil_attributes << [ivar_name, default] - end + attr_writer :default_executable - @@attributes << [name, default] - @@default_value[name] = default - attr_accessor(name) - end + ## + # A contact email for this gem + # + # If you are providing multiple authors and multiple emails they should be + # in the same order such that: + # + # Hash[*spec.authors.zip(spec.emails).flatten] + # + # Gives a hash of author name to email address. + + attr_accessor :email ## - # Same as :attribute, but ensures that values assigned to the attribute - # are array values by applying :to_a to the value. + # The URL of this gem's home page - def self.array_attribute(name) - @@non_nil_attributes << ["@#{name}".intern, []] + attr_accessor :homepage - @@array_attributes << name - @@attributes << [name, []] - @@default_value[name] = [] - code = %{ - def #{name} - @#{name} ||= [] - end - def #{name}=(value) - @#{name} = Array(value) - end - } + ## + # True when this gemspec has been activated. This attribute is not persisted. - module_eval code, __FILE__, __LINE__ - 9 - end + attr_accessor :loaded + + alias :loaded? :loaded ## - # Same as attribute above, but also records this attribute as mandatory. + # True when this gemspec has been activated. This attribute is not persisted. - def self.required_attribute(*args) - @@required_attributes << args.first - attribute(*args) - end + attr_accessor :activated + + alias :activated? :activated ## - # Sometimes we don't want the world to use a setter method for a - # particular attribute. - # - # +read_only+ makes it private so we can still use it internally. + # Path this gemspec was loaded from. This attribute is not persisted. - def self.read_only(*names) - names.each do |name| - private "#{name}=" - end - end + attr_reader :loaded_from - # Shortcut for creating several attributes at once (each with a default - # value of +nil+). + ## + # Allows deinstallation of gems with legacy platforms. - def self.attributes(*args) - args.each do |arg| - attribute(arg, nil) - end - end + attr_writer :original_platform # :nodoc: ## - # Some attributes require special behaviour when they are accessed. This - # allows for that. + # A message that gets displayed after the gem is installed - def self.overwrite_accessor(name, &block) - remove_method name - define_method(name, &block) - end + attr_accessor :post_install_message ## - # Defines a _singular_ version of an existing _plural_ attribute (i.e. one - # whose value is expected to be an array). This means just creating a - # helper method that takes a single value and appends it to the array. - # These are created for convenience, so that in a spec, one can write - # - # s.require_path = 'mylib' - # - # instead of: - # - # s.require_paths = ['mylib'] - # - # That above convenience is available courtesy of: - # - # attribute_alias_singular :require_path, :require_paths + # The version of ruby required by this gem - def self.attribute_alias_singular(singular, plural) - define_method("#{singular}=") { |val| - send("#{plural}=", [val]) - } - define_method("#{singular}") { - val = send("#{plural}") - val.nil? ? nil : val.first - } - end + attr_reader :required_ruby_version ## - # Dump only crucial instance variables. - #-- - # MAINTAIN ORDER! + # The RubyGems version required by this gem - def _dump(limit) - Marshal.dump [ - @rubygems_version, - @specification_version, - @name, - @version, - (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))), - @summary, - @required_ruby_version, - @required_rubygems_version, - @original_platform, - @dependencies, - @rubyforge_project, - @email, - @authors, - @description, - @homepage, - @has_rdoc, - @new_platform, - @licenses - ] - end + attr_reader :required_rubygems_version ## - # Load custom marshal format, re-initializing defaults as needed + # The rubyforge project this gem lives under. i.e. RubyGems' + # rubyforge_project is "rubygems". - def self._load(str) - array = Marshal.load str + attr_accessor :rubyforge_project - spec = Gem::Specification.new - spec.instance_variable_set :@specification_version, array[1] + ## + # The key used to sign this gem. See Gem::Security for details. - current_version = CURRENT_SPECIFICATION_VERSION + attr_accessor :signing_key - field_count = if spec.specification_version > current_version then - spec.instance_variable_set :@specification_version, - current_version - MARSHAL_FIELDS[current_version] - else - MARSHAL_FIELDS[spec.specification_version] - end + def self._all # :nodoc: + unless defined?(@@all) && @@all then + specs = [] - if array.size < field_count then - raise TypeError, "invalid Gem::Specification format #{array.inspect}" - end + self.dirs.reverse_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 + specs << spec if spec + } + } - spec.instance_variable_set :@rubygems_version, array[0] - # spec version - spec.instance_variable_set :@name, array[2] - spec.instance_variable_set :@version, array[3] - spec.instance_variable_set :@date, array[4] - spec.instance_variable_set :@summary, array[5] - spec.instance_variable_set :@required_ruby_version, array[6] - spec.instance_variable_set :@required_rubygems_version, array[7] - spec.instance_variable_set :@original_platform, array[8] - spec.instance_variable_set :@dependencies, array[9] - spec.instance_variable_set :@rubyforge_project, array[10] - spec.instance_variable_set :@email, array[11] - spec.instance_variable_set :@authors, array[12] - spec.instance_variable_set :@description, array[13] - spec.instance_variable_set :@homepage, array[14] - spec.instance_variable_set :@has_rdoc, array[15] - spec.instance_variable_set :@new_platform, array[16] - spec.instance_variable_set :@platform, array[16].to_s - spec.instance_variable_set :@license, array[17] - spec.instance_variable_set :@loaded, false + @@all = specs + _resort! + end + @@all + end - spec + def self._resort! # :nodoc: + @@all.sort! { |a, b| + names = a.name <=> b.name + next names if names.nonzero? + b.version <=> a.version + } end ## - # List of dependencies that will automatically be activated at runtime. + # Adds +spec+ to the known specifications, keeping the collection + # properly sorted. - def runtime_dependencies - # TODO: fix #type to return :runtime if nil - dependencies.select { |d| d.type == :runtime } + def self.add_spec spec + # TODO: find all extraneous adds + # puts + # p :add_spec => [spec.full_name, caller.reject { |s| s =~ /minitest/ }] + + # TODO: flush the rest of the crap from the tests + # raise "no dupes #{spec.full_name} in #{all_names.inspect}" if + # _all.include? spec + + raise "nil spec!" unless spec # TODO: remove once we're happy with tests + + return if _all.include? spec + + _all << spec + _resort! end ## - # List of dependencies that are used for development + # Adds multiple specs to the known specifications. - def development_dependencies - dependencies.select { |d| d.type == :development } - end + def self.add_specs *specs + raise "nil spec!" if specs.any?(&:nil?) # TODO: remove once we're happy - def test_suite_file # :nodoc: - warn 'test_suite_file deprecated, use test_files' - test_files.first - end + # TODO: this is much more efficient, but we need the extra checks for now + # _all.concat specs + # _resort! - def test_suite_file=(val) # :nodoc: - warn 'test_suite_file= deprecated, use test_files=' - @test_files = [] unless defined? @test_files - @test_files << val + specs.each do |spec| # TODO: slow + add_spec spec + end end ## - # true when this gemspec has been loaded from a specifications directory. - # This attribute is not persisted. + # Returns all specifications. This method is discouraged from use. + # You probably want to use one of the Enumerable methods instead. - attr_accessor :loaded + def self.all + warn "NOTE: Specification.all called from #{caller.first}" unless + Deprecate.skip + _all + end ## - # Path this gemspec was loaded from. This attribute is not persisted. + # Sets the known specs to +specs+. Not guaranteed to work for you in + # the future. Use at your own risk. Caveat emptor. Doomy doom doom. + # Etc etc. + # + #-- + # Makes +specs+ the known specs + # Listen, time is a river + # Winter comes, code breaks + # + # -- wilsonb - attr_accessor :loaded_from + def self.all= specs + @@all = specs + end ## - # Returns an array with bindir attached to each executable in the - # executables list - - def add_bindir(executables) - return nil if executables.nil? + # Return full names of all specs in sorted order. - if @bindir then - Array(executables).map { |e| File.join(@bindir, e) } - else - executables - end - rescue - return nil + def self.all_names + self._all.map(&:full_name) end ## - # Files in the Gem under one of the require_paths + # Return the list of all array-oriented instance variables. + #-- + # Not sure why we need to use so much stupid reflection in here... - def lib_files - @files.select do |file| - require_paths.any? do |path| - file.index(path) == 0 - end - end + def self.array_attributes + @@array_attributes.dup end ## - # True if this gem was loaded from disk + # Return the list of all instance variables. + #-- + # Not sure why we need to use so much stupid reflection in here... - alias :loaded? :loaded + def self.attribute_names + @@attributes.dup + end ## - # True if this gem has files in test_files + # Return the directories that Specification uses to find specs. - def has_unit_tests? - not test_files.empty? + def self.dirs + @@dirs ||= Gem.path.collect { |dir| + File.join dir, "specifications" + } end - # :stopdoc: - alias has_test_suite? has_unit_tests? - # :startdoc: - ## - # Specification constructor. Assigns the default values to the - # attributes and yields itself for further - # initialization. Optionally takes +name+ and +version+. + # Set the directories that Specification uses to find specs. Setting + # this resets the list of known specs. - def initialize name = nil, version = nil - @new_platform = nil - assign_defaults - @loaded = false - @loaded_from = nil - - self.name = name if name - self.version = version if version + def self.dirs= dirs + # TODO: find extra calls to dir= + # warn "NOTE: dirs= called from #{caller.first} for #{dirs.inspect}" - yield self if block_given? + self.reset - @@gather.call(self) if @@gather + # ugh + @@dirs = Array(dirs).map { |dir| File.join dir, "specifications" } end + extend Enumerable + ## - # Duplicates array_attributes from +other_spec+ so state isn't shared. + # Enumerate every known spec. See ::dirs= and ::add_spec to set the list of + # specs. - def initialize_copy(other_spec) - other_ivars = other_spec.instance_variables - other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9 - other_ivars.any? { |ivar| String === ivar } + def self.each + return enum_for(:each) unless block_given? - self.class.array_attributes.each do |name| - name = :"@#{name}" - next unless other_ivars.include? name - instance_variable_set name, other_spec.instance_variable_get(name).dup + self._all.each do |x| + yield x end end ## - # Each attribute has a default value (possibly nil). Here, we initialize - # all attributes to their default value. This is done through the - # accessor methods, so special behaviours will be honored. Furthermore, - # we take a _copy_ of the default so each specification instance has its - # own empty arrays, etc. - - def assign_defaults - @@nil_attributes.each do |name| - instance_variable_set name, nil - end + # Returns every spec that matches +name+ and optional +requirements+. - @@non_nil_attributes.each do |name, default| - value = case default - when Time, Numeric, Symbol, true, false, nil then default - else default.dup - end + def self.find_all_by_name name, *requirements + requirements = Gem::Requirement.default if requirements.empty? - instance_variable_set name, value - end + # TODO: maybe try: find_all { |s| spec === dep } - # HACK - instance_variable_set :@new_platform, Gem::Platform::RUBY + Gem::Dependency.new(name, *requirements).matching_specs end ## - # Special loader for YAML files. When a Specification object is loaded - # from a YAML file, it bypasses the normal Ruby object initialization - # routine (#initialize). This method makes up for that and deals with + # Find the best specification matching a +name+ and +requirements+. Raises + # if the dependency doesn't resolve to a valid specification. + + def self.find_by_name name, *requirements + requirements = Gem::Requirement.default if requirements.empty? + + # TODO: maybe try: find { |s| spec === dep } + + Gem::Dependency.new(name, *requirements).to_spec + end + + ## + # Return the best specification that contains the file matching +path+. + + def self.find_by_path path + self.find { |spec| + spec.contains_requirable_file? path + } + end + + ## + # Return currently unresolved specs that contain the file matching +path+. + + def self.find_in_unresolved path + # TODO: do we need these?? Kill it + specs = Gem.unresolved_deps.values.map { |dep| dep.to_specs }.flatten + + specs.find_all { |spec| spec.contains_requirable_file? path } + end + + ## + # Search through all unresolved deps and sub-dependencies and return + # specs that contain the file matching +path+. + + def self.find_in_unresolved_tree path + specs = Gem.unresolved_deps.values.map { |dep| dep.to_specs }.flatten + + specs.reverse_each do |spec| + trails = [] + spec.traverse do |from_spec, dep, to_spec, trail| + next unless to_spec.conflicts.empty? + trails << trail if to_spec.contains_requirable_file? path + end + + next if trails.empty? + + return trails.map(&:reverse).sort.first.reverse + end + + [] + end + + ## + # Special loader for YAML files. When a Specification object is loaded + # from a YAML file, it bypasses the normal Ruby object initialization + # routine (#initialize). This method makes up for that and deals with # gems of different ages. # - # 'input' can be anything that YAML.load() accepts: String or IO. + # +input+ can be anything that YAML.load() accepts: String or IO. def self.from_yaml(input) input = normalize_yaml_input input @@ -504,6 +511,27 @@ class Gem::Specification spec end + ## + # Return the latest specs, optionally including prerelease specs if + # +prerelease+ is true. + + def self.latest_specs prerelease = false + result = Hash.new { |h,k| h[k] = {} } + native = {} + + Gem::Specification._all.reverse_each do |spec| + next if spec.version.prerelease? unless prerelease + + native[spec.name] = spec.version if spec.platform == Gem::Platform::RUBY + result[spec.name][spec.platform] = spec + end + + result.map(&:last).map(&:values).flatten.reject { |spec| + minimum = native[spec.name] + minimum && spec.version < minimum + } + end + ## # Loads Ruby format gemspec from +file+. @@ -524,7 +552,7 @@ class Gem::Specification spec = eval code, binding, file if Gem::Specification === spec - spec.loaded_from = file + spec.loaded_from = file.to_s return spec end @@ -538,39 +566,259 @@ class Gem::Specification nil end + ## + # Specification attributes that must be non-nil + + def self.non_nil_attributes + @@non_nil_attributes.dup + end + ## # Make sure the YAML specification is properly formatted with dashes def self.normalize_yaml_input(input) result = input.respond_to?(:read) ? input.read : input result = "--- " + result unless result =~ /\A--- / - result.gsub(/ !!null \n/, " \n") + result.gsub!(/ !!null \n/, " \n") + # date: 2011-04-26 00:00:00.000000000Z + # date: 2011-04-26 00:00:00.000000000 Z + result.gsub!(/^(date: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+?)Z/, '\1 Z') + result end ## - # Sets the rubygems_version to the current RubyGems version + # Return a list of all outdated specifications. This method is HEAVY + # as it must go fetch specifications from the server. - def mark_version - @rubygems_version = Gem::VERSION + def self.outdated + outdateds = [] + + # TODO: maybe we should switch to rubygems' version service? + fetcher = Gem::SpecFetcher.fetcher + + latest_specs.each do |local| + dependency = Gem::Dependency.new local.name, ">= #{local.version}" + remotes = fetcher.find_matching dependency + remotes = remotes.map { |(_, version, _), _| version } + latest = remotes.sort.last + + outdateds << local.name if latest and local.version < latest + end + + outdateds end ## - # Ignore unknown attributes while loading + # Removes +spec+ from the known specs. - def method_missing(sym, *a, &b) # :nodoc: - if @specification_version > CURRENT_SPECIFICATION_VERSION and - sym.to_s =~ /=$/ then - warn "ignoring #{sym} loading #{full_name}" if $DEBUG + def self.remove_spec spec + # TODO: beat on the tests + raise "wtf: #{spec.full_name} not in #{all_names.inspect}" unless + _all.include? spec + _all.delete spec + end + + ## + # Is +name+ a required attribute? + + def self.required_attribute?(name) + @@required_attributes.include? name.to_sym + end + + ## + # Required specification attributes + + def self.required_attributes + @@required_attributes.dup + end + + ## + # Reset the list of known specs, running pre and post reset hooks + # registered in Gem. + + def self.reset + @@dirs = nil + # from = caller.first(10).reject { |s| s =~ /minitest/ } + # warn "" + # warn "NOTE: Specification.reset from #{from.inspect}" + Gem.pre_reset_hooks.each { |hook| hook.call } + @@all = nil + Gem.post_reset_hooks.each { |hook| hook.call } + end + + ## + # Load custom marshal format, re-initializing defaults as needed + + def self._load(str) + array = Marshal.load str + + spec = Gem::Specification.new + spec.instance_variable_set :@specification_version, array[1] + + current_version = CURRENT_SPECIFICATION_VERSION + + field_count = if spec.specification_version > current_version then + spec.instance_variable_set :@specification_version, + current_version + MARSHAL_FIELDS[current_version] + else + MARSHAL_FIELDS[spec.specification_version] + end + + if array.size < field_count then + raise TypeError, "invalid Gem::Specification format #{array.inspect}" + end + + spec.instance_variable_set :@rubygems_version, array[0] + # spec version + spec.instance_variable_set :@name, array[2] + spec.instance_variable_set :@version, array[3] + spec.instance_variable_set :@date, array[4] + spec.instance_variable_set :@summary, array[5] + spec.instance_variable_set :@required_ruby_version, array[6] + spec.instance_variable_set :@required_rubygems_version, array[7] + spec.instance_variable_set :@original_platform, array[8] + spec.instance_variable_set :@dependencies, array[9] + spec.instance_variable_set :@rubyforge_project, array[10] + spec.instance_variable_set :@email, array[11] + spec.instance_variable_set :@authors, array[12] + spec.instance_variable_set :@description, array[13] + spec.instance_variable_set :@homepage, array[14] + spec.instance_variable_set :@has_rdoc, array[15] + spec.instance_variable_set :@new_platform, array[16] + spec.instance_variable_set :@platform, array[16].to_s + spec.instance_variable_set :@license, array[17] + spec.instance_variable_set :@loaded, false + + spec + end + + def <=>(other) # :nodoc: + sort_obj <=> other.sort_obj + end + + def == other # :nodoc: + self.class === other && + name == other.name && + version == other.version && + platform == other.platform + end + + ## + # Dump only crucial instance variables. + #-- + # MAINTAIN ORDER! + # (down with the man) + + def _dump(limit) + Marshal.dump [ + @rubygems_version, + @specification_version, + @name, + @version, + date, + @summary, + @required_ruby_version, + @required_rubygems_version, + @original_platform, + @dependencies, + @rubyforge_project, + @email, + @authors, + @description, + @homepage, + true, # has_rdoc + @new_platform, + @licenses + ] + end + + ## + # Activate this spec, registering it as a loaded spec and adding + # it's lib paths to $LOAD_PATH. Returns true if the spec was + # activated, false if it was previously activated. Freaks out if + # there are conflicts upon activation. + + def activate + raise_if_conflicts + + return false if Gem.loaded_specs[self.name] + + activate_dependencies + add_self_to_load_path + + Gem.loaded_specs[self.name] = self + self.activated = true + + return true + end + + ## + # Activate all unambiguously resolved runtime dependencies of this + # spec. Add any ambigous dependencies to the unresolved list to be + # resolved later, as needed. + + def activate_dependencies + self.runtime_dependencies.each do |spec_dep| + # TODO: check for conflicts! not just name! + next if Gem.loaded_specs.include? spec_dep.name + specs = spec_dep.to_specs + + if specs.size == 1 then + specs.first.activate + else + name = spec_dep.name + Gem.unresolved_deps[name] = Gem.unresolved_deps[name].merge spec_dep + end + end + + Gem.unresolved_deps.delete self.name + end + + ## + # Returns an array with bindir attached to each executable in the + # +executables+ list + + def add_bindir(executables) + return nil if executables.nil? + + if @bindir then + Array(executables).map { |e| File.join(@bindir, e) } else - super + executables + end + rescue + return nil + end + + ## + # Adds a dependency on gem +dependency+ with type +type+ that requires + # +requirements+. Valid types are currently :runtime and + # :development. + + def add_dependency_with_type(dependency, type, *requirements) + requirements = if requirements.empty? then + Gem::Requirement.default + else + requirements.flatten + end + + unless dependency.respond_to?(:name) && + dependency.respond_to?(:version_requirements) + + dependency = Gem::Dependency.new(dependency, requirements, type) end + + dependencies << dependency end + private :add_dependency_with_type + ## # Adds a development dependency named +gem+ with +requirements+ to this # Gem. For example: # - # spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5' + # spec.add_development_dependency 'example', '~> 1.1', '>= 1.1.4' # # Development dependencies aren't installed by default and aren't # activated when a gem is required. @@ -583,140 +831,263 @@ class Gem::Specification # Adds a runtime dependency named +gem+ with +requirements+ to this Gem. # For example: # - # spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5' + # spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4' def add_runtime_dependency(gem, *requirements) add_dependency_with_type(gem, :runtime, *requirements) end - ## - # Adds a runtime dependency - alias add_dependency add_runtime_dependency ## - # 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. + # Adds this spec's require paths to LOAD_PATH, in the proper location. - def full_name - if platform == Gem::Platform::RUBY or platform.nil? then - "#{@name}-#{@version}" - else - "#{@name}-#{@version}-#{platform}" + def add_self_to_load_path + paths = require_paths.map do |path| + File.join full_gem_path, path end - end - ## - # Returns the full name (name-version) of this gemspec using the original - # platform. For use with legacy gems. + # gem directories must come after -I and ENV['RUBYLIB'] + insert_index = Gem.load_path_insert_index - def original_name # :nodoc: - if platform == Gem::Platform::RUBY or platform.nil? then - "#{@name}-#{@version}" + if insert_index then + # gem directories must come after -I and ENV['RUBYLIB'] + $LOAD_PATH.insert(insert_index, *paths) else - "#{@name}-#{@version}-#{@original_platform}" + # we are probably testing in core, -I and RUBYLIB don't apply + $LOAD_PATH.unshift(*paths) end end ## - # The full path to the gem (install path + full name). + # Singular reader for #authors - def full_gem_path - path = File.join installation_path, 'gems', full_name - return path if File.directory? path - File.join installation_path, 'gems', original_name + def author + val = authors and val.first end ## - # The default (generated) file name of the gem. See also #spec_name. - # - # spec.file_name # => "example-1.0.gem" + # Singular writer for #authors - def file_name - full_name + '.gem' + def author= o + self.authors = [o] end ## - # The directory that this gem was installed into. - - def installation_path - unless @loaded_from then - raise Gem::Exception, "spec #{full_name} is not from an installed gem" - end + # The list of author names who wrote this gem. + # + # If you are providing multiple authors and multiple emails they should be + # in the same order such that: + # + # Hash[*spec.authors.zip(spec.emails).flatten] + # + # Gives a hash of author name to email address. - File.expand_path File.dirname(File.dirname(@loaded_from)) + def authors + @authors ||= [] end ## - # Checks if this specification meets the requirement of +dependency+. + # Sets the list of authors, ensuring it is an array. - def satisfies_requirement?(dependency) - return @name == dependency.name && - dependency.requirement.satisfied_by?(@version) + def authors= value + @authors = Array(value).flatten.grep(String) end ## - # Returns an object you can use to sort specifications in #sort_by. + # Returns the full path to the base gem directory. + # + # eg: /usr/local/lib/ruby/gems/1.8 - def sort_obj - [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1] + def base_dir + return Gem.dir unless loaded_from + @base_dir ||= File.dirname File.dirname loaded_from end ## - # The default name of the gemspec. See also #file_name + # Returns the full path to installed gem's bin directory. # - # spec.spec_name # => "example-1.0.gemspec" + # NOTE: do not confuse this with +bindir+, which is just 'bin', not + # a full path. - def spec_name - full_name + '.gemspec' + def bin_dir + @bin_dir ||= File.join gem_dir, bindir # TODO: this is unfortunate end - def <=>(other) # :nodoc: - sort_obj <=> other.sort_obj + ## + # Returns the full path to an executable named +name+ in this gem. + + def bin_file name + File.join bin_dir, name end ## - # Tests specs for equality (across all attributes). + # Returns the full path to the cache directory containing this + # spec's cached gem. - def ==(other) # :nodoc: - self.class === other && same_attributes?(other) + def cache_dir + @cache_dir ||= File.join base_dir, "cache" end - alias eql? == # :nodoc: - ## - # A macro to yield cached gem path + # Returns the full path to the cached gem for this spec. + + def cache_file + @cache_file ||= File.join cache_dir, "#{full_name}.gem" + end + + alias :cache_gem :cache_file + + ## + # Return any possible conflicts against the currently loaded specs. + + def conflicts + conflicts = {} + Gem.loaded_specs.values.each do |spec| + bad = self.runtime_dependencies.find_all { |dep| + spec.name == dep.name and not spec.satisfies_requirement? dep + } + + conflicts[spec] = bad unless bad.empty? + end + conflicts + end + + ## + # Return true if this spec can require +file+. + + def contains_requirable_file? file + root = full_gem_path + + require_paths.each do |lib| + base = "#{root}/#{lib}/#{file}" + Gem.suffixes.each do |suf| + path = "#{base}#{suf}" + return true if File.file? path + end + end + + return false + end + + ## + # The date this gem was created. Lazily defaults to TODAY. + + def date + @date ||= TODAY + end + + ## + # The date this gem was created # - def cache_gem - cache_name = File.join(Gem.dir, 'cache', file_name) - return File.exist?(cache_name) ? cache_name : nil + # Do not set this, it is set automatically when the gem is packaged. + + def date= date + # We want to end up with a Time object with one-day resolution. + # This is the cleanest, most-readable, faster-than-using-Date + # way to do it. + @date = case date + when String then + if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then + Time.utc($1.to_i, $2.to_i, $3.to_i) + else + raise(Gem::InvalidSpecificationException, + "invalid date format in specification: #{date.inspect}") + end + when Time, Date then + Time.utc(date.year, date.month, date.day) + else + TODAY + end end ## - # True if this gem has the same attributes as +other+. + # The default executable for this gem. + # + # Deprecated: The name of the gem is assumed to be the name of the + # executable now. See Gem.bin_path. - def same_attributes?(other) - @@attributes.each do |name, default| - return false unless self.send(name) == other.send(name) + def default_executable + if defined?(@default_executable) and @default_executable + result = @default_executable + elsif @executables and @executables.size == 1 + result = Array(@executables).first + else + result = nil end - true + result end - private :same_attributes? + ## + # The default value for specification attribute +name+ - def hash # :nodoc: - @@attributes.inject(0) { |hash_code, (name, _)| - hash_code ^ self.send(name).hash - } + def default_value name + @@default_value[name] + end + + ## + # A list of Gem::Dependency objects this gem depends on. + # + # Use #add_dependency or #add_development_dependency to add dependencies to + # a gem. + + def dependencies + @dependencies ||= [] + end + + ## + # Return a list of all gems that have a dependency on this gemspec. The + # list is structured with entries that conform to: + # + # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]] + + def dependent_gems + out = [] + Gem::Specification.each do |spec| + spec.dependencies.each do |dep| + if self.satisfies_requirement?(dep) then + sats = [] + find_all_satisfiers(dep) do |sat| + sats << sat + end + out << [spec, dep, sats] + end + end + end + out + end + + ## + # Returns all specs that matches this spec's runtime dependencies. + + def dependent_specs + runtime_dependencies.map { |dep| dep.to_specs }.flatten + end + + ## + # A long description of this gem + + def description= str + @description = str.to_s + end + + ## + # List of dependencies that are used for development + + def development_dependencies + dependencies.select { |d| d.type == :development } + end + + ## + # Returns the full path to this spec's documentation directory. + + def doc_dir + @doc_dir ||= File.join base_dir, 'doc', full_name end def encode_with coder # :nodoc: mark_version - attributes = @@attributes.map { |name,| name.to_s }.sort - attributes = attributes - %w[name version platform] - coder.add 'name', @name coder.add 'version', @version platform = case @original_platform @@ -729,843 +1100,1029 @@ class Gem::Specification end coder.add 'platform', platform + attributes = @@attributes.map(&:to_s) - %w[name version platform] attributes.each do |name| coder.add name, instance_variable_get("@#{name}") end end - def to_yaml(opts = {}) # :nodoc: - if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then - super.gsub(/ !!null \n/, " \n") - else - YAML.quick_emit object_id, opts do |out| - out.map taguri, to_yaml_style do |map| - encode_with map - end - end - end - end - - def init_with coder # :nodoc: - yaml_initialize coder.tag, coder.map + def eql? other # :nodoc: + self.class === other && same_attributes?(other) end - def yaml_initialize(tag, vals) # :nodoc: - vals.each do |ivar, val| - instance_variable_set "@#{ivar}", val - end + ## + # Singular accessor for #executables - @original_platform = @platform # for backwards compatibility - self.platform = Gem::Platform.new @platform + def executable + val = executables and val.first end ## - # Returns a Ruby code representation of this specification, such that it - # can be eval'ed and reconstruct the same specification later. Attributes - # that still have their default values are omitted. - - def to_ruby - mark_version - result = [] - result << "# -*- encoding: utf-8 -*-" - result << nil - result << "Gem::Specification.new do |s|" + # Singular accessor for #executables - result << " s.name = #{ruby_code name}" - result << " s.version = #{ruby_code version}" - unless platform.nil? or platform == Gem::Platform::RUBY then - result << " s.platform = #{ruby_code original_platform}" - end - result << "" - result << " s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version=" + def executable=o + self.executables = [o] + end - handled = [ - :dependencies, - :name, - :platform, - :required_rubygems_version, - :specification_version, - :version, - ] + ## + # Executables included in the gem. - attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s } + def executables + @executables ||= [] + end - attributes.each do |attr_name, default| - next if handled.include? attr_name - current_value = self.send(attr_name) - if current_value != default or - self.class.required_attribute? attr_name then - result << " s.#{attr_name} = #{ruby_code current_value}" - end - end + ## + # Sets executables to +value+, ensuring it is an array. Don't + # use this, push onto the array instead. - result << nil - result << " if s.respond_to? :specification_version then" - result << " s.specification_version = #{specification_version}" - result << nil + def executables= value + # TODO: warn about setting instead of pushing + @executables = Array(value) + end - result << " if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then" + ## + # Extensions to build when installing the gem. See + # Gem::Installer#build_extensions for valid values. - dependencies.each do |dep| - req = dep.requirements_list.inspect - dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK - result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{req})" - end + def extensions + @extensions ||= [] + end - result << " else" + ## + # Sets extensions to +extensions+, ensuring it is an array. Don't + # use this, push onto the array instead. - dependencies.each do |dep| - version_reqs_param = dep.requirements_list.inspect - result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})" - end + def extensions= extensions + # TODO: warn about setting instead of pushing + @extensions = Array extensions + end - result << ' end' + ## + # Extra files to add to RDoc such as README or doc/examples.txt - result << " else" - dependencies.each do |dep| - version_reqs_param = dep.requirements_list.inspect - result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})" - end - result << " end" + def extra_rdoc_files + @extra_rdoc_files ||= [] + end - result << "end" - result << nil + ## + # Sets extra_rdoc_files to +files+, ensuring it is an array. Don't + # use this, push onto the array instead. - result.join "\n" + def extra_rdoc_files= files + # TODO: warn about setting instead of pushing + @extra_rdoc_files = Array files end - def to_ruby_for_cache - s = dup - # remove large blobs that aren't used at runtime: - s.files = nil - s.extra_rdoc_files = nil - s.rdoc_options = nil - s.to_ruby + ## + # The default (generated) file name of the gem. See also #spec_name. + # + # spec.file_name # => "example-1.0.gem" + + def file_name + "#{full_name}.gem" end ## - # Checks that the specification contains all required fields, and does a - # very basic sanity check. + # Files included in this gem. You cannot append to this accessor, you must + # assign to it. # - # Raises InvalidSpecificationException if the spec does not pass the - # checks.. + # Only add files you can require to this list, not directories, etc. + # + # Directories are automatically stripped from this list when building a gem, + # other non-files cause an error. - def validate - require 'rubygems/user_interaction' - extend Gem::UserInteraction - normalize + def files + # DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks) + @files = [@files, + @test_files, + add_bindir(@executables), + @extra_rdoc_files, + @extensions, + ].flatten.uniq.compact + end - if rubygems_version != Gem::VERSION then - raise Gem::InvalidSpecificationException, - "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}" - end + ## + # Sets files to +files+, ensuring it is an array. - @@required_attributes.each do |symbol| - unless self.send symbol then - raise Gem::InvalidSpecificationException, - "missing value for attribute #{symbol}" - end - end + def files= files + @files = Array files + end - unless String === name then - raise Gem::InvalidSpecificationException, - "invalid value for attribute name: \"#{name.inspect}\"" - end + ## + # Finds all gems that satisfy +dep+ - if require_paths.empty? then - raise Gem::InvalidSpecificationException, - 'specification must have at least one require_path' + def find_all_satisfiers dep + Gem::Specification.each do |spec| + yield spec if spec.satisfies_requirement? dep end + end - @files.delete_if do |file| File.directory? file end - @test_files.delete_if do |file| File.directory? file end - @executables.delete_if do |file| - File.directory? File.join(bindir, file) - end - @extra_rdoc_files.delete_if do |file| File.directory? file end - @extensions.delete_if do |file| File.directory? file end + private :find_all_satisfiers - non_files = files.select do |file| - !File.file? file - end + ## + # Creates a duplicate spec without large blobs that aren't used at runtime. - unless non_files.empty? then - non_files = non_files.map { |file| file.inspect } - raise Gem::InvalidSpecificationException, - "[#{non_files.join ", "}] are not files" - end + def for_cache + spec = dup - unless specification_version.is_a?(Fixnum) - raise Gem::InvalidSpecificationException, - 'specification_version must be a Fixnum (did you mean version?)' - end + spec.files = nil + spec.test_files = nil - case platform - when Gem::Platform, Gem::Platform::RUBY then # ok - else - raise Gem::InvalidSpecificationException, - "invalid platform #{platform.inspect}, see Gem::Platform" - end - - unless Array === authors and - authors.all? { |author| String === author } then - raise Gem::InvalidSpecificationException, - 'authors must be Array of Strings' - end + spec + end - licenses.each { |license| - if license.length > 64 - raise Gem::InvalidSpecificationException, - "each license must be 64 characters or less" - end - } + ## + # The full path to the gem (install path + full name). - # reject FIXME and TODO + def full_gem_path + # TODO: try to get rid of this... or the awkward + # 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 - unless authors.grep(/FIXME|TODO/).empty? then - raise Gem::InvalidSpecificationException, - '"FIXME" or "TODO" is not an author' - end + @full_gem_path = File.expand_path File.join(gems_dir, full_name) - unless Array(email).grep(/FIXME|TODO/).empty? then - raise Gem::InvalidSpecificationException, - '"FIXME" or "TODO" is not an email address' - end + return @full_gem_path if File.directory? @full_gem_path - if description =~ /FIXME|TODO/ then - raise Gem::InvalidSpecificationException, - '"FIXME" or "TODO" is not a description' - end + @full_gem_path = File.expand_path File.join(gems_dir, original_name) + end - if summary =~ /FIXME|TODO/ then - raise Gem::InvalidSpecificationException, - '"FIXME" or "TODO" is not a summary' - end + ## + # 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. - if homepage and not homepage.empty? and - homepage !~ /\A[a-z][a-z\d+.-]*:/i then - raise Gem::InvalidSpecificationException, - "\"#{homepage}\" is not a URI" + def full_name + if platform == Gem::Platform::RUBY or platform.nil? then + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{platform}" end + end - # Warnings - - %w[author description email homepage summary].each do |attribute| - value = self.send attribute - alert_warning "no #{attribute} specified" if value.nil? or value.empty? - end + ## + # Returns the full path to this spec's gem directory. + # eg: /usr/local/lib/ruby/1.8/gems/mygem-1.0 - if summary and not summary.empty? and description == summary then - alert_warning 'description and summary are identical' - end + def gem_dir + @gem_dir ||= File.expand_path File.join(gems_dir, full_name) + end - alert_warning "deprecated autorequire specified" if autorequire + ## + # Returns the full path to the gems directory containing this spec's + # gem directory. eg: /usr/local/lib/ruby/1.8/gems - executables.each do |executable| - executable_path = File.join bindir, executable - shebang = File.read(executable_path, 2) == '#!' + 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 - alert_warning "#{executable_path} is missing #! line" unless shebang - end + ## + # Deprecated and ignored, defaults to true. + # + # Formerly used to indicate this gem was RDoc-capable. + def has_rdoc true end ## - # Normalize the list of files so that: - # * All file lists have redundancies removed. - # * Files referenced in the extra_rdoc_files are included in the package - # file list. + # Deprecated and ignored. + # + # Formerly used to indicate this gem was RDoc-capable. - def normalize - if defined?(@extra_rdoc_files) and @extra_rdoc_files then - @extra_rdoc_files.uniq! - @files ||= [] - @files.concat(@extra_rdoc_files) - end - @files.uniq! if @files + def has_rdoc= ignored + @has_rdoc = true end + alias :has_rdoc? :has_rdoc + ## - # Return a list of all gems that have a dependency on this gemspec. The - # list is structured with entries that conform to: - # - # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]] + # True if this gem has files in test_files - def dependent_gems - out = [] - Gem.source_index.each do |name,gem| - gem.dependencies.each do |dep| - if self.satisfies_requirement?(dep) then - sats = [] - find_all_satisfiers(dep) do |sat| - sats << sat - end - out << [gem, dep, sats] - end - end - end - out + def has_unit_tests? + not test_files.empty? end - def to_s # :nodoc: - "#" + # :stopdoc: + alias has_test_suite? has_unit_tests? + # :startdoc: + + def hash # :nodoc: + @@attributes.inject(0) { |hash_code, (name, _)| + hash_code ^ self.send(name).hash + } end - def pretty_print(q) # :nodoc: - q.group 2, 'Gem::Specification.new do |s|', 'end' do - q.breakable + def init_with coder # :nodoc: + yaml_initialize coder.tag, coder.map + end - attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s } + ## + # Specification constructor. Assigns the default values to the attributes + # and yields itself for further initialization. Optionally takes +name+ and + # +version+. - attributes.each do |attr_name, default| - current_value = self.send attr_name - if current_value != default or - self.class.required_attribute? attr_name then + def initialize name = nil, version = nil + @loaded = false + @loaded_from = nil + @original_platform = nil - q.text "s.#{attr_name} = " + @@nil_attributes.each do |key| + instance_variable_set "@#{key}", nil + end - if attr_name == :date then - current_value = current_value.utc + @@non_nil_attributes.each do |key| + default = default_value(key) + value = case default + when Time, Numeric, Symbol, true, false, nil then default + else default.dup + end - q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})" - else - q.pp current_value - end + instance_variable_set "@#{key}", value + end - q.breakable + @new_platform = Gem::Platform::RUBY + + self.name = name if name + self.version = version if version + + yield self if block_given? + end + + ## + # Duplicates array_attributes from +other_spec+ so state isn't shared. + + def initialize_copy other_spec + other_ivars = other_spec.instance_variables + other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9 + String === other_ivars.first + + self.class.array_attributes.each do |name| + name = :"@#{name}" + next unless other_ivars.include? name + + begin + val = other_spec.instance_variable_get(name) + if val then + instance_variable_set name, val.dup + else + warn "WARNING: #{full_name} has an invalid nil value for #{name}" end + rescue TypeError + e = Gem::FormatException.new \ + "#{full_name} has an invalid value for #{name}" + + e.file_path = loaded_from + raise e end end end ## - # Adds a dependency on gem +dependency+ with type +type+ that requires - # +requirements+. Valid types are currently :runtime and - # :development. + # The directory that this gem was installed into. + # TODO: rename - horrible. this is the base_dir for a gem path - def add_dependency_with_type(dependency, type, *requirements) - requirements = if requirements.empty? then - Gem::Requirement.default - else - requirements.flatten - end + def installation_path + loaded_from && base_dir + end - unless dependency.respond_to?(:name) && - dependency.respond_to?(:version_requirements) + ## + # Returns a string usable in Dir.glob to match all requirable paths + # for this spec. - dependency = Gem::Dependency.new(dependency, requirements, type) - end + def lib_dirs_glob + dirs = if self.require_paths.size > 1 then + "{#{self.require_paths.join(',')}}" + else + self.require_paths.first + end - dependencies << dependency + "#{self.full_gem_path}/#{dirs}" end - private :add_dependency_with_type - ## - # Finds all gems that satisfy +dep+ + # Files in the Gem under one of the require_paths - def find_all_satisfiers(dep) - Gem.source_index.each do |_, gem| - yield gem if gem.satisfies_requirement? dep + def lib_files + @files.select do |file| + require_paths.any? do |path| + file.index(path) == 0 + end end end - private :find_all_satisfiers - ## - # Return a string containing a Ruby code representation of the given - # object. + # Singular accessor for #licenses - def ruby_code(obj) - case obj - when String then '%q{' + obj + '}' - when Array then obj.inspect - when Gem::Version then obj.to_s.inspect - when Date then '%q{' + obj.strftime('%Y-%m-%d') + '}' - when Time then '%q{' + obj.strftime('%Y-%m-%d') + '}' - when Numeric then obj.inspect - when true, false, nil then obj.inspect - when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})" - when Gem::Requirement then "Gem::Requirement.new(#{obj.to_s.inspect})" - else raise Gem::Exception, "ruby_code case not handled: #{obj.class}" - end + def license + val = licenses and val.first end - private :ruby_code + ## + # Singular accessor for #licenses - # :section: Required gemspec attributes + def license=o + self.licenses = [o] + end ## - # :attr_accessor: rubygems_version - # - # The version of RubyGems used to create this gem. - # - # Do not set this, it is set automatically when the gem is packaged. + # The license(s) for the library. Each license must be a short name, no + # more than 64 characters. - required_attribute :rubygems_version, Gem::VERSION + def licenses + @licenses ||= [] + end ## - # :attr_accessor: specification_version - # - # The Gem::Specification version of this gemspec. - # - # Do not set this, it is set automatically when the gem is packaged. + # Set licenses to +licenses+, ensuring it is an array. - required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION + def licenses= licenses + @licenses = Array licenses + end ## - # :attr_accessor: name - # - # This gem's name + # Set the location a Specification was loaded from. +obj+ is converted + # to a String. - required_attribute :name + def loaded_from= path + @loaded_from = path.to_s + end ## - # :attr_accessor: version - # - # This gem's version + # Sets the rubygems_version to the current RubyGems version. - required_attribute :version + def mark_version + @rubygems_version = Gem::VERSION + end ## - # :attr_accessor: date - # - # The date this gem was created - # - # Do not set this, it is set automatically when the gem is packaged. + # Return all files in this gem that match for +glob+. - required_attribute :date, TODAY + def matches_for_glob glob # TODO: rename? + # TODO: do we need these?? Kill it + glob = File.join(self.lib_dirs_glob, glob) + + Dir[glob].map { |f| f.untaint } # FIX our tests are brokey, run w/ SAFE=1 + end ## - # :attr_accessor: summary - # - # A short summary of this gem's description. Displayed in `gem list -d`. - # - # The description should be more detailed than the summary. For example, - # you might wish to copy the entire README into the description. - # - # As of RubyGems 1.3.2 newlines are no longer stripped. + # Warn about unknown attributes while loading a spec. - required_attribute :summary + def method_missing(sym, *a, &b) # :nodoc: + if @specification_version > CURRENT_SPECIFICATION_VERSION and + sym.to_s =~ /=$/ then + warn "ignoring #{sym} loading #{full_name}" if $DEBUG + else + super + end + end ## - # :attr_accessor: require_paths - # - # Paths in the gem to add to $LOAD_PATH when this gem is activated. - # - # The default 'lib' is typically sufficient. + # Normalize the list of files so that: + # * All file lists have redundancies removed. + # * Files referenced in the extra_rdoc_files are included in the package + # file list. - required_attribute :require_paths, ['lib'] + def normalize + if defined?(@extra_rdoc_files) and @extra_rdoc_files then + @extra_rdoc_files.uniq! + @files ||= [] + @files.concat(@extra_rdoc_files) + end - # :section: Optional gemspec attributes + @files = @files.uniq if @files + @extensions = @extensions.uniq if @extensions + @test_files = @test_files.uniq if @test_files + @executables = @executables.uniq if @executables + @extra_rdoc_files = @extra_rdoc_files.uniq if @extra_rdoc_files + end ## - # :attr_accessor: email - # - # A contact email for this gem - # - # If you are providing multiple authors and multiple emails they should be - # in the same order such that: - # - # Hash[*spec.authors.zip(spec.emails).flatten] - # - # Gives a hash of author name to email address. + # Returns the full name (name-version) of this gemspec using the original + # platform. For use with legacy gems. - attribute :email + def original_name # :nodoc: + if platform == Gem::Platform::RUBY or platform.nil? then + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{@original_platform}" + end + end ## - # :attr_accessor: homepage - # - # The URL of this gem's home page + # Cruft. Use +platform+. - attribute :homepage + def original_platform # :nodoc: + @original_platform ||= platform + end ## - # :attr_accessor: rubyforge_project - # - # The rubyforge project this gem lives under. i.e. RubyGems' - # rubyforge_project is "rubygems". + # The platform this gem runs on. See Gem::Platform for details. - attribute :rubyforge_project + def platform + @new_platform ||= Gem::Platform::RUBY + end ## - # :attr_accessor: description + # The platform this gem runs on. See Gem::Platform for details. # - # A long description of this gem + # Setting this to any value other than Gem::Platform::RUBY or + # Gem::Platform::CURRENT is probably wrong. - attribute :description + def platform= platform + if @original_platform.nil? or + @original_platform == Gem::Platform::RUBY then + @original_platform = platform + end - ## - # :attr_accessor: autorequire - # - # Autorequire was used by old RubyGems to automatically require a file. - # It no longer is supported. + case platform + when Gem::Platform::CURRENT then + @new_platform = Gem::Platform.local + @original_platform = @new_platform.to_s - attribute :autorequire + when Gem::Platform then + @new_platform = platform - ## - # :attr_accessor: default_executable - # - # The default executable for this gem. - # - # This is not used. + # legacy constants + when nil, Gem::Platform::RUBY then + @new_platform = Gem::Platform::RUBY + when 'mswin32' then # was Gem::Platform::WIN32 + @new_platform = Gem::Platform.new 'x86-mswin32' + when 'i586-linux' then # was Gem::Platform::LINUX_586 + @new_platform = Gem::Platform.new 'x86-linux' + when 'powerpc-darwin' then # was Gem::Platform::DARWIN + @new_platform = Gem::Platform.new 'ppc-darwin' + else + @new_platform = Gem::Platform.new platform + end - attribute :default_executable + @platform = @new_platform.to_s - ## - # :attr_accessor: bindir - # - # The path in the gem for executable scripts + @new_platform + end - attribute :bindir, 'bin' + def pretty_print(q) # :nodoc: + q.group 2, 'Gem::Specification.new do |s|', 'end' do + q.breakable - ## - # :attr_accessor: has_rdoc - # - # Deprecated and ignored, defaults to true. - # - # Formerly used to indicate this gem was RDoc-capable. + # REFACTOR: each_attr - use in to_yaml as well + @@attributes.each do |attr_name| + current_value = self.send attr_name + if current_value != default_value(attr_name) or + self.class.required_attribute? attr_name then - attribute :has_rdoc, true + q.text "s.#{attr_name} = " - ## - # True if this gem supports RDoc + if attr_name == :date then + current_value = current_value.utc - alias :has_rdoc? :has_rdoc + q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})" + else + q.pp current_value + end + + q.breakable + end + end + end + end ## - # :attr_accessor: required_ruby_version - # - # The version of ruby required by this gem + # Check the spec for possible conflicts and freak out if there are any. - attribute :required_ruby_version, Gem::Requirement.default + def raise_if_conflicts + other = Gem.loaded_specs[self.name] - ## - # :attr_accessor: required_rubygems_version - # - # The RubyGems version required by this gem + if other and self.version != other.version then + # This gem is already loaded. If the currently loaded gem is not in the + # list of candidate gems, then we have a version conflict. - attribute :required_rubygems_version, Gem::Requirement.default + msg = "can't activate #{full_name}, already activated #{other.full_name}" + + e = Gem::LoadError.new msg + e.name = self.name + # TODO: e.requirement = dep.requirement + + raise e + end + + conf = self.conflicts + + unless conf.empty? then + y = conf.map { |act,con| + "#{act.full_name} conflicts with #{con.join(", ")}" + }.join ", " + + # TODO: improve message by saying who activated `con` + + raise Gem::LoadError, "Unable to activate #{self.full_name}, because #{y}" + end + end ## - # :attr_accessor: platform - # - # The platform this gem runs on. See Gem::Platform for details. - # - # Setting this to any value other than Gem::Platform::RUBY or - # Gem::Platform::CURRENT is probably wrong. + # An ARGV style array of options to RDoc - attribute :platform, Gem::Platform::RUBY + def rdoc_options + @rdoc_options ||= [] + end ## - # :attr_accessor: signing_key - # - # The key used to sign this gem. See Gem::Security for details. + # Sets rdoc_options to +value+, ensuring it is an array. Don't + # use this, push onto the array instead. - attribute :signing_key, nil + def rdoc_options= options + # TODO: warn about setting instead of pushing + @rdoc_options = Array options + end ## - # :attr_accessor: cert_chain - # - # The certificate chain used to sign this gem. See Gem::Security for - # details. + # Singular accessor for #require_paths - attribute :cert_chain, [] + def require_path + val = require_paths and val.first + end ## - # :attr_accessor: post_install_message - # - # A message that gets displayed after the gem is installed + # Singular accessor for #require_paths - attribute :post_install_message, nil + def require_path= path + self.require_paths = [path] + end ## - # :attr_accessor: authors - # - # The list of author names who wrote this gem. - # - # If you are providing multiple authors and multiple emails they should be - # in the same order such that: - # - # Hash[*spec.authors.zip(spec.emails).flatten] - # - # Gives a hash of author name to email address. + # The version of ruby required by this gem - array_attribute :authors + def required_ruby_version= req + @required_ruby_version = Gem::Requirement.create req + end ## - # :attr_accessor: licenses - # - # The license(s) for the library. Each license must be a short name, no - # more than 64 characters. + # The RubyGems version required by this gem - array_attribute :licenses + def required_rubygems_version= req + @required_rubygems_version = Gem::Requirement.create req + end ## - # :attr_accessor: files - # - # Files included in this gem. You cannot append to this accessor, you must - # assign to it. - # - # Only add files you can require to this list, not directories, etc. - # - # Directories are automatically stripped from this list when building a gem, - # other non-files cause an error. + # An array or things required by this gem. Not used by anything + # presently. - array_attribute :files + def requirements + @requirements ||= [] + end ## - # :attr_accessor: test_files - # - # Test files included in this gem. You cannot append to this accessor, you - # must assign to it. + # Set requirements to +req+, ensuring it is an array. Don't + # use this, push onto the array instead. - array_attribute :test_files + def requirements= req + # TODO: warn about setting instead of pushing + @requirements = Array req + end ## - # :attr_accessor: rdoc_options - # - # An ARGV style array of options to RDoc + # Returns the full path to this spec's ri directory. - array_attribute :rdoc_options + def ri_dir + @ri_dir ||= File.join base_dir, 'ri', full_name + end ## - # :attr_accessor: extra_rdoc_files - # - # Extra files to add to RDoc such as README or doc/examples.txt + # Return a string containing a Ruby code representation of the given + # object. + + def ruby_code(obj) + case obj + when String then '%q{' + obj + '}' + when Array then '[' + obj.map { |x| ruby_code x }.join(", ") + ']' + when Gem::Version then obj.to_s.inspect + when Date then '%q{' + obj.strftime('%Y-%m-%d') + '}' + when Time then '%q{' + obj.strftime('%Y-%m-%d') + '}' + when Numeric then obj.inspect + when true, false, nil then obj.inspect + when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})" + when Gem::Requirement then "Gem::Requirement.new(#{obj.to_s.inspect})" + else raise Gem::Exception, "ruby_code case not handled: #{obj.class}" + end + end - array_attribute :extra_rdoc_files + private :ruby_code ## - # :attr_accessor: executables - # - # Executables included in the gem. + # List of dependencies that will automatically be activated at runtime. - array_attribute :executables + def runtime_dependencies + dependencies.select { |d| d.type == :runtime } + end ## - # :attr_accessor: extensions - # - # Extensions to build when installing the gem. See - # Gem::Installer#build_extensions for valid values. + # True if this gem has the same attributes as +other+. - array_attribute :extensions + def same_attributes? spec + @@attributes.all? { |name, default| self.send(name) == spec.send(name) } + end + + private :same_attributes? ## - # :attr_accessor: requirements - # - # An array or things required by this gem. Not used by anything - # presently. + # Checks if this specification meets the requirement of +dependency+. - array_attribute :requirements + def satisfies_requirement? dependency + return @name == dependency.name && + dependency.requirement.satisfied_by?(@version) + end ## - # :attr_reader: dependencies - # - # A list of Gem::Dependency objects this gem depends on. - # - # Use #add_dependency or #add_development_dependency to add dependencies to - # a gem. + # Returns an object you can use to sort specifications in #sort_by. - array_attribute :dependencies + def sort_obj + # TODO: this is horrible. Deprecate it. + [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1] + end - read_only :dependencies + ## + # Returns the full path to the directory containing this spec's + # gemspec file. eg: /usr/local/lib/ruby/gems/1.8/specifications - # :section: Aliased gemspec attributes + def spec_dir + @spec_dir ||= File.join base_dir, "specifications" + end ## - # Singular accessor for #executables + # Returns the full path to this spec's gemspec file. + # eg: /usr/local/lib/ruby/gems/1.8/specifications/mygem-1.0.gemspec - attribute_alias_singular :executable, :executables + def spec_file + @spec_file ||= File.join spec_dir, "#{full_name}.gemspec" + end ## - # Singular accessor for #authors + # The default name of the gemspec. See also #file_name + # + # spec.spec_name # => "example-1.0.gemspec" - attribute_alias_singular :author, :authors + def spec_name + "#{full_name}.gemspec" + end ## - # Singular accessor for #licenses + # A short summary of this gem's description. - attribute_alias_singular :license, :licenses + def summary= str + @summary = str.to_s.strip. + gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") # so. weird. + end ## - # Singular accessor for #require_paths + # Singular accessor for #test_files - attribute_alias_singular :require_path, :require_paths + def test_file + val = test_files and val.first + end ## # Singular accessor for #test_files - attribute_alias_singular :test_file, :test_files + def test_file= file + self.test_files = [file] + end ## - # has_rdoc is now ignored + # Test files included in this gem. You cannot append to this accessor, you + # must assign to it. - overwrite_accessor :has_rdoc do - true + def test_files + # Handle the possibility that we have @test_suite_file but not + # @test_files. This will happen when an old gem is loaded via + # YAML. + if defined? @test_suite_file then + @test_files = [@test_suite_file].flatten + @test_suite_file = nil + end + if defined?(@test_files) and @test_files then + @test_files + else + @test_files = [] + end end ## - # has_rdoc is now ignored + # Set test_files to +files+, ensuring it is an array. - overwrite_accessor :has_rdoc= do |value| - @has_rdoc = true + def test_files= files + @test_files = Array files end - overwrite_accessor :version= do |version| - @version = Gem::Version.create(version) - self.required_rubygems_version = '> 1.3.1' if @version.prerelease? - return @version + def test_suite_file # :nodoc: + # TODO: deprecate + test_files.first end - overwrite_accessor :platform do - @new_platform + def test_suite_file= file # :nodoc: + # TODO: deprecate + @test_files = [] unless defined? @test_files + @test_files << file end - overwrite_accessor :platform= do |platform| - if @original_platform.nil? or - @original_platform == Gem::Platform::RUBY then - @original_platform = platform + ## + # Returns a Ruby code representation of this specification, such that it can + # be eval'ed and reconstruct the same specification later. Attributes that + # still have their default values are omitted. + + def to_ruby + mark_version + result = [] + result << "# -*- encoding: utf-8 -*-" + result << nil + result << "Gem::Specification.new do |s|" + + result << " s.name = #{ruby_code name}" + result << " s.version = #{ruby_code version}" + unless platform.nil? or platform == Gem::Platform::RUBY then + result << " s.platform = #{ruby_code original_platform}" end + result << "" + result << " s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version=" - case platform - when Gem::Platform::CURRENT then - @new_platform = Gem::Platform.local - @original_platform = @new_platform.to_s + handled = [ + :dependencies, + :name, + :platform, + :required_rubygems_version, + :specification_version, + :version, + :has_rdoc, + :default_executable, + ] - when Gem::Platform then - @new_platform = platform + @@attributes.each do |attr_name| + next if handled.include? attr_name + current_value = self.send(attr_name) + if current_value != default_value(attr_name) or + self.class.required_attribute? attr_name then + result << " s.#{attr_name} = #{ruby_code current_value}" + end + end - # legacy constants - when nil, Gem::Platform::RUBY then - @new_platform = Gem::Platform::RUBY - when 'mswin32' then # was Gem::Platform::WIN32 - @new_platform = Gem::Platform.new 'x86-mswin32' - when 'i586-linux' then # was Gem::Platform::LINUX_586 - @new_platform = Gem::Platform.new 'x86-linux' - when 'powerpc-darwin' then # was Gem::Platform::DARWIN - @new_platform = Gem::Platform.new 'ppc-darwin' - else - @new_platform = Gem::Platform.new platform + result << nil + result << " if s.respond_to? :specification_version then" + result << " s.specification_version = #{specification_version}" + result << nil + + result << " if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then" + + dependencies.each do |dep| + req = dep.requirements_list.inspect + dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK + result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{req})" end - @platform = @new_platform.to_s + result << " else" - @new_platform + dependencies.each do |dep| + version_reqs_param = dep.requirements_list.inspect + result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})" + end + + result << ' end' + + result << " else" + dependencies.each do |dep| + version_reqs_param = dep.requirements_list.inspect + result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})" + end + result << " end" + + result << "end" + result << nil + + result.join "\n" end - overwrite_accessor :required_ruby_version= do |value| - @required_ruby_version = Gem::Requirement.create(value) + ## + # Returns a Ruby lighter-weight code representation of this specification, + # used for indexing only. + # + # See #to_ruby. + + def to_ruby_for_cache + for_cache.to_ruby end - overwrite_accessor :required_rubygems_version= do |value| - @required_rubygems_version = Gem::Requirement.create(value) + def to_s # :nodoc: + "#" end - overwrite_accessor :date= do |date| - # We want to end up with a Time object with one-day resolution. - # This is the cleanest, most-readable, faster-than-using-Date - # way to do it. - case date - when String then - @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then - Time.local($1.to_i, $2.to_i, $3.to_i) - else - require 'time' - Time.parse date - end - when Time then - @date = Time.local(date.year, date.month, date.day) - when Date then - @date = Time.local(date.year, date.month, date.day) + def to_yaml(opts = {}) # :nodoc: + if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then + super.gsub(/ !!null \n/, " \n") else - @date = TODAY + YAML.quick_emit object_id, opts do |out| + out.map taguri, to_yaml_style do |map| + encode_with map + end + end end end - overwrite_accessor :date do - self.date = nil if @date.nil? # HACK Sets the default value for date - @date - end + ## + # Recursively walk dependencies of this spec, executing the +block+ for each + # hop. - overwrite_accessor :summary= do |str| - @summary = if str then - str.strip. - gsub(/(\w-)\n[ \t]*(\w)/, '\1\2'). - gsub(/\n[ \t]*/, " ") - end + def traverse trail = [], &block + trail = trail + [self] + runtime_dependencies.each do |dep| + dep.to_specs.each do |dep_spec| + block[self, dep, dep_spec, trail + [dep_spec]] + dep_spec.traverse(trail, &block) unless + trail.map(&:name).include? dep_spec.name + end + end end - overwrite_accessor :description= do |str| - @description = str.to_s - end + ## + # Checks that the specification contains all required fields, and does a + # very basic sanity check. + # + # Raises InvalidSpecificationException if the spec does not pass the + # checks.. - overwrite_accessor :default_executable do - begin - if defined?(@default_executable) and @default_executable - result = @default_executable - elsif @executables and @executables.size == 1 - result = Array(@executables).first - else - result = nil + def validate packaging = true + require 'rubygems/user_interaction' + extend Gem::UserInteraction + normalize + + nil_attributes = self.class.non_nil_attributes.find_all do |name| + instance_variable_get("@#{name}").nil? + end + + unless nil_attributes.empty? then + raise Gem::InvalidSpecificationException, + "#{nil_attributes.join ', '} must not be nil" + end + + if packaging and rubygems_version != Gem::VERSION then + raise Gem::InvalidSpecificationException, + "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}" + end + + @@required_attributes.each do |symbol| + unless self.send symbol then + raise Gem::InvalidSpecificationException, + "missing value for attribute #{symbol}" end - result - rescue - nil end - end - overwrite_accessor :test_files do - # Handle the possibility that we have @test_suite_file but not - # @test_files. This will happen when an old gem is loaded via - # YAML. - if defined? @test_suite_file then - @test_files = [@test_suite_file].flatten - @test_suite_file = nil + unless String === name then + raise Gem::InvalidSpecificationException, + "invalid value for attribute name: \"#{name.inspect}\"" end - if defined?(@test_files) and @test_files then - @test_files + + if require_paths.empty? then + raise Gem::InvalidSpecificationException, + 'specification must have at least one require_path' + end + + @files.delete_if { |x| File.directory?(x) } + @test_files.delete_if { |x| File.directory?(x) } + @executables.delete_if { |x| File.directory?(File.join(@bindir, x)) } + @extra_rdoc_files.delete_if { |x| File.directory?(x) } + @extensions.delete_if { |x| File.directory?(x) } + + non_files = files.reject { |x| File.file?(x) } + + unless not packaging or non_files.empty? then + raise Gem::InvalidSpecificationException, + "[\"#{non_files.join "\", \""}\"] are not files" + end + + unless specification_version.is_a?(Fixnum) + raise Gem::InvalidSpecificationException, + 'specification_version must be a Fixnum (did you mean version?)' + end + + case platform + when Gem::Platform, Gem::Platform::RUBY then # ok else - @test_files = [] + raise Gem::InvalidSpecificationException, + "invalid platform #{platform.inspect}, see Gem::Platform" end - end - overwrite_accessor :files do - # DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks) - @files = [@files, - @test_files, - add_bindir(@executables), - @extra_rdoc_files, - @extensions, - ].flatten.uniq.compact - end + self.class.array_attributes.each do |field| + val = self.send field + klass = case field + when :dependencies + Gem::Dependency + else + String + end - def conflicts - conflicts = {} - Gem.loaded_specs.values.each do |spec| - bad = self.runtime_dependencies.find_all { |dep| - spec.name == dep.name and not spec.satisfies_requirement? dep - } + unless Array === val and val.all? { |x| x.kind_of?(klass) } then + raise(Gem::InvalidSpecificationException, + "#{field} must be an Array of #{klass}") + end + end - conflicts[spec] = bad unless bad.empty? + [:authors].each do |field| + val = self.send field + raise Gem::InvalidSpecificationException, "#{field} may not be empty" if + val.empty? end - conflicts - end - def traverse trail = [], &b - trail = trail + [self] - runtime_dependencies.each do |dep| - dep_specs = Gem.source_index.search dep, true - dep_specs.each do |dep_spec| - b[self, dep, dep_spec, trail + [dep_spec]] - dep_spec.traverse(trail, &b) unless - trail.map(&:name).include? dep_spec.name + licenses.each { |license| + if license.length > 64 + raise Gem::InvalidSpecificationException, + "each license must be 64 characters or less" end + } + + # reject lazy developers: + + lazy = '"FIxxxXME" or "TOxxxDO"'.gsub(/xxx/, '') + + unless authors.grep(/FI XME|TO DO/x).empty? then + raise Gem::InvalidSpecificationException, "#{lazy} is not an author" + end + + unless Array(email).grep(/FI XME|TO DO/x).empty? then + raise Gem::InvalidSpecificationException, "#{lazy} is not an email" end + + if description =~ /FI XME|TO DO/x then + raise Gem::InvalidSpecificationException, "#{lazy} is not a description" + end + + if summary =~ /FI XME|TO DO/x then + raise Gem::InvalidSpecificationException, "#{lazy} is not a summary" + end + + if homepage and not homepage.empty? and + homepage !~ /\A[a-z][a-z\d+.-]*:/i then + raise Gem::InvalidSpecificationException, + "\"#{homepage}\" is not a URI" + end + + # Warnings + + %w[author description email homepage summary].each do |attribute| + value = self.send attribute + alert_warning "no #{attribute} specified" if value.nil? or value.empty? + end + + if description == summary then + alert_warning 'description and summary are identical' + end + + # TODO: raise at some given date + alert_warning "deprecated autorequire specified" if autorequire + + executables.each do |executable| + executable_path = File.join(bindir, executable) + shebang = File.read(executable_path, 2) == '#!' + + alert_warning "#{executable_path} is missing #! line" unless shebang + end + + true end - def dependent_specs - runtime_dependencies.map { |dep| Gem.source_index.search dep, true }.flatten + ## + # Set the version to +version+, potentially also setting + # required_rubygems_version if +version+ indicates it is a + # prerelease. + + def version= version + @version = Gem::Version.create(version) + self.required_rubygems_version = '> 1.3.1' if @version.prerelease? + return @version end + + # FIX: have this handle the platform/new_platform/original_platform bullshit + def yaml_initialize(tag, vals) # :nodoc: + vals.each do |ivar, val| + instance_variable_set "@#{ivar}", val + end + + @original_platform = @platform # for backwards compatibility + self.platform = Gem::Platform.new @platform + end + + extend Deprecate + + deprecate :test_suite_file, :test_file, 2011, 10 + deprecate :test_suite_file=, :test_file=, 2011, 10 + deprecate :loaded, :activated, 2011, 10 + deprecate :loaded?, :activated?, 2011, 10 + deprecate :loaded=, :activated=, 2011, 10 + deprecate :installation_path, :base_dir, 2011, 10 + deprecate :cache_gem, :cache_file, 2011, 10 + # TODO: + # deprecate :has_rdoc, :none, 2011, 10 + # deprecate :has_rdoc?, :none, 2011, 10 + # deprecate :has_rdoc=, :none, 2011, 10 + # deprecate :default_executable, :none, 2011, 10 + # deprecate :default_executable=, :none, 2011, 10 + # deprecate :spec_name, :spec_file, 2011, 10 + # deprecate :file_name, :cache_file, 2011, 10 + # deprecate :full_gem_path, :cache_file, 2011, 10 end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 895002df05..3b26d31611 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -17,6 +17,7 @@ begin rescue Gem::LoadError end +require "rubygems/deprecate" require 'minitest/autorun' require 'fileutils' require 'tmpdir' @@ -25,6 +26,7 @@ require 'rubygems/package' require 'rubygems/test_utilities' require 'pp' require 'zlib' +require 'pathname' Gem.load_yaml require 'rubygems/mock_gem_ui' @@ -44,6 +46,8 @@ module Gem # requiring 'rubygems/test_case' def self.source_index=(si) + raise "This method is not supported" + Gem::Specification.reset if si # HACK @@source_index = si end @@ -82,12 +86,24 @@ end class Gem::TestCase < MiniTest::Unit::TestCase + # TODO: move to minitest + def assert_path_exists path, msg = nil + msg = message(msg) { "Expected path '#{path}' to exist" } + assert File.exist?(path), msg + end + + # TODO: move to minitest + def refute_path_exists path, msg = nil + msg = message(msg) { "Expected path '#{path}' to not exist" } + refute File.exist?(path), msg + end + include Gem::DefaultUserInteraction undef_method :default_test if instance_methods.include? 'default_test' or instance_methods.include? :default_test - @@project_dir = Dir.pwd unless defined?(@@project_dir) + @@project_dir = Dir.pwd ## # #setup prepares a sandboxed location to install gems. All installs are @@ -106,14 +122,15 @@ class Gem::TestCase < MiniTest::Unit::TestCase @orig_gem_home = ENV['GEM_HOME'] @orig_gem_path = ENV['GEM_PATH'] - @current_dir = Dir.pwd @ui = Gem::MockGemUi.new + tmpdir = nil Dir.chdir Dir.tmpdir do tmpdir = Dir.pwd end # HACK OSX /private/tmp + if ENV['KEEP_FILES'] then - @tempdir = File.join tmpdir, "test_rubygems_#{$$}.#{Time.now.to_i}" + @tempdir = File.join(tmpdir, "test_rubygems_#{$$}.#{Time.now.to_i}") else - @tempdir = File.join tmpdir, "test_rubygems_#{$$}" + @tempdir = File.join(tmpdir, "test_rubygems_#{$$}") end @tempdir.untaint @gemhome = File.join @tempdir, 'gemhome' @@ -126,6 +143,9 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem.ensure_gem_subdirectories @gemhome + @orig_LOAD_PATH = $LOAD_PATH.dup + $LOAD_PATH.map! { |s| File.expand_path s } + Dir.chdir @tempdir @orig_ENV_HOME = ENV['HOME'] @@ -136,6 +156,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase FileUtils.mkdir_p @userhome Gem.use_paths(@gemhome) + Gem.loaded_specs.clear Gem.unresolved_deps.clear @@ -191,8 +212,6 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem.pre_uninstall do |uninstaller| @pre_uninstall_hook_arg = uninstaller end - - @orig_LOAD_PATH = $LOAD_PATH.dup end ## @@ -209,15 +228,13 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem::RemoteFetcher.fetcher = nil end - Dir.chdir @current_dir + Dir.chdir @@project_dir FileUtils.rm_rf @tempdir unless ENV['KEEP_FILES'] ENV['GEM_HOME'] = @orig_gem_home ENV['GEM_PATH'] = @orig_gem_path - Gem.clear_paths - _ = @orig_ruby Gem.class_eval { @ruby = _ } if _ @@ -240,7 +257,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase end end - gem = File.join(@tempdir, spec.file_name).untaint + gem = File.join(@tempdir, File.basename(spec.cache_file)).untaint Gem::Installer.new(gem, :wrappers => true).install end @@ -250,9 +267,19 @@ class Gem::TestCase < MiniTest::Unit::TestCase def uninstall_gem spec require 'rubygems/uninstaller' - uninstaller = Gem::Uninstaller.new spec.name, :executables => true, - :user_install => true - uninstaller.uninstall + Gem::Uninstaller.new(spec.name, + :executables => true, :user_install => true).uninstall + end + + ## + # creates a temporary directory with hax + + def create_tmpdir + tmpdir = nil + Dir.chdir Dir.tmpdir do tmpdir = Dir.pwd end # HACK OSX /private/tmp + tmpdir = File.join tmpdir, "test_rubygems_#{$$}" + FileUtils.mkdir_p tmpdir + return tmpdir end ## @@ -285,7 +312,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase # Writes a binary file to +path+ which is relative to +@gemhome+ def write_file(path) - path = File.join @gemhome, path + path = File.join @gemhome, path unless Pathname.new(path).absolute? dir = File.dirname path FileUtils.mkdir_p dir @@ -296,6 +323,10 @@ class Gem::TestCase < MiniTest::Unit::TestCase path end + def all_spec_names + Gem::Specification.map(&:full_name) + end + ## # Creates a Gem::Specification with a minimum of extra work. +name+ and # +version+ are the gem's name and version, platform, author, email, @@ -317,26 +348,27 @@ class Gem::TestCase < MiniTest::Unit::TestCase s.author = 'A User' s.email = 'example@example.com' s.homepage = 'http://example.com' - s.has_rdoc = true s.summary = "this is a summary" s.description = "This is a test description" yield(s) if block_given? end - path = File.join "specifications", spec.spec_name - written_path = write_file path do |io| - io.write(spec.to_ruby) + Gem::Specification.map # HACK: force specs to (re-)load before we write + + written_path = write_file spec.spec_file do |io| + io.write spec.to_ruby_for_cache end - spec.loaded_from = written_path + spec.loaded_from = spec.loaded_from = written_path - Gem.source_index.add_spec spec + Gem::Specification.add_spec spec.for_cache return spec end def quick_spec name, version = '2' + # TODO: deprecate require 'rubygems/specification' spec = Gem::Specification.new do |s| @@ -346,16 +378,15 @@ class Gem::TestCase < MiniTest::Unit::TestCase s.author = 'A User' s.email = 'example@example.com' s.homepage = 'http://example.com' - s.has_rdoc = true s.summary = "this is a summary" s.description = "This is a test description" yield(s) if block_given? end - spec.loaded_from = @gemhome + spec.loaded_from = spec.spec_file - Gem.source_index.add_spec spec + Gem::Specification.add_spec spec return spec end @@ -365,7 +396,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase # 'cache'. Automatically creates files based on +spec.files+ def util_build_gem(spec) - dir = File.join(@gemhome, 'gems', spec.full_name) + dir = spec.gem_dir FileUtils.mkdir_p dir Dir.chdir dir do @@ -379,8 +410,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem::Builder.new(spec).build end - FileUtils.mv spec.file_name, - Gem.cache_gem("#{spec.original_name}.gem") + cache = spec.cache_file + FileUtils.mv File.basename(cache), cache end end @@ -388,19 +419,16 @@ class Gem::TestCase < MiniTest::Unit::TestCase # Removes all installed gems from +@gemhome+. def util_clear_gems - FileUtils.rm_rf File.join(@gemhome, 'gems') - FileUtils.rm_rf File.join(@gemhome, 'specifications') - Gem.source_index.refresh! + FileUtils.rm_rf File.join(@gemhome, "gems") # TODO: use Gem::Dirs + FileUtils.rm_rf File.join(@gemhome, "specifications") + Gem::Specification.reset end ## # Install the provided specs def install_specs(*specs) - specs.each do |spec| - # TODO: inverted responsibility - Gem.source_index.add_spec spec - end + Gem::Specification.add_specs(*specs) Gem.searcher = nil end @@ -409,19 +437,42 @@ class Gem::TestCase < MiniTest::Unit::TestCase # up properly. Use this instead of util_spec and util_gem. def new_spec name, version, deps = nil, *files - # TODO: unfactor and deprecate util_gem and util_spec - spec, = unless files.empty? then - util_gem name, version do |s| - Array(deps).each do |n,v| - s.add_dependency n, v - end - s.files.push(*files) - end - else - util_spec name, version, deps - end - spec.loaded_from = File.join @gemhome, 'specifications', spec.spec_name - spec.loaded = false + require 'rubygems/specification' + + spec = Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.name = name + s.version = version + s.author = 'A User' + s.email = 'example@example.com' + s.homepage = 'http://example.com' + s.summary = "this is a summary" + s.description = "This is a test description" + + Array(deps).each do |n, req| + s.add_dependency n, (req || '>= 0') + end + + s.files.push(*files) unless files.empty? + + yield s if block_given? + end + + spec.loaded_from = spec.spec_file + + unless files.empty? then + write_file spec.spec_file do |io| + io.write spec.to_ruby_for_cache + end + + util_build_gem spec + + cache_file = File.join @tempdir, 'gems', "#{spec.full_name}.gem" + FileUtils.mkdir_p File.dirname cache_file + FileUtils.mv spec.cache_file, cache_file + FileUtils.rm spec.spec_file + end + spec end @@ -429,6 +480,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase # Creates a spec with +name+, +version+ and +deps+. def util_spec(name, version, deps = nil, &block) + # TODO: deprecate raise "deps or block, not both" if deps and block if deps then @@ -449,6 +501,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase # location are returned. def util_gem(name, version, deps = nil, &block) + # TODO: deprecate raise "deps or block, not both" if deps and block if deps then @@ -465,11 +518,10 @@ class Gem::TestCase < MiniTest::Unit::TestCase cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem" FileUtils.mkdir_p File.dirname cache_file - FileUtils.mv Gem.cache_gem("#{spec.original_name}.gem"), cache_file - FileUtils.rm File.join(@gemhome, 'specifications', spec.spec_name) + FileUtils.mv spec.cache_file, cache_file + FileUtils.rm spec.spec_file spec.loaded_from = nil - spec.loaded = false [spec, cache_file] end @@ -517,8 +569,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase This line is really, really long. So long, in fact, that it is more than eighty characters long! The purpose of this line is for testing wrapping behavior because sometimes people don't wrap their text to eighty characters. Without the wrapping, the text might not look good in the RSS feed. Also, a list: - * An entry that's actually kind of sort - * an entry that's really long, which will probably get wrapped funny. That's ok, somebody wasn't thinking straight when they made it more than eighty characters. + * An entry that\'s actually kind of sort + * an entry that\'s really long, which will probably get wrapped funny. That's ok, somebody wasn't thinking straight when they made it more than eighty characters. DESC end @@ -557,9 +609,7 @@ Also, a list: util_build_gem spec end - FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name) - - Gem.source_index = nil + FileUtils.rm_r File.join(@gemhome, "gems", @pl1.original_name) end ## @@ -589,6 +639,7 @@ Also, a list: @fetcher = Gem::FakeFetcher.new util_make_gems(prerelease) + Gem::Specification.reset @all_gems = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2].sort @all_gem_names = @all_gems.map { |gem| gem.full_name } @@ -596,14 +647,6 @@ Also, a list: gem_names = [@a1.full_name, @a2.full_name, @a3a.full_name, @b2.full_name] @gem_names = gem_names.sort.join("\n") - @source_index = Gem::SourceIndex.new - @source_index.add_spec @a1 - @source_index.add_spec @a2 - @source_index.add_spec @a3a - @source_index.add_spec @a_evil9 - @source_index.add_spec @c1_2 - @source_index.add_spec @a2_pre if prerelease - Gem::RemoteFetcher.fetcher = @fetcher end @@ -612,37 +655,42 @@ Also, a list: # Best used with +@all_gems+ from #util_setup_fake_fetcher. def util_setup_spec_fetcher(*specs) - specs = Hash[*specs.map { |spec| [spec.full_name, spec] }.flatten] - si = Gem::SourceIndex.new specs + specs -= Gem::Specification._all + Gem::Specification.add_specs(*specs) spec_fetcher = Gem::SpecFetcher.fetcher + prerelease, _ = Gem::Specification.partition { |spec| + spec.version.prerelease? + } + spec_fetcher.specs[@uri] = [] - si.gems.sort_by { |_, spec| spec }.each do |_, spec| + Gem::Specification.each do |spec| spec_tuple = [spec.name, spec.version, spec.original_platform] spec_fetcher.specs[@uri] << spec_tuple end spec_fetcher.latest_specs[@uri] = [] - si.latest_specs.sort.each do |spec| + Gem::Specification.latest_specs.each do |spec| spec_tuple = [spec.name, spec.version, spec.original_platform] spec_fetcher.latest_specs[@uri] << spec_tuple end spec_fetcher.prerelease_specs[@uri] = [] - si.prerelease_specs.sort.each do |spec| + prerelease.each do |spec| spec_tuple = [spec.name, spec.version, spec.original_platform] spec_fetcher.prerelease_specs[@uri] << spec_tuple end - (si.gems.merge si.prerelease_gems).sort_by { |_,spec| spec }.each do |_, spec| - path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz" + v = Gem.marshal_version + Gem::Specification.each do |spec| + path = "#{@gem_repo}quick/Marshal.#{v}/#{spec.original_name}.gemspec.rz" data = Marshal.dump spec data_deflate = Zlib::Deflate.deflate data @fetcher.data[path] = data_deflate end - si + nil # force errors end ## diff --git a/lib/rubygems/test_utilities.rb b/lib/rubygems/test_utilities.rb index 43f905f017..1e43fe5eb9 100644 --- a/lib/rubygems/test_utilities.rb +++ b/lib/rubygems/test_utilities.rb @@ -103,8 +103,8 @@ class Gem::FakeFetcher end def download spec, source_uri, install_dir = Gem.dir - name = spec.file_name - path = Gem.cache_gem(name, install_dir) + name = File.basename spec.cache_file + path = File.join install_dir, "cache", name Gem.ensure_gem_subdirectories install_dir @@ -120,7 +120,8 @@ class Gem::FakeFetcher end def download_to_cache dependency - found = Gem::SpecFetcher.fetcher.fetch dependency + found = Gem::SpecFetcher.fetcher.fetch dependency, true, true, + dependency.prerelease? return if found.empty? diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb index ddf1e820a7..a4642f961d 100644 --- a/lib/rubygems/text.rb +++ b/lib/rubygems/text.rb @@ -21,7 +21,7 @@ module Gem::Text while work.length > wrap do if work =~ /^(.{0,#{wrap}})[ \n]/ then - result << $1 + result << $1.rstrip work.slice!(0, $&.length) else result << work.slice!(0, wrap) diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index 02976866b1..1e370c38ee 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -48,26 +48,23 @@ class Gem::Uninstaller # Constructs an uninstaller that will uninstall +gem+ def initialize(gem, options = {}) - @gem = gem - @version = options[:version] || Gem::Requirement.default - gem_home = options[:install_dir] || Gem.dir - @gem_home = File.expand_path gem_home + @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] + @force_all = options[:all] + @force_ignore = options[:ignore] + @bin_dir = options[:bin_dir] @format_executable = options[:format_executable] # only add user directory if install_dir is not set @user_install = false @user_install = options[:user_install] unless options[:install_dir] - spec_dir = File.join @gem_home, 'specifications' - @source_index = Gem::SourceIndex.from_gems_in spec_dir - if @user_install then - user_dir = File.join Gem.user_dir, 'specifications' - @user_index = Gem::SourceIndex.from_gems_in user_dir + Gem.use_paths Gem.user_dir, @gem_home + else + Gem.use_paths @gem_home end end @@ -76,14 +73,13 @@ class Gem::Uninstaller # directory, and the cached .gem file. def uninstall - list = @source_index.find_name @gem, @version - list += @user_index.find_name @gem, @version if @user_install + list = Gem::Specification.find_all_by_name(@gem, @version) if list.empty? then raise Gem::InstallError, "cannot uninstall, check `gem list -d #{@gem}`" elsif list.size > 1 and @force_all then - remove_all list.dup + remove_all list elsif list.size > 1 then gem_names = list.collect {|gem| gem.full_name} + ["All versions"] @@ -92,21 +88,21 @@ class Gem::Uninstaller _, index = choose_from_list "Select gem to uninstall:", gem_names if index == list.size then - remove_all list.dup + remove_all list elsif index >= 0 && index < list.size then - uninstall_gem list[index], list.dup + uninstall_gem list[index] else say "Error: must enter a number [1-#{list.size+1}]" end else - uninstall_gem list.first, list.dup + uninstall_gem list.first end end ## # Uninstalls gem +spec+ - def uninstall_gem(spec, specs) + def uninstall_gem(spec) @spec = spec unless dependencies_ok? spec @@ -121,7 +117,7 @@ class Gem::Uninstaller end remove_executables @spec - remove @spec, specs + remove @spec Gem.post_uninstall_hooks.each do |hook| hook.call self @@ -137,10 +133,8 @@ class Gem::Uninstaller def remove_executables(spec) return if spec.nil? or spec.executables.empty? - bindir = @bin_dir ? @bin_dir : Gem.bindir(spec.installation_path) - - list = @source_index.find_name(spec.name).delete_if { |s| - s.version == spec.version + list = Gem::Specification.find_all { |s| + s.name == spec.name && s.version != spec.version } executables = spec.executables.clone @@ -165,6 +159,8 @@ class Gem::Uninstaller unless remove then say "Executables and scripts will remain installed." else + bindir = @bin_dir || Gem.bindir(spec.base_dir) + raise Gem::FilePermissionError, bindir unless File.writable? bindir spec.executables.each do |exe_name| @@ -181,7 +177,7 @@ class Gem::Uninstaller # NOTE: removes uninstalled gems from +list+. def remove_all(list) - list.dup.each { |spec| uninstall_gem spec, list } + list.each { |spec| uninstall_gem spec } end ## @@ -191,7 +187,7 @@ class Gem::Uninstaller # Warning: this method modifies the +list+ parameter. Once it has # uninstalled a gem, it is removed from that list. - def remove(spec, list) + def remove(spec) unless path_ok?(@gem_home, spec) or (@user_install and path_ok?(Gem.user_dir, spec)) then e = Gem::GemNotInHomeException.new \ @@ -201,28 +197,27 @@ class Gem::Uninstaller raise e end - raise Gem::FilePermissionError, spec.installation_path unless - File.writable?(spec.installation_path) + raise Gem::FilePermissionError, spec.base_dir unless + File.writable?(spec.base_dir) FileUtils.rm_rf spec.full_gem_path - original_platform_name = [ - spec.name, spec.version, spec.original_platform].join '-' + # TODO: should this be moved to spec?... I vote eww (also exists in docmgr) + old_platform_name = [spec.name, + spec.version, + spec.original_platform].join '-' - spec_dir = File.join spec.installation_path, 'specifications' - gemspec = File.join spec_dir, spec.spec_name + gemspec = spec.spec_file unless File.exist? gemspec then - gemspec = File.join spec_dir, "#{original_platform_name}.gemspec" + gemspec = File.join(File.dirname(gemspec), "#{old_platform_name}.gemspec") end FileUtils.rm_rf gemspec - gem = Gem.cache_gem(spec.file_name, spec.installation_path) - - unless File.exist? gem then - gem = Gem.cache_gem("#{original_platform_name}.gem", spec.installation_path) - end + gem = spec.cache_file + gem = File.join(spec.cache_dir, "#{old_platform_name}.gem") unless + File.exist? gem FileUtils.rm_rf gem @@ -230,14 +225,14 @@ class Gem::Uninstaller say "Successfully uninstalled #{spec.full_name}" - list.delete spec + Gem::Specification.remove_spec spec end ## # Is +spec+ in +gem_dir+? def path_ok?(gem_dir, spec) - full_path = File.join gem_dir, 'gems', spec.full_name + full_path = File.join gem_dir, 'gems', spec.full_name original_path = File.join gem_dir, 'gems', spec.original_name full_path == spec.full_gem_path || original_path == spec.full_gem_path @@ -246,8 +241,7 @@ class Gem::Uninstaller def dependencies_ok?(spec) return true if @force_ignore - deplist = Gem::DependencyList.from_source_index @source_index - deplist.add(*@user_index.gems.values) if @user_install + deplist = Gem::DependencyList.from_specs deplist.ok_to_remove?(spec.full_name) end @@ -255,11 +249,13 @@ class Gem::Uninstaller msg = [''] msg << 'You have requested to uninstall the gem:' msg << "\t#{spec.full_name}" - spec.dependent_gems.each do |gem,dep,satlist| + + spec.dependent_gems.each do |dep_spec, dep, satlist| msg << - ("#{gem.name}-#{gem.version} depends on " + - "[#{dep.name} (#{dep.requirement})]") + ("#{dep_spec.name}-#{dep_spec.version} depends on " + + "[#{dep.name} (#{dep.requirement})]") end + msg << 'If you remove this gems, one or more dependencies will not be met.' msg << 'Continue with Uninstall?' return ask_yes_no(msg.join("\n"), true) @@ -272,7 +268,4 @@ class Gem::Uninstaller filename end end - - end - diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb index 87d13dab26..1dbcf38eee 100644 --- a/lib/rubygems/user_interaction.rb +++ b/lib/rubygems/user_interaction.rb @@ -90,44 +90,40 @@ module Gem::UserInteraction include Gem::DefaultUserInteraction - ## - # :method: alert + def alert(*args) + ui.alert(*args) + end - ## - # :method: alert_error + def alert_error(*args) + ui.alert_error(*args) + end - ## - # :method: alert_warning + def alert_warning(*args) + ui.alert_warning(*args) + end - ## - # :method: ask + def ask(*args) + ui.ask(*args) + end - ## - # :method: ask_yes_no + def ask_for_password(*args) + ui.ask_for_password(*args) + end - ## - # :method: choose_from_list + def ask_yes_no(*args) + ui.ask_yes_no(*args) + end - ## - # :method: say + def choose_from_list(*args) + ui.choose_from_list(*args) + end - ## - # :method: terminate_interaction - - [:alert, - :alert_error, - :alert_warning, - :ask, - :ask_for_password, - :ask_yes_no, - :choose_from_list, - :say, - :terminate_interaction ].each do |methname| - class_eval %{ - def #{methname}(*args) - ui.#{methname}(*args) - end - }, __FILE__, __LINE__ + def say(*args) + ui.say(*args) + end + + def terminate_interaction(*args) + ui.terminate_interaction(*args) end end diff --git a/test/rubygems/functional.rb b/test/rubygems/functional.rb deleted file mode 100644 index 6b7131f9d6..0000000000 --- a/test/rubygems/functional.rb +++ /dev/null @@ -1,98 +0,0 @@ -###################################################################### -# This file is imported from the rubygems project. -# DO NOT make modifications in this repo. They _will_ be reverted! -# File a patch instead and assign it to Ryan Davis or Eric Hodel. -###################################################################### - -require 'rubygems' -require 'minitest/unit' -require 'test/insure_session' -require 'rubygems/format' -require 'rubygems/command_manager' - -class FunctionalTest < MiniTest::Unit::TestCase - - def setup - @gem_path = File.expand_path("bin/gem") - lib_path = File.expand_path("lib") - @ruby_options = "-I#{lib_path} -I." - @verbose = false - end - - def test_gem_help_options - gem_nossl 'help options' - assert_match(/Usage:/, @out, @err) - assert_status - end - - def test_gem_help_commands - gem_nossl 'help commands' - assert_match(/gem install/, @out) - assert_status - end - - def test_gem_no_args_shows_help - gem_nossl - assert_match(/Usage:/, @out) - assert_status 1 - end - - # This test is disabled because of the insanely long time it takes - # to time out. - def xtest_bogus_source_hoses_up_remote_install_but_gem_command_gives_decent_error_message - @ruby_options << " -rtest/bogussources" - gem_nossl "install asdf --remote" - assert_match(/error/im, @err) - assert_status 1 - end - - def test_all_command_helps - mgr = Gem::CommandManager.new - mgr.command_names.each do |cmdname| - gem_nossl "help #{cmdname}" - assert_match(/Usage: gem #{cmdname}/, @out, - "should see help for #{cmdname}") - end - end - - # :section: Help Methods - - # Run a gem command without the SSL library. - def gem_nossl(options="") - old_options = @ruby_options.dup - @ruby_options << " -Itest/fake_certlib" - gem(options) - ensure - @ruby_options = old_options - end - - # Run a gem command with the SSL library. - def gem_withssl(options="") - gem(options) - end - - # Run a gem command for the functional test. - def gem(options="") - shell = Session::Shell.new - options = options + " --config-file missing_file" if options !~ /--config-file/ - command = "#{Gem.ruby} #{@ruby_options} #{@gem_path} #{options}" - puts "\n\nCOMMAND: [#{command}]" if @verbose - @out, @err = shell.execute command - @status = shell.exit_status - puts "STATUS: [#{@status}]" if @verbose - puts "OUTPUT: [#{@out}]" if @verbose - puts "ERROR: [#{@err}]" if @verbose - puts "PWD: [#{Dir.pwd}]" if @verbose - shell.close - end - - private - - def assert_status(expected_status=0) - assert_equal expected_status, @status - end - -end - -MiniTest::Unit.autorun - diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 118066b957..96077117e2 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -29,12 +29,12 @@ class TestGem < Gem::TestCase def assert_activate expected, *specs specs.each do |spec| case spec - when Array - Gem.activate(*spec) - when String - Gem.activate spec + when String then + Gem::Specification.find_by_name(spec).activate + when Gem::Specification then + spec.activate else - Gem.activate spec.name + flunk spec.inspect end end @@ -57,17 +57,21 @@ class TestGem < Gem::TestCase Gem.unresolved_deps.values.map(&:to_s).sort end + # TODO: move these to specification def test_self_activate_via_require - new_spec "a", "1", "b" => "= 1" - new_spec "b", "1", nil, "lib/b/c.rb" - new_spec "b", "2", nil, "lib/b/c.rb" + 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 - Gem.activate "a", "= 1" + a1.activate require "b/c" 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" @@ -77,7 +81,7 @@ class TestGem < Gem::TestCase install_specs a1, b1, b2, c1, c2 - Gem.activate "a", "= 1" + a1.activate assert_equal %w(a-1 b-1 c-1), loaded_spec_names end @@ -88,6 +92,7 @@ class TestGem < Gem::TestCase $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" @@ -96,9 +101,10 @@ class TestGem < Gem::TestCase c1 = new_spec "c", "1" c2 = new_spec "c", "2" + Gem::Specification.reset install_specs a1, b1, b2, c1, c2 - Gem.activate "a", "= 1" + a1.activate assert_equal %w(a-1), loaded_spec_names assert_equal ["b (> 0)"], unresolved_names @@ -109,6 +115,7 @@ class TestGem < Gem::TestCase end end + # TODO: move these to specification def test_self_activate_ambiguous_indirect save_loaded_features do a1 = new_spec "a", "1", "b" => "> 0" @@ -119,7 +126,7 @@ class TestGem < Gem::TestCase install_specs a1, b1, b2, c1, c2 - Gem.activate "a", "= 1" + a1.activate assert_equal %w(a-1), loaded_spec_names assert_equal ["b (> 0)"], unresolved_names @@ -130,6 +137,7 @@ 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" @@ -141,7 +149,7 @@ class TestGem < Gem::TestCase install_specs a1, b1, b2, c1, c2, d1 - Gem.activate "a", "= 1" + a1.activate assert_equal %w(a-1), loaded_spec_names assert_equal ["b (> 0)"], unresolved_names @@ -152,6 +160,7 @@ class TestGem < Gem::TestCase 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" @@ -163,7 +172,7 @@ class TestGem < Gem::TestCase install_specs a1, a2, b1, b2, c1, c2 - Gem.activate "a", "= 2" + a2.activate assert_equal %w(a-2), loaded_spec_names assert_equal ["b (> 0)"], unresolved_names @@ -174,13 +183,14 @@ class TestGem < Gem::TestCase 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 - Gem.activate "a", "= 1" + a1.activate assert_equal %w(a-1), loaded_spec_names assert_equal [], unresolved_names @@ -191,6 +201,7 @@ class TestGem < Gem::TestCase 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" @@ -202,8 +213,8 @@ class TestGem < Gem::TestCase install_specs a1, a2, b1, b2, c1, c2 - Gem.activate "a", "= 1" - Gem.activate "c", "= 1" + a1.activate + c1.activate assert_equal %w(a-1 c-1), loaded_spec_names assert_equal ["b (> 0)"], unresolved_names @@ -222,11 +233,26 @@ class TestGem < Gem::TestCase end end + def test_require_does_not_glob + save_loaded_features do + a1 = new_spec "a", "1", nil, "lib/a1.rb" + + install_specs a1 + + assert_raises ::LoadError do + require "a*" + end + + assert_equal [], loaded_spec_names + end + end + + # TODO: move these to specification def test_self_activate_loaded - util_spec 'foo', '1' + foo = util_spec 'foo', '1' - assert Gem.activate 'foo' - refute Gem.activate 'foo' + assert foo.activate + refute foo.activate end ## @@ -249,15 +275,16 @@ class TestGem < Gem::TestCase # [B] ~> 1.0 # # and should resolve using b-1.0 + # TODO: move these to specification def test_self_activate_over - util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '= 1.0' + 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' - Gem.activate "a" + a.activate assert_equal %w[a-1.0 c-1.0], loaded_spec_names assert_equal ["b (>= 1.0, ~> 1.0)"], unresolved_names @@ -412,28 +439,22 @@ class TestGem < Gem::TestCase assert_activate %w[d-1 e-1], e1, "d" end - def test_self_all_load_paths + def test_self_available? util_make_gems - - expected = [ - File.join(@gemhome, *%W[gems #{@a1.full_name} lib]), - File.join(@gemhome, *%W[gems #{@a2.full_name} lib]), - File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]), - File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]), - File.join(@gemhome, *%W[gems #{@b2.full_name} lib]), - File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]), - File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]), - ] - - assert_equal expected, Gem.all_load_paths.sort + Deprecate.skip_during do + assert(Gem.available?("a")) + assert(Gem.available?("a", "1")) + assert(Gem.available?("a", ">1")) + assert(!Gem.available?("monkeys")) + end end - def test_self_available? - util_make_gems - assert(Gem.available?("a")) - assert(Gem.available?("a", "1")) - assert(Gem.available?("a", ">1")) - assert(!Gem.available?("monkeys")) + def test_self_bin_path_no_exec_name + e = assert_raises ArgumentError do + Gem.bin_path 'a' + end + + assert_equal 'you must supply exec_name', e.message end def test_self_bin_path_bin_name @@ -446,16 +467,6 @@ class TestGem < Gem::TestCase assert_equal @abin_path, Gem.bin_path('a', 'abin', '4') end - def test_self_bin_path_name - util_exec_gem - assert_equal @exec_path, Gem.bin_path('a') - end - - def test_self_bin_path_name_version - util_exec_gem - assert_equal @exec_path, Gem.bin_path('a', nil, '4') - end - def test_self_bin_path_nonexistent_binfile quick_spec 'a', '2' do |s| s.executables = ['exec'] @@ -467,14 +478,14 @@ class TestGem < Gem::TestCase def test_self_bin_path_no_bin_file quick_spec 'a', '1' - assert_raises(Gem::Exception) do + assert_raises(ArgumentError) do Gem.bin_path('a', nil, '1') end end def test_self_bin_path_not_found assert_raises(Gem::GemNotFoundException) do - Gem.bin_path('non-existent') + Gem.bin_path('non-existent', 'blah') end end @@ -482,7 +493,6 @@ class TestGem < Gem::TestCase util_exec_gem quick_spec 'a', '10' do |s| s.executables = [] - s.default_executable = nil end # Should not find a-10's non-abin (bug) assert_equal @abin_path, Gem.bin_path('a', 'abin') @@ -507,17 +517,12 @@ class TestGem < Gem::TestCase end def test_self_clear_paths - Gem.dir - Gem.path - searcher = Gem.searcher - source_index = Gem.source_index + assert_match(/gemhome$/, Gem.dir) + assert_match(/gemhome$/, Gem.path.first) Gem.clear_paths - assert_equal nil, Gem.instance_variable_get(:@gem_home) - assert_equal nil, Gem.instance_variable_get(:@gem_path) - refute_equal searcher, Gem.searcher - refute_equal source_index.object_id, Gem.source_index.object_id + assert_nil Gem::Specification.send(:class_variable_get, :@@all) end def test_self_configuration @@ -540,8 +545,6 @@ class TestGem < Gem::TestCase install_gem foo end - Gem.source_index = nil - gem 'foo' expected = File.join @gemhome, 'gems', foo.full_name, 'data', 'foo' @@ -598,7 +601,7 @@ class TestGem < Gem::TestCase Gem.ensure_gem_subdirectories @gemhome - assert File.directory?(Gem.cache_dir(@gemhome)) + assert File.directory? File.join(@gemhome, "cache") end def test_self_ensure_gem_directories_missing_parents @@ -610,7 +613,7 @@ class TestGem < Gem::TestCase Gem.ensure_gem_subdirectories gemdir - assert File.directory?(Gem.cache_dir(gemdir)) + assert File.directory?(util_cache_dir) end unless win_platform? then # only for FS that support write protection @@ -624,7 +627,7 @@ class TestGem < Gem::TestCase Gem.ensure_gem_subdirectories gemdir - refute File.exist?(Gem.cache_dir(gemdir)) + refute File.exist?(util_cache_dir) ensure FileUtils.chmod 0600, gemdir end @@ -641,7 +644,7 @@ class TestGem < Gem::TestCase Gem.ensure_gem_subdirectories gemdir - refute File.exist?(Gem.cache_dir(gemdir)) + refute File.exist? File.join(gemdir, "gems") ensure FileUtils.chmod 0600, parent end @@ -661,30 +664,26 @@ class TestGem < Gem::TestCase end def test_self_find_files - discover_path = File.join 'lib', 'sff', 'discover.rb' cwd = File.expand_path("test/rubygems", @@project_dir) $LOAD_PATH.unshift cwd - foo1 = quick_gem 'sff', '1' do |s| - s.files << discover_path - end - - foo2 = quick_gem 'sff', '2' do |s| - s.files << discover_path - end - - path = File.join 'gems', foo1.full_name, discover_path - write_file(path) { |fp| fp.puts "# #{path}" } + discover_path = File.join 'lib', 'sff', 'discover.rb' - path = File.join 'gems', foo2.full_name, discover_path - write_file(path) { |fp| fp.puts "# #{path}" } + foo1, foo2 = %w(1 2).map { |version| + spec = quick_gem 'sff', version do |s| + s.files << discover_path + end - @fetcher = Gem::FakeFetcher.new - Gem::RemoteFetcher.fetcher = @fetcher + write_file(File.join 'gems', spec.full_name, discover_path) do |fp| + fp.puts "# #{spec.full_name}" + end - Gem.source_index = util_setup_spec_fetcher foo1, foo2 + spec + } + # HACK should be Gem.refresh Gem.searcher = nil + Gem::Specification.reset expected = [ File.expand_path('test/rubygems/sff/discover.rb', @@project_dir), @@ -698,26 +697,11 @@ class TestGem < Gem::TestCase assert_equal cwd, $LOAD_PATH.shift end - def test_self_latest_load_paths - util_make_gems - - expected = [ - File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]), - File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]), - File.join(@gemhome, *%W[gems #{@b2.full_name} lib]), - File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]), - File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]), - ] - - assert_equal expected, Gem.latest_load_paths.sort - end - def test_self_loaded_specs foo = quick_spec 'foo' install_gem foo - Gem.source_index = nil - Gem.activate 'foo' + foo.activate assert_equal true, Gem.loaded_specs.keys.include?('foo') end @@ -738,9 +722,10 @@ class TestGem < Gem::TestCase orig_APPLE_GEM_HOME = APPLE_GEM_HOME Object.send :remove_const, :APPLE_GEM_HOME end - Gem.instance_variable_set :@gem_path, nil - assert_equal [Gem.default_path, Gem.dir].flatten, Gem.path + Gem.instance_variable_set :@paths, nil + + assert_equal [Gem.default_path, Gem.dir].flatten.uniq, Gem.path ensure Object.const_set :APPLE_GEM_HOME, orig_APPLE_GEM_HOME end @@ -771,7 +756,6 @@ class TestGem < Gem::TestCase end def test_self_path_ENV_PATH - Gem.send :set_paths, nil path_count = Gem.path.size Gem.clear_paths @@ -840,29 +824,20 @@ class TestGem < Gem::TestCase def test_self_refresh util_make_gems - a1_spec = File.join @gemhome, "specifications", @a1.spec_name - - FileUtils.mv a1_spec, @tempdir + a1_spec = @a1.spec_file + moved_path = File.join @tempdir, File.basename(a1_spec) - refute Gem.source_index.gems.include?(@a1.full_name) - - FileUtils.mv File.join(@tempdir, @a1.spec_name), a1_spec + FileUtils.mv a1_spec, moved_path Gem.refresh - assert_includes Gem.source_index.gems, @a1.full_name - assert_equal nil, Gem.instance_variable_get(:@searcher) - end + refute_includes Gem::Specification.all_names, @a1.full_name - def test_self_required_location - util_make_gems + FileUtils.mv moved_path, a1_spec + + Gem.refresh - assert_equal File.join(@tempdir, *%w[gemhome gems c-1.2 lib code.rb]), - Gem.required_location("c", "code.rb") - assert_equal File.join(@tempdir, *%w[gemhome gems a-1 lib code.rb]), - Gem.required_location("a", "code.rb", "< 2") - assert_equal File.join(@tempdir, *%w[gemhome gems a-2 lib code.rb]), - Gem.required_location("a", "code.rb", "= 2") + assert_includes Gem::Specification.all_names, @a1.full_name end def test_self_ruby_escaping_spaces_in_path @@ -927,19 +902,20 @@ class TestGem < Gem::TestCase util_restore_RUBY_VERSION end - def test_self_searcher - assert_kind_of Gem::GemPathSearcher, Gem.searcher - end - - def test_self_set_paths + def test_self_paths_eq other = File.join @tempdir, 'other' path = [@userhome, other].join File::PATH_SEPARATOR - Gem.send :set_paths, path + + # + # FIXME remove after fixing test_case + # + ENV["GEM_HOME"] = @gemhome + Gem.paths = { "GEM_PATH" => path } assert_equal [@userhome, other, @gemhome], Gem.path end - def test_self_set_paths_nonexistent_home + def test_self_paths_eq_nonexistent_home ENV['GEM_HOME'] = @gemhome Gem.clear_paths @@ -947,19 +923,37 @@ class TestGem < Gem::TestCase ENV['HOME'] = other - Gem.send :set_paths, other + Gem.paths = { "GEM_PATH" => other } assert_equal [other, @gemhome], Gem.path end def test_self_source_index - assert_kind_of Gem::SourceIndex, Gem.source_index + Deprecate.skip_during do + assert_kind_of Gem::SourceIndex, Gem.source_index + end end def test_self_sources assert_equal %w[http://gems.example.com/], Gem.sources end + def test_self_try_activate_missing_dep + a = util_spec 'a', '1.0', 'b' => '>= 1.0' + + a_file = File.join a.gem_dir, 'lib', 'a_file.rb' + + write_file a_file do |io| + io.puts '# a_file.rb' + end + + e = assert_raises Gem::LoadError do + Gem.try_activate 'a_file' + end + + assert_match %r%Could not find b %, e.message + end + def test_ssl_available_eh orig_Gem_ssl_available = Gem.ssl_available? @@ -994,20 +988,6 @@ class TestGem < Gem::TestCase end end - def test_self_cache_dir - util_ensure_gem_dirs - - assert_equal File.join(@gemhome, 'cache'), Gem.cache_dir - assert_equal File.join(@userhome, '.gem', Gem.ruby_engine, Gem::ConfigMap[:ruby_version], 'cache'), Gem.cache_dir(Gem.user_dir) - end - - def test_self_cache_gem - util_ensure_gem_dirs - - assert_equal File.join(@gemhome, 'cache', 'test.gem'), Gem.cache_gem('test.gem') - assert_equal File.join(@userhome, '.gem', Gem.ruby_engine, Gem::ConfigMap[:ruby_version], 'cache', 'test.gem'), Gem.cache_gem('test.gem', Gem.user_dir) - end - if Gem.win_platform? then def test_self_user_home_userprofile skip 'Ruby 1.9 properly handles ~ path expansion' unless '1.9' > RUBY_VERSION @@ -1069,8 +1049,8 @@ class TestGem < Gem::TestCase install_gem foo end - Gem.source_index = nil Gem.searcher = nil + Gem::Specification.reset gem 'foo' @@ -1114,6 +1094,10 @@ class TestGem < Gem::TestCase def util_ensure_gem_dirs Gem.ensure_gem_subdirectories @gemhome + + # + # FIXME what does this solve precisely? -ebh + # @additional.each do |dir| Gem.ensure_gem_subdirectories @gemhome end @@ -1121,7 +1105,6 @@ class TestGem < Gem::TestCase def util_exec_gem spec, _ = quick_spec 'a', '4' do |s| - s.default_executable = 'exec' s.executables = ['exec', 'abin'] end @@ -1164,5 +1147,9 @@ class TestGem < Gem::TestCase Gem::Commands.send :remove_const, :InterruptCommand if Gem::Commands.const_defined? :InterruptCommand end + + def util_cache_dir + File.join Gem.dir, "cache" + end end diff --git a/test/rubygems/test_gem_builder.rb b/test/rubygems/test_gem_builder.rb index f95472f626..5895b5f458 100644 --- a/test/rubygems/test_gem_builder.rb +++ b/test/rubygems/test_gem_builder.rb @@ -6,6 +6,7 @@ require 'rubygems/test_case' require 'rubygems/builder' +require 'rubygems/package' class TestGemBuilder < Gem::TestCase @@ -29,5 +30,21 @@ class TestGemBuilder < Gem::TestCase end end -end + def test_build_specification_result + util_make_gems + + spec = build_gem_and_yield_spec @a1 + + assert_operator @a1, :eql?, spec + end + def build_gem_and_yield_spec(spec) + builder = Gem::Builder.new spec + + spec = Dir.chdir @tempdir do + FileUtils.mkdir 'lib' + File.open('lib/code.rb', 'w') { |f| f << "something" } + Gem::Package.open(File.open(builder.build, 'rb')) { |x| x.metadata } + end + end +end diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb index 3769c250d5..54b26e1b9e 100644 --- a/test/rubygems/test_gem_command_manager.rb +++ b/test/rubygems/test_gem_command_manager.rb @@ -29,6 +29,7 @@ class TestGemCommandManager < Gem::TestCase end ensure $:.replace old_load_path + Gem::CommandManager.reset end def test_run_crash_command @@ -46,6 +47,7 @@ class TestGemCommandManager < Gem::TestCase end ensure $:.replace old_load_path + @command_manager.unregister_command :crash end def test_process_args_bad_arg diff --git a/test/rubygems/test_gem_commands_build_command.rb b/test/rubygems/test_gem_commands_build_command.rb index 5c38a1a5e8..d4d7c29b72 100644 --- a/test/rubygems/test_gem_commands_build_command.rb +++ b/test/rubygems/test_gem_commands_build_command.rb @@ -40,10 +40,38 @@ class TestGemCommandsBuildCommand < Gem::TestCase util_test_build_gem @gem, gemspec_file end - def test_execute_bad_gem + def test_execute_bad_spec + @gem.date = "2010-11-08" + + gemspec_file = File.join(@tempdir, @gem.spec_name) + + File.open gemspec_file, 'w' do |gs| + gs.write @gem.to_ruby.sub(/11-08/, "11-8") + end + + @cmd.options[:args] = [gemspec_file] + + out, err = use_ui @ui do + capture_io do + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end + end + end + + assert_equal "", out + assert_match(/invalid date format in specification/, err) + + assert_equal '', @ui.output + assert_equal "ERROR: Error loading gemspec. Aborting.\n", @ui.error + end + + def test_execute_missing_file @cmd.options[:args] = %w[some_gem] use_ui @ui do - @cmd.execute + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end end assert_equal '', @ui.output @@ -67,7 +95,7 @@ class TestGemCommandsBuildCommand < Gem::TestCase assert_equal [], output assert_equal '', @ui.error - gem_file = File.join @tempdir, gem.file_name + gem_file = File.join @tempdir, File.basename(gem.cache_file) assert File.exist?(gem_file) spec = Gem::Format.from_file_by_path(gem_file).spec diff --git a/test/rubygems/test_gem_commands_cleanup_command.rb b/test/rubygems/test_gem_commands_cleanup_command.rb new file mode 100644 index 0000000000..14224c4752 --- /dev/null +++ b/test/rubygems/test_gem_commands_cleanup_command.rb @@ -0,0 +1,57 @@ +###################################################################### +# This file is imported from the rubygems project. +# DO NOT make modifications in this repo. They _will_ be reverted! +# File a patch instead and assign it to Ryan Davis or Eric Hodel. +###################################################################### + +require 'rubygems/test_case' +require 'rubygems/commands/cleanup_command' + +class TestGemCommandsCleanupCommand < Gem::TestCase + + def setup + super + + @cmd = Gem::Commands::CleanupCommand.new + + @a_1 = quick_spec 'a', 1 + @a_2 = quick_spec 'a', 2 + + install_gem @a_1 + install_gem @a_2 + end + + def test_execute + @cmd.options[:args] = %w[a] + + @cmd.execute + + refute_path_exists @a_1.gem_dir + end + + def test_execute_all + @b_1 = quick_spec 'b', 1 + @b_2 = quick_spec 'b', 2 + + install_gem @b_1 + install_gem @b_2 + + @cmd.options[:args] = [] + + @cmd.execute + + refute_path_exists @a_1.gem_dir + refute_path_exists @b_1.gem_dir + end + + def test_execute_dry_run + @cmd.options[:args] = %w[a] + @cmd.options[:dryrun] = true + + @cmd.execute + + assert_path_exists @a_1.gem_dir + end + +end + diff --git a/test/rubygems/test_gem_commands_contents_command.rb b/test/rubygems/test_gem_commands_contents_command.rb index 6b9750e861..cf927e73dd 100644 --- a/test/rubygems/test_gem_commands_contents_command.rb +++ b/test/rubygems/test_gem_commands_contents_command.rb @@ -15,11 +15,18 @@ class TestGemCommandsContentsCommand < Gem::TestCase @cmd = Gem::Commands::ContentsCommand.new end + def gem name + spec = quick_gem name do |gem| + gem.files = %W[lib/#{name}.rb Rakefile] + end + write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb]) + write_file File.join(*%W[gems #{spec.full_name} Rakefile]) + end + def test_execute @cmd.options[:args] = %w[foo] - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end + + gem 'foo' use_ui @ui do @cmd.execute @@ -33,13 +40,8 @@ class TestGemCommandsContentsCommand < Gem::TestCase def test_execute_all @cmd.options[:all] = true - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end - - quick_gem 'bar' do |gem| - gem.files = %w[lib/bar.rb Rakefile] - end + gem 'foo' + gem 'bar' use_ui @ui do @cmd.execute @@ -67,13 +69,8 @@ class TestGemCommandsContentsCommand < Gem::TestCase def test_execute_exact_match @cmd.options[:args] = %w[foo] - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end - - quick_gem 'foo_bar' do |gem| - gem.files = %w[lib/foo_bar.rb Rakefile] - end + gem 'foo' + gem 'bar' use_ui @ui do @cmd.execute @@ -88,9 +85,7 @@ class TestGemCommandsContentsCommand < Gem::TestCase @cmd.options[:args] = %w[foo] @cmd.options[:lib_only] = true - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end + gem 'foo' use_ui @ui do @cmd.execute @@ -104,13 +99,9 @@ class TestGemCommandsContentsCommand < Gem::TestCase def test_execute_multiple @cmd.options[:args] = %w[foo bar] - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end - quick_gem 'bar' do |gem| - gem.files = %w[lib/bar.rb Rakefile] - end + gem 'foo' + gem 'bar' use_ui @ui do @cmd.execute @@ -126,17 +117,15 @@ class TestGemCommandsContentsCommand < Gem::TestCase @cmd.options[:args] = %w[foo] @cmd.options[:prefix] = false - quick_gem 'foo' do |gem| - gem.files = %w[lib/foo.rb Rakefile] - end + gem 'foo' use_ui @ui do @cmd.execute end expected = <<-EOF -lib/foo.rb Rakefile +lib/foo.rb EOF assert_equal expected, @ui.output diff --git a/test/rubygems/test_gem_commands_dependency_command.rb b/test/rubygems/test_gem_commands_dependency_command.rb index 665cd98c4d..d3f2b68640 100644 --- a/test/rubygems/test_gem_commands_dependency_command.rb +++ b/test/rubygems/test_gem_commands_dependency_command.rb @@ -24,8 +24,6 @@ class TestGemCommandsDependencyCommand < Gem::TestCase gem.add_dependency 'baz', '> 1' end - Gem.source_index = nil - @cmd.options[:args] = %w[foo] use_ui @ui do @@ -38,8 +36,6 @@ class TestGemCommandsDependencyCommand < Gem::TestCase end def test_execute_no_args - Gem.source_index = nil - @cmd.options[:args] = [] use_ui @ui do @@ -99,8 +95,6 @@ Gem pl-1-x86-linux end def test_execute_regexp - Gem.source_index = nil - @cmd.options[:args] = %w[/[ab]/] use_ui @ui do @@ -136,8 +130,6 @@ Gem b-2 gem.add_dependency 'foo' end - Gem.source_index = nil - @cmd.options[:args] = %w[foo] @cmd.options[:reverse_dependencies] = true @@ -199,14 +191,31 @@ ERROR: Only reverse dependencies for local gems are supported. assert_equal '', @ui.error end + def test_execute_remote_version + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + util_setup_spec_fetcher @a1, @a2 + + @cmd.options[:args] = %w[a] + @cmd.options[:domain] = :remote + @cmd.options[:version] = req '= 1' + + use_ui @ui do + @cmd.execute + end + + assert_equal "Gem a-1\n\n", @ui.output + assert_equal '', @ui.error + end + def test_execute_prerelease @fetcher = Gem::FakeFetcher.new Gem::RemoteFetcher.fetcher = @fetcher + util_clear_gems util_setup_spec_fetcher @a2_pre - FileUtils.rm File.join(@gemhome, 'specifications', @a2_pre.spec_name) - @cmd.options[:args] = %w[a] @cmd.options[:domain] = :remote @cmd.options[:prerelease] = true diff --git a/test/rubygems/test_gem_commands_fetch_command.rb b/test/rubygems/test_gem_commands_fetch_command.rb index 173a33572f..926e9e97e0 100644 --- a/test/rubygems/test_gem_commands_fetch_command.rb +++ b/test/rubygems/test_gem_commands_fetch_command.rb @@ -22,7 +22,7 @@ class TestGemCommandsFetchCommand < Gem::TestCase util_setup_spec_fetcher @a2 @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - File.read(Gem.cache_gem(@a2.file_name, @gemhome)) + File.read(@a2.cache_file) @cmd.options[:args] = [@a2.name] @@ -38,12 +38,13 @@ class TestGemCommandsFetchCommand < Gem::TestCase def test_execute_prerelease util_setup_fake_fetcher true + util_clear_gems util_setup_spec_fetcher @a2, @a2_pre @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - File.read(Gem.cache_gem(@a2.file_name, @gemhome)) + File.read(@a2.cache_file) @fetcher.data["#{@gem_repo}gems/#{@a2_pre.file_name}"] = - File.read(Gem.cache_gem(@a2_pre.file_name, @gemhome)) + File.read(@a2_pre.cache_file) @cmd.options[:args] = [@a2.name] @cmd.options[:prerelease] = true @@ -63,7 +64,7 @@ class TestGemCommandsFetchCommand < Gem::TestCase util_setup_spec_fetcher @a1, @a2 @fetcher.data["#{@gem_repo}gems/#{@a1.file_name}"] = - File.read(Gem.cache_gem(@a1.file_name, @gemhome)) + File.read(@a1.cache_file) @cmd.options[:args] = [@a2.name] @cmd.options[:version] = Gem::Requirement.new '1' diff --git a/test/rubygems/test_gem_commands_help_command.rb b/test/rubygems/test_gem_commands_help_command.rb new file mode 100644 index 0000000000..acfc2daefc --- /dev/null +++ b/test/rubygems/test_gem_commands_help_command.rb @@ -0,0 +1,64 @@ +###################################################################### +# This file is imported from the rubygems project. +# DO NOT make modifications in this repo. They _will_ be reverted! +# File a patch instead and assign it to Ryan Davis or Eric Hodel. +###################################################################### + +require "rubygems" +require "rubygems/test_case" +require "rubygems/commands/help_command" +require "rubygems/format" +require "rubygems/command_manager" + +class TestGemCommandsHelpCommand < Gem::TestCase + def setup + super + + @cmd = Gem::Commands::HelpCommand.new + end + + def test_gem_help_bad + util_gem 'bad' do |out, err| + assert_equal('', out) + assert_match(/Unknown command bad. Try gem help commands\n/, err) + end + end + + def test_gem_help_platforms + util_gem 'platforms' do |out, err| + assert_match(/x86-freebsd/, out) + assert_equal '', err + end + end + + def test_gem_help_commands + mgr = Gem::CommandManager.new + + util_gem 'commands' do |out, err| + mgr.command_names.each do |cmd| + assert_match(/\s+#{cmd}\s+\S+/, out) + end + assert_equal '', err + end + end + + def test_gem_no_args_shows_help + util_gem do |out, err| + assert_match(/Usage:/, out) + assert_match(/gem install/, out) + assert_equal '', err + end + end + + def util_gem *args + @cmd.options[:args] = args + + use_ui @ui do + Dir.chdir @tempdir do + @cmd.execute + end + end + + yield @ui.output, @ui.error + end +end diff --git a/test/rubygems/test_gem_commands_install_command.rb b/test/rubygems/test_gem_commands_install_command.rb index adc66aa911..522731b60e 100644 --- a/test/rubygems/test_gem_commands_install_command.rb +++ b/test/rubygems/test_gem_commands_install_command.rb @@ -24,13 +24,13 @@ class TestGemCommandsInstallCommand < Gem::TestCase end def test_execute_exclude_prerelease - util_setup_fake_fetcher(:prerelease) - util_setup_spec_fetcher @a2, @a2_pre + util_setup_fake_fetcher :prerelease + util_setup_spec_fetcher @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - read_binary(Gem.cache_gem(@a2.file_name, @gemhome)) + read_binary(@a2.cache_file) @fetcher.data["#{@gem_repo}gems/#{@a2_pre.file_name}"] = - read_binary(Gem.cache_gem(@a2_pre.file_name, @gemhome)) + read_binary(@a2_pre.cache_file) @cmd.options[:args] = [@a2.name] @@ -46,13 +46,13 @@ class TestGemCommandsInstallCommand < Gem::TestCase end def test_execute_explicit_version_includes_prerelease - util_setup_fake_fetcher(:prerelease) - util_setup_spec_fetcher @a2, @a2_pre + util_setup_fake_fetcher :prerelease + util_setup_spec_fetcher @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - read_binary(Gem.cache_gem(@a2.file_name, @gemhome)) + read_binary(@a2.cache_file) @fetcher.data["#{@gem_repo}gems/#{@a2_pre.file_name}"] = - read_binary(Gem.cache_gem(@a2_pre.file_name, @gemhome)) + read_binary(@a2_pre.cache_file) @cmd.handle_options [@a2_pre.name, '--version', @a2_pre.version.to_s, "--no-ri", "--no-rdoc"] @@ -92,7 +92,7 @@ class TestGemCommandsInstallCommand < Gem::TestCase util_setup_fake_fetcher @cmd.options[:domain] = :local - FileUtils.mv Gem.cache_gem(@a2.file_name, @gemhome), @tempdir + FileUtils.mv @a2.cache_file, @tempdir @cmd.options[:args] = [@a2.name] @@ -121,15 +121,15 @@ class TestGemCommandsInstallCommand < Gem::TestCase util_setup_fake_fetcher @cmd.options[:user_install] = false - FileUtils.mv Gem.cache_gem(@a2.file_name, @gemhome), @tempdir + FileUtils.mv @a2.cache_file, @tempdir @cmd.options[:args] = [@a2.name] use_ui @ui do orig_dir = Dir.pwd begin - File.chmod 0755, @userhome - File.chmod 0555, @gemhome + FileUtils.chmod 0755, @userhome + FileUtils.chmod 0555, @gemhome Dir.chdir @tempdir assert_raises Gem::FilePermissionError do @@ -137,7 +137,7 @@ class TestGemCommandsInstallCommand < Gem::TestCase end ensure Dir.chdir orig_dir - File.chmod 0755, @gemhome + FileUtils.chmod 0755, @gemhome end end end @@ -208,13 +208,14 @@ ERROR: Possible alternatives: non_existent_with_hint end def test_execute_prerelease - util_setup_fake_fetcher(:prerelease) + util_setup_fake_fetcher :prerelease + util_clear_gems util_setup_spec_fetcher @a2, @a2_pre @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - read_binary(Gem.cache_gem(@a2.file_name, @gemhome)) + read_binary(@a2.cache_file) @fetcher.data["#{@gem_repo}gems/#{@a2_pre.file_name}"] = - read_binary(Gem.cache_gem(@a2_pre.file_name, @gemhome)) + read_binary(@a2_pre.cache_file) @cmd.options[:prerelease] = true @cmd.options[:args] = [@a2_pre.name] @@ -235,10 +236,10 @@ ERROR: Possible alternatives: non_existent_with_hint @cmd.options[:generate_ri] = true util_setup_fake_fetcher - util_setup_spec_fetcher @a2 + util_setup_spec_fetcher @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = - read_binary(Gem.cache_gem(@a2.file_name, @gemhome)) + read_binary(@a2.cache_file) @cmd.options[:args] = [@a2.name] @@ -265,9 +266,9 @@ ERROR: Possible alternatives: non_existent_with_hint util_setup_fake_fetcher @cmd.options[:domain] = :local - FileUtils.mv Gem.cache_gem(@a2.file_name, @gemhome), @tempdir + FileUtils.mv @a2.cache_file, @tempdir - FileUtils.mv Gem.cache_gem(@b2.file_name, @gemhome), @tempdir + FileUtils.mv @b2.cache_file, @tempdir @cmd.options[:args] = [@a2.name, @b2.name] @@ -293,10 +294,10 @@ ERROR: Possible alternatives: non_existent_with_hint def test_execute_conservative util_setup_fake_fetcher - util_setup_spec_fetcher @b2 + util_setup_spec_fetcher @fetcher.data["#{@gem_repo}gems/#{@b2.file_name}"] = - read_binary(Gem.cache_gem(@b2.file_name, @gemhome)) + read_binary(@b2.cache_file) uninstall_gem(@b2) @@ -308,16 +309,16 @@ ERROR: Possible alternatives: non_existent_with_hint orig_dir = Dir.pwd begin Dir.chdir @tempdir - e = assert_raises Gem::SystemExitException do + assert_raises Gem::SystemExitException do @cmd.execute end - assert_equal 0, e.exit_code ensure Dir.chdir orig_dir end end out = @ui.output.split "\n" + assert_equal "", @ui.error assert_equal "Successfully installed #{@b2.full_name}", out.shift assert_equal "1 gem installed", out.shift assert out.empty?, out.inspect diff --git a/test/rubygems/test_gem_commands_list_command.rb b/test/rubygems/test_gem_commands_list_command.rb index 9a56ebc779..1339737391 100644 --- a/test/rubygems/test_gem_commands_list_command.rb +++ b/test/rubygems/test_gem_commands_list_command.rb @@ -26,16 +26,13 @@ class TestGemCommandsListCommand < Gem::TestCase def test_execute_installed @cmd.handle_options %w[c --installed] - e = assert_raises Gem::SystemExitException do + assert_raises Gem::MockGemUi::SystemExitException do use_ui @ui do @cmd.execute end end - assert_equal 0, e.exit_code - assert_equal "true\n", @ui.output - assert_equal '', @ui.error end diff --git a/test/rubygems/test_gem_commands_outdated_command.rb b/test/rubygems/test_gem_commands_outdated_command.rb index 632e9a5548..ae15efee70 100644 --- a/test/rubygems/test_gem_commands_outdated_command.rb +++ b/test/rubygems/test_gem_commands_outdated_command.rb @@ -20,24 +20,25 @@ class TestGemCommandsOutdatedCommand < Gem::TestCase end def test_execute - quick_gem 'foo', '0.1' - quick_gem 'foo', '0.2' remote_10 = quick_spec 'foo', '1.0' remote_20 = quick_spec 'foo', '2.0' - remote_spec_file = File.join @gemhome, 'specifications', remote_10.spec_name - remote_spec_file = File.join @gemhome, 'specifications', remote_20.spec_name - - @fetcher = Gem::FakeFetcher.new - Gem::RemoteFetcher.fetcher = @fetcher + Gem::RemoteFetcher.fetcher = @fetcher = Gem::FakeFetcher.new + util_clear_gems util_setup_spec_fetcher remote_10, remote_20 - use_ui @ui do @cmd.execute end + quick_gem 'foo', '0.1' + quick_gem 'foo', '0.2' + + Gem::Specification.reset + + use_ui @ui do + @cmd.execute + end assert_equal "foo (0.2 < 2.0)\n", @ui.output assert_equal "", @ui.error end - end diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb index 4decdf81b9..aa1f3bf7a6 100644 --- a/test/rubygems/test_gem_commands_pristine_command.rb +++ b/test/rubygems/test_gem_commands_pristine_command.rb @@ -16,8 +16,8 @@ class TestGemCommandsPristineCommand < Gem::TestCase def test_execute a = quick_spec 'a' do |s| s.executables = %w[foo] end - FileUtils.mkdir_p File.join(@tempdir, 'bin') - File.open File.join(@tempdir, 'bin', 'foo'), 'w' do |fp| + + write_file File.join(@tempdir, 'bin', 'foo') do |fp| fp.puts "#!/usr/bin/ruby" end @@ -25,7 +25,7 @@ class TestGemCommandsPristineCommand < Gem::TestCase foo_path = File.join @gemhome, 'gems', a.full_name, 'bin', 'foo' - File.open foo_path, 'w' do |io| + write_file foo_path do |io| io.puts 'I changed it!' end @@ -39,15 +39,14 @@ class TestGemCommandsPristineCommand < Gem::TestCase out = @ui.output.split "\n" - assert_equal "Restoring gem(s) to pristine condition...", out.shift + assert_equal "Restoring gems to pristine condition...", out.shift assert_equal "Restored #{a.full_name}", out.shift assert_empty out, out.inspect end def test_execute_all a = quick_spec 'a' do |s| s.executables = %w[foo] end - FileUtils.mkdir_p File.join(@tempdir, 'bin') - File.open File.join(@tempdir, 'bin', 'foo'), 'w' do |fp| + write_file File.join(@tempdir, 'bin', 'foo') do |fp| fp.puts "#!/usr/bin/ruby" end @@ -67,35 +66,106 @@ class TestGemCommandsPristineCommand < Gem::TestCase out = @ui.output.split "\n" - assert_equal "Restoring gem(s) to pristine condition...", out.shift + assert_equal "Restoring gems to pristine condition...", out.shift assert_equal "Restored #{a.full_name}", out.shift assert_empty out, out.inspect end - def test_execute_missing_cache_gem - a = quick_spec 'a' do |s| - s.executables = %w[foo] + def test_execute_no_exetension + a = quick_spec 'a' do |s| s.extensions << 'ext/a/extconf.rb' end + + ext_path = File.join @tempdir, 'ext', 'a', 'extconf.rb' + write_file ext_path do |io| + io.write '# extconf.rb' end - FileUtils.mkdir_p File.join(@tempdir, 'bin') + util_build_gem a - File.open File.join(@tempdir, 'bin', 'foo'), 'w' do |fp| - fp.puts "#!/usr/bin/ruby" + @cmd.options[:args] = %w[a] + @cmd.options[:extensions] = false + + use_ui @ui do + @cmd.execute + end + + out = @ui.output.split "\n" + + assert_equal 'Restoring gems to pristine condition...', out.shift + assert_equal "Skipped #{a.full_name}, it needs to compile an extension", + out.shift + assert_empty out, out.inspect + end + + def test_execute_many + a = quick_spec 'a' + b = quick_spec 'b' + + install_gem a + install_gem b + + @cmd.options[:args] = %w[a b] + + use_ui @ui do + @cmd.execute end + out = @ui.output.split "\n" + + assert_equal "Restoring gems to pristine condition...", out.shift + assert_equal "Restored #{a.full_name}", out.shift + assert_equal "Restored #{b.full_name}", out.shift + assert_empty out, out.inspect + end + + def test_execute_many_multi_repo + a = quick_spec 'a' install_gem a - a_data = nil - open File.join(@gemhome, 'cache', a.file_name), 'rb' do |fp| - a_data = fp.read + Gem.clear_paths + gemhome2 = File.join @tempdir, 'gemhome2' + Gem.paths = { "GEM_PATH" => [gemhome2, @gemhome], "GEM_HOME" => gemhome2 } + + b = quick_spec 'b' + install_gem b + + @cmd.options[:args] = %w[a b] + + use_ui @ui do + @cmd.execute + end + + out = @ui.output.split "\n" + + assert_equal "Restoring gems to pristine condition...", out.shift + assert_equal "Restored #{a.full_name}", out.shift + assert_equal "Restored #{b.full_name}", out.shift + assert_empty out, out.inspect + + assert_path_exists File.join(@gemhome, "gems", 'a-2') + refute_path_exists File.join(gemhome2, "gems", 'a-2') + assert_path_exists File.join(gemhome2, "gems", 'b-2') + refute_path_exists File.join(@gemhome, "gems", 'b-2') + end + + def test_execute_missing_cache_gem + a_2 = quick_spec 'a', 2 + a_3 = quick_spec 'a', 3 + + install_gem a_2 + install_gem a_3 + + a_2_data = nil + open File.join(@gemhome, 'cache', a_2.file_name), 'rb' do |fp| + a_2_data = fp.read end util_setup_fake_fetcher - util_setup_spec_fetcher a + util_setup_spec_fetcher a_2 - Gem::RemoteFetcher.fetcher.data["http://gems.example.com/gems/#{a.file_name}"] = a_data + url = "http://gems.example.com/gems/#{a_2.file_name}" + Gem::RemoteFetcher.fetcher.data[url] = a_2_data - FileUtils.rm Gem.cache_gem(a.file_name, @gemhome) + FileUtils.rm a_2.cache_file @cmd.options[:args] = %w[a] @@ -106,11 +176,12 @@ class TestGemCommandsPristineCommand < Gem::TestCase out = @ui.output.split "\n" [ - "Restoring gem\(s\) to pristine condition...", + "Restoring gems to pristine condition...", "Restored a-1", "Cached gem for a-2 not found, attempting to fetch...", "Restored a-2", - "Restored a-3.a" + "Restored a-3.a", + "Restored a-3", ].each do |line| assert_equal line, out.shift end @@ -127,7 +198,7 @@ class TestGemCommandsPristineCommand < Gem::TestCase end end - assert_match %r|specify a gem name|, e.message + assert_match %r|at least one gem name|, e.message end end diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb index 917407dc32..7aa7109c45 100644 --- a/test/rubygems/test_gem_commands_push_command.rb +++ b/test/rubygems/test_gem_commands_push_command.rb @@ -21,7 +21,7 @@ class TestGemCommandsPushCommand < Gem::TestCase super @gems_dir = File.join @tempdir, 'gems' - @cache_dir = Gem.cache_dir @gemhome + @cache_dir = File.join @gemhome, "cache" FileUtils.mkdir @gems_dir diff --git a/test/rubygems/test_gem_commands_query_command.rb b/test/rubygems/test_gem_commands_query_command.rb index 91868b848b..4f06968344 100644 --- a/test/rubygems/test_gem_commands_query_command.rb +++ b/test/rubygems/test_gem_commands_query_command.rb @@ -15,8 +15,8 @@ class TestGemCommandsQueryCommand < Gem::TestCase @cmd = Gem::Commands::QueryCommand.new util_setup_fake_fetcher - - @si = util_setup_spec_fetcher @a1, @a2, @pl1, @a3a + util_clear_gems + util_setup_spec_fetcher @a1, @a2, @pl1, @a3a @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do raise Gem::RemoteFetcher::FetchError @@ -48,7 +48,8 @@ pl (1 i386-linux) @a1.platform = 'x86-linux' @a2.platform = 'universal-darwin' - @si = util_setup_spec_fetcher @a1, @a1r, @a2, @b2, @pl1 + util_clear_gems + util_setup_spec_fetcher @a1, @a1r, @a2, @b2, @pl1 @cmd.handle_options %w[-r -a] @@ -113,7 +114,8 @@ pl (1 i386-linux) @a2.homepage = 'http://a.example.com/' @a2.rubyforge_project = 'rubygems' - @si = util_setup_spec_fetcher @a1, @a2, @pl1 + util_clear_gems + util_setup_spec_fetcher @a1, @a2, @pl1 @cmd.handle_options %w[-r -d] @@ -154,7 +156,8 @@ pl (1) @a2.rubyforge_project = 'rubygems' @a2.platform = 'universal-darwin' - @si = util_setup_spec_fetcher @a1, @a2, @pl1 + util_clear_gems + util_setup_spec_fetcher @a1, @a2, @pl1 @cmd.handle_options %w[-r -d] @@ -190,25 +193,22 @@ pl (1) end def test_execute_installed - @cmd.handle_options %w[-n c --installed] + @cmd.handle_options %w[-n a --installed] - e = assert_raises Gem::SystemExitException do + assert_raises Gem::MockGemUi::SystemExitException do use_ui @ui do @cmd.execute end end - assert_equal 0, e.exit_code - assert_equal "true\n", @ui.output - assert_equal '', @ui.error end def test_execute_installed_no_name @cmd.handle_options %w[--installed] - e = assert_raises Gem::SystemExitException do + e = assert_raises Gem::MockGemUi::TermError do use_ui @ui do @cmd.execute end @@ -223,7 +223,7 @@ pl (1) def test_execute_installed_not_installed @cmd.handle_options %w[-n not_installed --installed] - e = assert_raises Gem::SystemExitException do + e = assert_raises Gem::MockGemUi::TermError do use_ui @ui do @cmd.execute end @@ -236,9 +236,9 @@ pl (1) end def test_execute_installed_version - @cmd.handle_options %w[-n c --installed --version 1.2] + @cmd.handle_options %w[-n a --installed --version 2] - e = assert_raises Gem::SystemExitException do + assert_raises Gem::MockGemUi::SystemExitException do use_ui @ui do @cmd.execute end @@ -246,14 +246,12 @@ pl (1) assert_equal "true\n", @ui.output assert_equal '', @ui.error - - assert_equal 0, e.exit_code end def test_execute_installed_version_not_installed @cmd.handle_options %w[-n c --installed --version 2] - e = assert_raises Gem::SystemExitException do + e = assert_raises Gem::MockGemUi::TermError do use_ui @ui do @cmd.execute end @@ -265,65 +263,6 @@ pl (1) assert_equal 1, e.exit_code end - def test_execute_local_details - @a3a.summary = 'This is a lot of text. ' * 4 - @a3a.authors = ['Abraham Lincoln', 'Hirohito'] - @a3a.homepage = 'http://a.example.com/' - @a3a.rubyforge_project = 'rubygems' - - @cmd.handle_options %w[--local --details] - - use_ui @ui do - @cmd.execute - end - - expected = <<-EOF - -*** LOCAL GEMS *** - -a (3.a, 2, 1) - Author: A User - Homepage: http://example.com - Installed at (3.a): #{@gemhome} - (2): #{@gemhome} - (1): #{@gemhome} - - this is a summary - -a_evil (9) - Author: A User - Homepage: http://example.com - Installed at: #{@gemhome} - - this is a summary - -b (2) - Author: A User - Homepage: http://example.com - Installed at: #{@gemhome} - - this is a summary - -c (1.2) - Author: A User - Homepage: http://example.com - Installed at: #{@gemhome} - - this is a summary - -pl (1) - Platform: i386-linux - Author: A User - Homepage: http://example.com - Installed at: #{@gemhome} - - this is a summary - EOF - - assert_equal expected, @ui.output - assert_equal '', @ui.error - end - def test_execute_local_notty @cmd.handle_options %w[] @@ -335,9 +274,6 @@ pl (1) expected = <<-EOF a (3.a, 2, 1) -a_evil (9) -b (2) -c (1.2) pl (1 i386-linux) EOF @@ -412,9 +348,6 @@ a (3.a) *** LOCAL GEMS *** a (3.a, 2, 1) -a_evil (9) -b (2) -c (1.2) pl (1 i386-linux) EOF diff --git a/test/rubygems/test_gem_commands_sources_command.rb b/test/rubygems/test_gem_commands_sources_command.rb index 40449bec22..7dea7971d2 100644 --- a/test/rubygems/test_gem_commands_sources_command.rb +++ b/test/rubygems/test_gem_commands_sources_command.rb @@ -42,12 +42,11 @@ class TestGemCommandsSourcesCommand < Gem::TestCase def test_execute_add util_setup_fake_fetcher - si = Gem::SourceIndex.new - si.add_spec @a1 + install_specs @a1 - specs = si.map do |_, spec| + specs = Gem::Specification.map { |spec| [spec.name, spec.version, spec.original_platform] - end + } specs_dump_gz = StringIO.new Zlib::GzipWriter.wrap specs_dump_gz do |io| @@ -187,18 +186,18 @@ beta-gems.example.com is not a URI @cmd.handle_options %w[--update] util_setup_fake_fetcher - source_index = util_setup_spec_fetcher @a1 + util_setup_spec_fetcher @a1 - specs = source_index.map do |name, spec| + specs = Gem::Specification.map { |spec| [spec.name, spec.version, spec.original_platform] - end + } @fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] = util_gzip Marshal.dump(specs) - latest_specs = source_index.latest_specs.map do |spec| + latest_specs = Gem::Specification.latest_specs.map { |spec| [spec.name, spec.version, spec.original_platform] - end + } @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = util_gzip Marshal.dump(latest_specs) diff --git a/test/rubygems/test_gem_commands_specification_command.rb b/test/rubygems/test_gem_commands_specification_command.rb index 767992f240..512b9f50cf 100644 --- a/test/rubygems/test_gem_commands_specification_command.rb +++ b/test/rubygems/test_gem_commands_specification_command.rb @@ -17,7 +17,8 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase def test_execute foo = quick_spec 'foo' - Gem.source_index.add_spec foo + + install_specs foo @cmd.options[:args] = %w[foo] @@ -77,8 +78,9 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase end def test_execute_field - foo = quick_spec 'foo' - Gem.source_index.add_spec foo + foo = new_spec 'foo', '2' + + install_specs foo @cmd.options[:args] = %w[foo name] @@ -90,8 +92,9 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase end def test_execute_marshal - foo = quick_spec 'foo' - Gem.source_index.add_spec foo + foo = new_spec 'foo', '2' + + install_specs foo @cmd.options[:args] = %w[foo] @cmd.options[:format] = :marshal @@ -127,7 +130,8 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase def test_execute_ruby foo = quick_spec 'foo' - Gem.source_index.add_spec foo + + install_specs foo @cmd.options[:args] = %w[foo] @cmd.options[:format] = :ruby diff --git a/test/rubygems/test_gem_commands_stale_command.rb b/test/rubygems/test_gem_commands_stale_command.rb index d5aad6ce0c..05cc9d234b 100644 --- a/test/rubygems/test_gem_commands_stale_command.rb +++ b/test/rubygems/test_gem_commands_stale_command.rb @@ -25,12 +25,12 @@ class TestGemCommandsStaleCommand < Gem::TestCase end files.each do |file| - filename = bar_baz.full_gem_path + "/#{file}" - FileUtils.mkdir_p(File.dirname(filename)) + filename = File.join(bar_baz.full_gem_path, file) + FileUtils.mkdir_p File.dirname filename FileUtils.touch(filename, :mtime => Time.now) - filename = foo_bar.full_gem_path + "/#{file}" - FileUtils.mkdir_p(File.dirname(filename)) + filename = File.join(foo_bar.full_gem_path, file) + FileUtils.mkdir_p File.dirname filename FileUtils.touch(filename, :mtime => Time.now - 86400) end diff --git a/test/rubygems/test_gem_commands_unpack_command.rb b/test/rubygems/test_gem_commands_unpack_command.rb index 8764a4017b..3f072277f1 100644 --- a/test/rubygems/test_gem_commands_unpack_command.rb +++ b/test/rubygems/test_gem_commands_unpack_command.rb @@ -21,20 +21,20 @@ class TestGemCommandsUnpackCommand < Gem::TestCase util_make_gems assert_equal( - @cmd.find_in_cache(@a1.file_name), - Gem.cache_gem(@a1.file_name, @gemhome), + @cmd.find_in_cache(File.basename @a1.cache_file), + @a1.cache_file, 'found a-1.gem in the cache' ) end def test_get_path - util_make_gems util_setup_fake_fetcher + util_clear_gems util_setup_spec_fetcher @a1 a1_data = nil - open Gem.cache_gem(@a1.file_name, @gemhome), 'rb' do |fp| + open @a1.cache_file, 'rb' do |fp| a1_data = fp.read end @@ -44,15 +44,15 @@ class TestGemCommandsUnpackCommand < Gem::TestCase dep = Gem::Dependency.new(@a1.name, @a1.version) assert_equal( @cmd.get_path(dep), - Gem.cache_gem(@a1.file_name, @gemhome), + @a1.cache_file, 'fetches a-1 and returns the cache path' ) - FileUtils.rm Gem.cache_gem(@a1.file_name, @gemhome) + FileUtils.rm @a1.cache_file assert_equal( @cmd.get_path(dep), - Gem.cache_gem(@a1.file_name, @gemhome), + @a1.cache_file, 'when removed from cache, refetches a-1' ) end @@ -73,16 +73,14 @@ class TestGemCommandsUnpackCommand < Gem::TestCase end def test_execute_gem_path - util_make_gems - util_setup_spec_fetcher util_setup_fake_fetcher + util_setup_spec_fetcher Gem.clear_paths gemhome2 = File.join @tempdir, 'gemhome2' - Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR) - Gem.send :set_home, gemhome2 + Gem.paths = { "GEM_PATH" => [gemhome2, @gemhome], "GEM_HOME" => gemhome2 } @cmd.options[:args] = %w[a] @@ -96,15 +94,14 @@ class TestGemCommandsUnpackCommand < Gem::TestCase end def test_execute_gem_path_missing - util_make_gems + util_setup_fake_fetcher util_setup_spec_fetcher Gem.clear_paths gemhome2 = File.join @tempdir, 'gemhome2' - Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR) - Gem.send :set_home, gemhome2 + Gem.paths = { "GEM_PATH" => [gemhome2, @gemhome], "GEM_HOME" => gemhome2 } @cmd.options[:args] = %w[z] @@ -123,7 +120,7 @@ class TestGemCommandsUnpackCommand < Gem::TestCase util_clear_gems a2_data = nil - open Gem.cache_gem(@a2.file_name, @gemhome), 'rb' do |fp| + open @a2.cache_file, 'rb' do |fp| a2_data = fp.read end @@ -142,10 +139,28 @@ class TestGemCommandsUnpackCommand < Gem::TestCase assert File.exist?(File.join(@tempdir, 'a-2')), 'a should be unpacked' end + def test_execute_spec + util_make_gems + + @cmd.options[:args] = %w[a b] + @cmd.options[:spec] = true + + use_ui @ui do + Dir.chdir @tempdir do + @cmd.execute + end + end + + assert File.exist?(File.join(@tempdir, 'a-3.a.gemspec')) + assert File.exist?(File.join(@tempdir, 'b-2.gemspec')) + end + def test_execute_sudo + skip 'Cannot perform this test on windows (chmod)' if win_platform? + util_make_gems - File.chmod 0555, @gemhome + FileUtils.chmod 0555, @gemhome @cmd.options[:args] = %w[b] @@ -157,7 +172,7 @@ class TestGemCommandsUnpackCommand < Gem::TestCase assert File.exist?(File.join(@tempdir, 'b-2')), 'b should be unpacked' ensure - File.chmod 0755, @gemhome + FileUtils.chmod 0755, @gemhome end def test_execute_with_target_option @@ -203,5 +218,13 @@ class TestGemCommandsUnpackCommand < Gem::TestCase assert File.exist?(File.join(@tempdir, foo_spec.full_name)) end + def test_handle_options_metadata + refute @cmd.options[:spec] + + @cmd.send :handle_options, %w[--spec a] + + assert @cmd.options[:spec] + end + end diff --git a/test/rubygems/test_gem_commands_update_command.rb b/test/rubygems/test_gem_commands_update_command.rb index 24966a3a84..b43be11843 100644 --- a/test/rubygems/test_gem_commands_update_command.rb +++ b/test/rubygems/test_gem_commands_update_command.rb @@ -24,15 +24,15 @@ class TestGemCommandsUpdateCommand < Gem::TestCase @cmd.options[:generate_ri] = false util_setup_fake_fetcher - - @a1_path = Gem.cache_gem(@a1.file_name, @gemhome) - @a2_path = Gem.cache_gem(@a2.file_name, @gemhome) - + util_clear_gems util_setup_spec_fetcher @a1, @a2 - @fetcher.data["#{@gem_repo}gems/#{@a1.file_name}"] = + @a1_path = @a1.cache_file + @a2_path = @a2.cache_file + + @fetcher.data["#{@gem_repo}gems/#{File.basename @a1_path}"] = read_binary @a1_path - @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = + @fetcher.data["#{@gem_repo}gems/#{File.basename @a2_path}"] = read_binary @a2_path end @@ -81,18 +81,19 @@ class TestGemCommandsUpdateCommand < Gem::TestCase def util_add_to_fetcher *specs specs.each do |spec| - gem_file = Gem.cache_gem(spec.file_name, @gemhome) + gem_file = spec.cache_file + file_name = File.basename gem_file - @fetcher.data["http://gems.example.com/gems/#{spec.file_name}"] = + @fetcher.data["http://gems.example.com/gems/#{file_name}"] = Gem.read_binary gem_file end end def test_execute_system + util_clear_gems util_setup_rubygem9 util_setup_spec_fetcher @rubygem9 util_add_to_fetcher @rubygem9 - util_clear_gems @cmd.options[:args] = [] @cmd.options[:system] = true @@ -113,17 +114,17 @@ class TestGemCommandsUpdateCommand < Gem::TestCase end def test_execute_system_at_latest + util_clear_gems util_setup_rubygem_current util_setup_spec_fetcher @rubygem_current util_add_to_fetcher @rubygem_current - util_clear_gems @cmd.options[:args] = [] @cmd.options[:system] = true @cmd.options[:generate_rdoc] = false @cmd.options[:generate_ri] = false - assert_raises Gem::SystemExitException do + assert_raises Gem::MockGemUi::SystemExitException do use_ui @ui do @cmd.execute end @@ -135,11 +136,11 @@ class TestGemCommandsUpdateCommand < Gem::TestCase end def test_execute_system_multiple + util_clear_gems util_setup_rubygem9 util_setup_rubygem8 util_setup_spec_fetcher @rubygem8, @rubygem9 util_add_to_fetcher @rubygem8, @rubygem9 - util_clear_gems @cmd.options[:args] = [] @cmd.options[:system] = true @@ -184,6 +185,31 @@ class TestGemCommandsUpdateCommand < Gem::TestCase assert_empty out end + def test_execute_system_specifically_to_latest_version + util_clear_gems + util_setup_rubygem9 + util_setup_rubygem8 + util_setup_spec_fetcher @rubygem8, @rubygem9 + util_add_to_fetcher @rubygem8, @rubygem9 + + @cmd.options[:args] = [] + @cmd.options[:system] = "9" + @cmd.options[:generate_rdoc] = false + @cmd.options[:generate_ri] = false + + use_ui @ui do + @cmd.execute + end + + out = @ui.output.split "\n" + assert_equal "Updating rubygems-update", out.shift + assert_equal "Successfully installed rubygems-update-9", out.shift + assert_equal "Installing RubyGems 9", out.shift + assert_equal "RubyGems system software updated", out.shift + + assert_empty out + end + def test_execute_system_with_gems @cmd.options[:args] = %w[gem] @cmd.options[:system] = true @@ -218,16 +244,11 @@ class TestGemCommandsUpdateCommand < Gem::TestCase @a2.add_dependency 'c', '2' @a2.add_dependency 'b', '2' - @b2_path = Gem.cache_gem(@b2.file_name, @gemhome) - @c1_2_path = Gem.cache_gem(@c1_2.file_name, @gemhome) - @c2_path = Gem.cache_gem(@c2.file_name, @gemhome) + @b2_path = @b2.cache_file + @c1_2_path = @c1_2.cache_file + @c2_path = @c2.cache_file - @source_index = Gem::SourceIndex.new - @source_index.add_spec @a1 - @source_index.add_spec @a2 - @source_index.add_spec @b2 - @source_index.add_spec @c1_2 - @source_index.add_spec @c2 + install_specs @a1, @a2, @b2, @c1_2, @c2 util_build_gem @a1 util_build_gem @a2 @@ -236,16 +257,16 @@ class TestGemCommandsUpdateCommand < Gem::TestCase @fetcher.data["#{@gem_repo}gems/#{@a1.file_name}"] = read_binary @a1_path @fetcher.data["#{@gem_repo}gems/#{@a2.file_name}"] = read_binary @a2_path @fetcher.data["#{@gem_repo}gems/#{@b2.file_name}"] = read_binary @b2_path - @fetcher.data["#{@gem_repo}gems/#{@c1_2.file_name}"] = - read_binary @c1_2_path + @fetcher.data["#{@gem_repo}gems/#{@c1_2.file_name}"] = read_binary @c1_2_path @fetcher.data["#{@gem_repo}gems/#{@c2.file_name}"] = read_binary @c2_path util_setup_spec_fetcher @a1, @a2, @b2, @c1_2, @c2 - util_clear_gems Gem::Installer.new(@c1_2_path).install Gem::Installer.new(@a1_path).install + Gem::Specification.reset + @cmd.options[:args] = [] use_ui @ui do diff --git a/test/rubygems/test_gem_commands_which_command.rb b/test/rubygems/test_gem_commands_which_command.rb index 8f9a2926db..7a21f7cc05 100644 --- a/test/rubygems/test_gem_commands_which_command.rb +++ b/test/rubygems/test_gem_commands_which_command.rb @@ -11,6 +11,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase def setup super + Gem::Specification.reset @cmd = Gem::Commands::WhichCommand.new end @@ -28,6 +29,8 @@ class TestGemCommandsWhichCommand < Gem::TestCase end def test_execute_one_missing + # TODO: this test fails in isolation + util_foo_bar @cmd.handle_options %w[foo_bar missing] @@ -37,7 +40,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase end assert_equal "#{@foo_bar.full_gem_path}/lib/foo_bar.rb\n", @ui.output - assert_match %r%Can't find ruby library file or shared library missing\n%, + assert_match %r%Can.t find ruby library file or shared library missing\n%, @ui.error end @@ -51,7 +54,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase end assert_equal '', @ui.output - assert_match %r%Can't find ruby library file or shared library missing\n%, + assert_match %r%Can.t find ruby library file or shared library missing\n%, @ui.error end @@ -62,8 +65,8 @@ class TestGemCommandsWhichCommand < Gem::TestCase end files.each do |file| - filename = @foo_bar.full_gem_path + "/#{file}" - FileUtils.mkdir_p File.dirname(filename) + filename = File.join(@foo_bar.full_gem_path, file) + FileUtils.mkdir_p File.dirname filename FileUtils.touch filename end end diff --git a/test/rubygems/test_gem_dependency.rb b/test/rubygems/test_gem_dependency.rb index b4a21b896c..a77ddf5e2d 100644 --- a/test/rubygems/test_gem_dependency.rb +++ b/test/rubygems/test_gem_dependency.rb @@ -67,16 +67,20 @@ class TestGemDependency < Gem::TestCase assert_match d, d, "match self" assert_match dep("a", ">= 0"), d, "match version exact" assert_match dep("a", ">= 0"), dep("a", "1"), "match version" - assert_match dep(/a/, ">= 0"), d, "match simple regexp" - assert_match dep(/a|b/, ">= 0"), d, "match scary regexp" - - refute_match dep(/a/), dep("b") refute_match dep("a"), Object.new + + Deprecate.skip_during do + assert_match dep(/a/, ">= 0"), d, "match simple regexp" + assert_match dep(/a|b/, ">= 0"), d, "match scary regexp" + refute_match dep(/a/), dep("b") + end end def test_equals_tilde_escape refute_match dep("a|b"), dep("a", "1") - assert_match dep(/a|b/), dep("a", "1") + Deprecate.skip_during do + assert_match dep(/a|b/), dep("a", "1") + end end def test_equals_tilde_object @@ -90,9 +94,11 @@ class TestGemDependency < Gem::TestCase def test_equals_tilde_spec assert_match dep("a", ">= 0"), spec("a", "0") assert_match dep("a", "1"), spec("a", "1") - assert_match dep(/a/, ">= 0"), spec("a", "0") - assert_match dep(/a|b/, ">= 0"), spec("b", "0") - refute_match dep(/a/, ">= 0"), spec("b", "0") + Deprecate.skip_during do + assert_match dep(/a/, ">= 0"), spec("a", "0") + assert_match dep(/a|b/, ">= 0"), spec("b", "0") + refute_match dep(/a/, ">= 0"), spec("b", "0") + end end def test_hash @@ -166,5 +172,12 @@ class TestGemDependency < Gem::TestCase assert d.prerelease? end + + def test_specific + refute dep('a', '> 1').specific? + + assert dep('a', '= 1').specific? + end + end diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb index 5cf79d3c59..48d85b8ed4 100644 --- a/test/rubygems/test_gem_dependency_installer.rb +++ b/test/rubygems/test_gem_dependency_installer.rb @@ -14,10 +14,14 @@ class TestGemDependencyInstaller < Gem::TestCase super @gems_dir = File.join @tempdir, 'gems' - @cache_dir = Gem.cache_dir(@gemhome) + @cache_dir = File.join @gemhome, 'cache' FileUtils.mkdir @gems_dir + Gem::RemoteFetcher.fetcher = @fetcher = Gem::FakeFetcher.new + end + + def util_setup_gems @a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end @a1_pre, @a1_pre_gem = util_gem 'a', '1.a' @b1, @b1_gem = util_gem 'b', '1' do |s| @@ -25,12 +29,13 @@ class TestGemDependencyInstaller < Gem::TestCase s.add_development_dependency 'aa' end - Gem::RemoteFetcher.fetcher = @fetcher = Gem::FakeFetcher.new - + util_clear_gems util_reset_gems end def test_install + util_setup_gems + FileUtils.mv @a1_gem, @tempdir inst = nil @@ -39,13 +44,13 @@ class TestGemDependencyInstaller < Gem::TestCase inst.install 'a' end - assert_equal Gem::SourceIndex.new(@a1.full_name => @a1), - Gem::SourceIndex.from_installed_gems - + assert_equal %w[a-1], Gem::Specification.map(&:full_name) assert_equal [@a1], inst.installed_gems end def test_install_all_dependencies + util_setup_gems + _, e1_gem = util_gem 'e', '1' do |s| s.add_dependency 'b' end @@ -71,6 +76,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_cache_dir + util_setup_gems + FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir inst = nil @@ -82,15 +89,18 @@ class TestGemDependencyInstaller < Gem::TestCase assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name } - assert Gem.cache_gem(@a1.file_name, @gemhome) - assert Gem.cache_gem(@b1.file_name, @gemhome) + assert File.exist? File.join(@gemhome, "cache", @a1.file_name) + assert File.exist? File.join(@gemhome, "cache", @b1.file_name) end def test_install_dependencies_satisfied + util_setup_gems + a2, a2_gem = util_gem 'a', '2' FileUtils.rm_rf File.join(@gemhome, 'gems') - Gem.source_index.refresh! + + Gem::Specification.reset FileUtils.mv @a1_gem, @tempdir FileUtils.mv a2_gem, @tempdir # not in index @@ -109,14 +119,13 @@ class TestGemDependencyInstaller < Gem::TestCase inst.install 'b' end - installed = Gem::SourceIndex.from_installed_gems.map { |n,s| s.full_name } - - assert_equal %w[a-2 b-1], installed.sort - + assert_equal %w[a-2 b-1], Gem::Specification.map(&:full_name) assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name } end def test_install_dependency + util_setup_gems + FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir inst = nil @@ -130,6 +139,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_dependency_development + util_setup_gems + @aa1, @aa1_gem = util_gem 'aa', '1' util_reset_gems @@ -148,6 +159,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_dependency_existing + util_setup_gems + Gem::Installer.new(@a1_gem).install FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -180,6 +193,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_local + util_setup_gems + FileUtils.mv @a1_gem, @tempdir inst = nil @@ -192,6 +207,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_local_dependency + util_setup_gems + FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -206,6 +223,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_local_dependency_installed + util_setup_gems + FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -222,6 +241,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_local_subdir + util_setup_gems + inst = nil Dir.chdir @tempdir do @@ -233,11 +254,13 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_env_shebang + util_setup_gems + FileUtils.mv @a1_gem, @tempdir inst = nil Dir.chdir @tempdir do - inst = Gem::DependencyInstaller.new :env_shebang => true, :wrappers => true + inst = Gem::DependencyInstaller.new :env_shebang => true, :wrappers => true, :format_executable => false inst.install 'a' end @@ -248,6 +271,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_force + util_setup_gems + FileUtils.mv @b1_gem, @tempdir si = util_setup_spec_fetcher @b1 @fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml @@ -262,6 +287,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_ignore_dependencies + util_setup_gems + FileUtils.mv @b1_gem, @tempdir inst = nil @@ -274,6 +301,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_install_dir + util_setup_gems + FileUtils.mv @a1_gem, @tempdir gemhome2 = File.join @tempdir, 'gemhome2' Dir.mkdir gemhome2 @@ -287,10 +316,12 @@ class TestGemDependencyInstaller < Gem::TestCase assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name } assert File.exist?(File.join(gemhome2, 'specifications', @a1.spec_name)) - assert File.exist?(Gem.cache_gem(@a1.file_name, gemhome2)) + assert File.exist?(File.join(gemhome2, 'cache', @a1.file_name)) end def test_install_domain_both + util_setup_gems + a1_data = nil File.open @a1_gem, 'rb' do |fp| a1_data = fp.read @@ -309,14 +340,13 @@ class TestGemDependencyInstaller < Gem::TestCase assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name } a1, b1 = inst.installed_gems - a1_expected = File.join(@gemhome, 'specifications', a1.spec_name) - b1_expected = File.join(@gemhome, 'specifications', b1.spec_name) - - assert_equal a1_expected, a1.loaded_from - assert_equal b1_expected, b1.loaded_from + assert_equal a1.spec_file, a1.loaded_from + assert_equal b1.spec_file, b1.loaded_from end def test_install_domain_both_no_network + util_setup_gems + @fetcher.data["http://gems.example.com/gems/Marshal.#{@marshal_version}"] = proc do raise Gem::RemoteFetcher::FetchError @@ -335,12 +365,11 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_domain_local + util_setup_gems + FileUtils.mv @b1_gem, @tempdir inst = nil - Gem.source_index.remove_spec @a1.full_name - Gem.source_index.remove_spec @a1_pre.full_name - Dir.chdir @tempdir do e = assert_raises Gem::DependencyError do inst = Gem::DependencyInstaller.new :domain => :local @@ -355,6 +384,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_domain_remote + util_setup_gems + a1_data = nil File.open @a1_gem, 'rb' do |fp| a1_data = fp.read @@ -369,6 +400,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_dual_repository + util_setup_gems + FileUtils.mv @a1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir inst = nil @@ -393,6 +426,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_reinstall + util_setup_gems + Gem::Installer.new(@a1_gem).install FileUtils.mv @a1_gem, @tempdir inst = nil @@ -402,13 +437,13 @@ class TestGemDependencyInstaller < Gem::TestCase inst.install 'a' end - assert_equal Gem::SourceIndex.new(@a1.full_name => @a1), - Gem::SourceIndex.from_installed_gems - - assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name } + assert_equal %w[a-1], Gem::Specification.map(&:full_name) + assert_equal %w[a-1], inst.installed_gems.map(&:full_name) end def test_install_remote + util_setup_gems + a1_data = nil File.open @a1_gem, 'rb' do |fp| a1_data = fp.read @@ -426,6 +461,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_remote_dep + util_setup_gems + a1_data = nil File.open @a1_gem, 'rb' do |fp| a1_data = fp.read @@ -444,6 +481,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_install_remote_platform_newer + util_setup_gems + a2_o, a2_o_gem = util_gem 'a', '2' do |s| s.platform = Gem::Platform.new %w[cpu other_platform 1] end @@ -473,6 +512,8 @@ class TestGemDependencyInstaller < Gem::TestCase if defined? OpenSSL then def test_install_security_policy + util_setup_gems + data = File.open(@a1_gem, 'rb') { |f| f.read } @fetcher.data['http://gems.example.com/gems/a-1.gem'] = data @@ -495,9 +536,11 @@ class TestGemDependencyInstaller < Gem::TestCase # Wrappers don't work on mswin unless win_platform? then def test_install_no_wrappers + util_setup_gems + @fetcher.data['http://gems.example.com/gems/a-1.gem'] = read_binary(@a1_gem) - inst = Gem::DependencyInstaller.new :wrappers => false + inst = Gem::DependencyInstaller.new :wrappers => false, :format_executable => false inst.install 'a' refute_match(%r|This file was generated by RubyGems.|, @@ -537,14 +580,19 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_find_gems_gems_with_sources + util_setup_gems + inst = Gem::DependencyInstaller.new dep = Gem::Dependency.new 'b', '>= 0' - assert_equal [[@b1, @gem_repo]], - inst.find_gems_with_sources(dep) + Gem::Specification.reset + + assert_equal [[@b1, @gem_repo]], inst.find_gems_with_sources(dep) end def test_find_gems_with_sources_local + util_setup_gems + FileUtils.mv @a1_gem, @tempdir inst = Gem::DependencyInstaller.new dep = Gem::Dependency.new 'a', '>= 0' @@ -566,6 +614,8 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_find_gems_with_sources_prerelease + util_setup_gems + installer = Gem::DependencyInstaller.new dependency = Gem::Dependency.new('a', Gem::Requirement.default) @@ -586,8 +636,8 @@ class TestGemDependencyInstaller < Gem::TestCase def assert_resolve expected, *specs util_clear_gems - util_setup_spec_fetcher(*specs) + Gem::Specification.reset inst = Gem::DependencyInstaller.new inst.find_spec_by_name_and_version specs.first.name @@ -601,6 +651,7 @@ class TestGemDependencyInstaller < Gem::TestCase util_clear_gems util_setup_spec_fetcher(*specs) + Gem::Specification.reset spec = specs.first @@ -613,6 +664,9 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_gather_dependencies + util_setup_gems + util_reset_gems + inst = Gem::DependencyInstaller.new inst.find_spec_by_name_and_version 'b' inst.gather_dependencies @@ -725,6 +779,7 @@ class TestGemDependencyInstaller < Gem::TestCase end def test_gather_dependencies_prerelease + util_setup_gems util_setup_c1_pre assert_resolve_pre %w[a-1.a b-1 c-1.a], @c1_pre, @a1_pre, @b1 @@ -782,6 +837,9 @@ class TestGemDependencyInstaller < Gem::TestCase end def util_reset_gems + @a1 ||= nil + @b1 ||= nil + @a1_pre ||= nil @c1_pre ||= nil @d1 ||= nil @d2 ||= nil diff --git a/test/rubygems/test_gem_dependency_list.rb b/test/rubygems/test_gem_dependency_list.rb index 4201a31cdd..348f111391 100644 --- a/test/rubygems/test_gem_dependency_list.rb +++ b/test/rubygems/test_gem_dependency_list.rb @@ -12,8 +12,11 @@ class TestGemDependencyList < Gem::TestCase def setup super + util_clear_gems + @deplist = Gem::DependencyList.new + # TODO: switch to new_spec @a1 = quick_spec 'a', '1' @a2 = quick_spec 'a', '2' @a3 = quick_spec 'a', '3' @@ -28,13 +31,10 @@ class TestGemDependencyList < Gem::TestCase end def test_self_from_source_index - hash = { - 'a-1' => @a1, - 'b-2' => @b2, - } + util_clear_gems + install_specs @a1, @b2 - si = Gem::SourceIndex.new hash - deps = Gem::DependencyList.from_source_index si + deps = Deprecate.skip_during { Gem::DependencyList.from_source_index } assert_equal %w[b-2 a-1], deps.dependency_order.map { |s| s.full_name } end diff --git a/test/rubygems/test_gem_doc_manager.rb b/test/rubygems/test_gem_doc_manager.rb index f52f1f87f1..f7ab6416c0 100644 --- a/test/rubygems/test_gem_doc_manager.rb +++ b/test/rubygems/test_gem_doc_manager.rb @@ -17,21 +17,21 @@ class TestGemDocManager < Gem::TestCase end def test_uninstall_doc_unwritable - path = @spec.installation_path + path = @spec.base_dir orig_mode = File.stat(path).mode # File.chmod has no effect on MS Windows directories (it needs ACL). if win_platform? skip("test_uninstall_doc_unwritable skipped on MS Windows") else - File.chmod 0000, path + FileUtils.chmod 0000, path end assert_raises Gem::FilePermissionError do @manager.uninstall_doc end ensure - File.chmod orig_mode, path + FileUtils.chmod orig_mode, path end end diff --git a/test/rubygems/test_gem_format.rb b/test/rubygems/test_gem_format.rb index 6f169588eb..85fb521c67 100644 --- a/test/rubygems/test_gem_format.rb +++ b/test/rubygems/test_gem_format.rb @@ -20,7 +20,7 @@ class TestGemFormat < Gem::Package::TarTestCase def test_class_from_file_by_path util_make_gems - gems = Dir[Gem.cache_gem('*.gem', @gemhome)] + gems = Dir[File.join(@gemhome, "cache", "*.gem")] names = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].map do |spec| spec.original_name diff --git a/test/rubygems/test_gem_gem_path_searcher.rb b/test/rubygems/test_gem_gem_path_searcher.rb index cb4516eaca..c7f5af777c 100644 --- a/test/rubygems/test_gem_gem_path_searcher.rb +++ b/test/rubygems/test_gem_gem_path_searcher.rb @@ -13,72 +13,88 @@ class Gem::GemPathSearcher end class TestGemGemPathSearcher < Gem::TestCase - def setup super - @foo1 = quick_gem 'foo', '0.1' do |s| - s.require_paths << 'lib2' - s.files << 'lib/foo.rb' - end - + @foo1 = new_spec 'foo', '0.1', nil, "lib/foo.rb" + @foo1.require_paths << 'lib2' path = File.join 'gems', @foo1.full_name, 'lib', 'foo.rb' write_file(path) { |fp| fp.puts "# #{path}" } - @foo2 = quick_gem 'foo', '0.2' - @bar1 = quick_gem 'bar', '0.1' - @bar2 = quick_gem 'bar', '0.2' - @nrp = quick_gem 'nil_require_paths', '0.1' - @nrp.require_paths = nil + @foo2 = new_spec 'foo', '0.2' + @bar1 = new_spec 'bar', '0.1' + @bar2 = new_spec 'bar', '0.2' + @nrp = new_spec 'nil_require_paths', '0.1' do |s| + s.require_paths = nil + end + util_setup_fake_fetcher + Gem::Specification.reset + util_setup_spec_fetcher @foo1, @foo2, @bar1, @bar2 @fetcher = Gem::FakeFetcher.new Gem::RemoteFetcher.fetcher = @fetcher - Gem.source_index = util_setup_spec_fetcher @foo1, @foo2, @bar1, @bar2 - - @gps = Gem::GemPathSearcher.new + @gps = Deprecate.skip_during { Gem::GemPathSearcher.new } end def test_find - assert_equal @foo1, @gps.find('foo') + Deprecate.skip_during do + assert_equal @foo1, @gps.find('foo') + end end def test_find_all - assert_equal [@foo1], @gps.find_all('foo') + Deprecate.skip_during do + assert_equal [@foo1], @gps.find_all('foo') + end end def test_init_gemspecs - assert_equal [@bar2, @bar1, @foo2, @foo1], @gps.init_gemspecs + Deprecate.skip_during do + util_clear_gems + util_setup_spec_fetcher @foo1, @foo2, @bar1, @bar2 + expected = [@bar2, @bar1, @foo2, @foo1].map(&:full_name) + actual = @gps.init_gemspecs.map(&:full_name) + assert_equal expected, actual + end end def test_lib_dirs_for - lib_dirs = @gps.lib_dirs_for(@foo1) - expected = File.join @gemhome, 'gems', @foo1.full_name, '{lib,lib2}' + Deprecate.skip_during do + lib_dirs = @gps.lib_dirs_for(@foo1) + expected = File.join @gemhome, 'gems', @foo1.full_name, '{lib,lib2}' - assert_equal expected, lib_dirs + assert_equal expected, lib_dirs + end end def test_lib_dirs_for_nil_require_paths - assert_nil @gps.lib_dirs_for(@nrp) + Deprecate.skip_during do + assert_nil @gps.lib_dirs_for(@nrp) + end end def test_matching_file_eh - refute @gps.matching_file?(@foo1, 'bar') - assert @gps.matching_file?(@foo1, 'foo') + Deprecate.skip_during do + refute @gps.matching_file?(@foo1, 'bar') + assert @gps.matching_file?(@foo1, 'foo') + end end def test_matching_files - assert_equal [], @gps.matching_files(@foo1, 'bar') + Deprecate.skip_during do + assert_equal [], @gps.matching_files(@foo1, 'bar') - expected = File.join @foo1.full_gem_path, 'lib', 'foo.rb' + expected = File.join @foo1.full_gem_path, 'lib', 'foo.rb' - assert_equal [expected], @gps.matching_files(@foo1, 'foo') + assert_equal [expected], @gps.matching_files(@foo1, 'foo') + end end def test_matching_files_nil_require_paths - assert_empty @gps.matching_files(@nrp, 'foo') + Deprecate.skip_during do + assert_empty @gps.matching_files(@nrp, 'foo') + end end - end - diff --git a/test/rubygems/test_gem_gem_runner.rb b/test/rubygems/test_gem_gem_runner.rb index 177c71507a..3cb841058d 100644 --- a/test/rubygems/test_gem_gem_runner.rb +++ b/test/rubygems/test_gem_gem_runner.rb @@ -39,10 +39,7 @@ class TestGemGemRunner < Gem::TestCase def test_build_args__are_handled Gem.clear_paths - gr = Gem::GemRunner.new - assert_raises(Gem::SystemExitException) do - gr.run(%W[--help -- --build_arg1 --build_arg2]) - end + Gem::GemRunner.new.run(%W[help -- --build_arg1 --build_arg2]) assert_equal %w[--build_arg1 --build_arg2], Gem::Command.build_args end diff --git a/test/rubygems/test_gem_indexer.rb b/test/rubygems/test_gem_indexer.rb index e3c78ecb70..a4f9bd454b 100644 --- a/test/rubygems/test_gem_indexer.rb +++ b/test/rubygems/test_gem_indexer.rb @@ -16,6 +16,7 @@ class TestGemIndexer < Gem::TestCase def setup super + util_clear_gems util_make_gems @d2_0 = quick_spec 'd', '2.0' do |s| @@ -33,11 +34,12 @@ class TestGemIndexer < Gem::TestCase gems = File.join(@tempdir, 'gems') FileUtils.mkdir_p gems - FileUtils.mv Dir[Gem.cache_gem('*.gem', @gemhome)], gems + FileUtils.mv Dir[File.join(@gemhome, "cache", '*.gem')], gems - @indexer = Gem::Indexer.new @tempdir, :rss_title => 'ExampleForge gems', - :rss_host => 'example.com', - :rss_gems_host => 'gems.example.com' + @indexer = Gem::Indexer.new(@tempdir, + :rss_title => 'ExampleForge gems', + :rss_host => 'example.com', + :rss_gems_host => 'gems.example.com') end def test_initialize @@ -61,36 +63,37 @@ class TestGemIndexer < Gem::TestCase end def test_build_indicies - spec = quick_spec 'd', '2.0' - spec.instance_variable_set :@original_platform, '' - @indexer.make_temp_directories - index = Gem::SourceIndex.new - index.add_spec spec - use_ui @ui do - @indexer.build_indicies index + @indexer.build_indicies end specs_path = File.join @indexer.directory, "specs.#{@marshal_version}" specs_dump = Gem.read_binary specs_path specs = Marshal.load specs_dump - expected = [ - ['d', Gem::Version.new('2.0'), 'ruby'], - ] + expected = [["a", Gem::Version.new("1"), "ruby"], + ["a", Gem::Version.new("2"), "ruby"], + ["a_evil", Gem::Version.new("9"), "ruby"], + ["b", Gem::Version.new("2"), "ruby"], + ["c", Gem::Version.new("1.2"), "ruby"], + ["d", Gem::Version.new("2.0"), "ruby"], + ["pl", Gem::Version.new("1"), "i386-linux"]] - assert_equal expected, specs, 'specs' + assert_equal expected, specs - latest_specs_path = File.join @indexer.directory, - "latest_specs.#{@marshal_version}" + latest_specs_path = File.join(@indexer.directory, + "latest_specs.#{@marshal_version}") latest_specs_dump = Gem.read_binary latest_specs_path latest_specs = Marshal.load latest_specs_dump - expected = [ - ['d', Gem::Version.new('2.0'), 'ruby'], - ] + expected = [["a", Gem::Version.new("2"), "ruby"], + ["a_evil", Gem::Version.new("9"), "ruby"], + ["b", Gem::Version.new("2"), "ruby"], + ["c", Gem::Version.new("1.2"), "ruby"], + ["d", Gem::Version.new("2.0"), "ruby"], + ["pl", Gem::Version.new("1"), "i386-linux"]] assert_equal expected, latest_specs, 'latest_specs' end @@ -109,10 +112,10 @@ class TestGemIndexer < Gem::TestCase assert File.directory?(quickdir) assert File.directory?(marshal_quickdir) - assert_indexed marshal_quickdir, "#{@a1.spec_name}.rz" - assert_indexed marshal_quickdir, "#{@a2.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz" - refute_indexed marshal_quickdir, @c1_2.spec_name + refute_indexed marshal_quickdir, File.basename(@c1_2.spec_file) assert_indexed @tempdir, "specs.#{@marshal_version}" assert_indexed @tempdir, "specs.#{@marshal_version}.gz" @@ -230,12 +233,12 @@ class TestGemIndexer < Gem::TestCase <pre>This line is really, really long. So long, in fact, that it is more than eighty characters long! The purpose of this line is for testing wrapping -behavior because sometimes people don't wrap their text to eighty characters. +behavior because sometimes people don't wrap their text to eighty characters. Without the wrapping, the text might not look good in the RSS feed. Also, a list: * An entry that's actually kind of sort - * an entry that's really long, which will probably get wrapped funny. + * an entry that's really long, which will probably get wrapped funny. That's ok, somebody wasn't thinking straight when they made it more than eighty characters.</pre> @@ -272,10 +275,10 @@ eighty characters.</pre> assert File.directory?(quickdir) assert File.directory?(marshal_quickdir) - assert_indexed marshal_quickdir, "#{@a1.spec_name}.rz" - assert_indexed marshal_quickdir, "#{@a2.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz" - refute_indexed marshal_quickdir, "#{@c1_2.spec_name}" + refute_indexed marshal_quickdir, "#{File.basename(@c1_2.spec_file)}" refute_indexed @tempdir, "specs.#{@marshal_version}" refute_indexed @tempdir, "specs.#{@marshal_version}.gz" @@ -308,8 +311,8 @@ eighty characters.</pre> assert File.directory?(marshal_quickdir) - assert_indexed marshal_quickdir, "#{@a1.spec_name}.rz" - assert_indexed marshal_quickdir, "#{@a2.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz" assert_indexed @tempdir, "specs.#{@marshal_version}" assert_indexed @tempdir, "specs.#{@marshal_version}.gz" @@ -343,19 +346,19 @@ eighty characters.</pre> refute_indexed quickdir, "latest_index" refute_indexed quickdir, "latest_index.rz" - refute_indexed quickdir, "#{@a1.spec_name}.rz" - refute_indexed quickdir, "#{@a2.spec_name}.rz" - refute_indexed quickdir, "#{@b2.spec_name}.rz" - refute_indexed quickdir, "#{@c1_2.spec_name}.rz" + refute_indexed quickdir, "#{File.basename(@a1.spec_file)}.rz" + refute_indexed quickdir, "#{File.basename(@a2.spec_file)}.rz" + refute_indexed quickdir, "#{File.basename(@b2.spec_file)}.rz" + refute_indexed quickdir, "#{File.basename(@c1_2.spec_file)}.rz" refute_indexed quickdir, "#{@pl1.original_name}.gemspec.rz" - refute_indexed quickdir, "#{@pl1.spec_name}.rz" + refute_indexed quickdir, "#{File.basename(@pl1.spec_file)}.rz" - assert_indexed marshal_quickdir, "#{@a1.spec_name}.rz" - assert_indexed marshal_quickdir, "#{@a2.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz" - refute_indexed quickdir, "#{@c1_2.spec_name}" - refute_indexed marshal_quickdir, "#{@c1_2.spec_name}" + refute_indexed quickdir, "#{File.basename(@c1_2.spec_file)}" + refute_indexed marshal_quickdir, "#{File.basename(@c1_2.spec_file)}" assert_indexed @tempdir, "specs.#{@marshal_version}" assert_indexed @tempdir, "specs.#{@marshal_version}.gz" @@ -389,8 +392,8 @@ eighty characters.</pre> assert File.directory?(quickdir) assert File.directory?(marshal_quickdir) - assert_indexed marshal_quickdir, "#{@a1.spec_name}.rz" - assert_indexed marshal_quickdir, "#{@a2.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz" assert_indexed @tempdir, "specs.#{@marshal_version}" assert_indexed @tempdir, "specs.#{@marshal_version}.gz" @@ -404,10 +407,7 @@ eighty characters.</pre> @indexer.generate_index end - assert_match %r%^Loading 10 gems from #{Regexp.escape @tempdir}$%, - @ui.output assert_match %r%^\.\.\.\.\.\.\.\.\.\.$%, @ui.output - assert_match %r%^Loaded all gems$%, @ui.output assert_match %r%^Generating Marshal quick index gemspecs for 10 gems$%, @ui.output assert_match %r%^Complete$%, @ui.output @@ -520,14 +520,15 @@ eighty characters.</pre> @d2_1_a_tuple = [@d2_1_a.name, @d2_1_a.version, @d2_1_a.original_platform] gems = File.join @tempdir, 'gems' - FileUtils.mv Gem.cache_gem(@d2_1.file_name, @gemhome), gems - FileUtils.mv Gem.cache_gem(@d2_1_a.file_name, @gemhome), gems + + FileUtils.mv @d2_1.cache_file, gems + FileUtils.mv @d2_1_a.cache_file, gems use_ui @ui do @indexer.update_index end - assert_indexed marshal_quickdir, "#{@d2_1.spec_name}.rz" + assert_indexed marshal_quickdir, "#{File.basename(@d2_1.spec_file)}.rz" specs_index = Marshal.load Gem.read_binary(@indexer.dest_specs_index) diff --git a/test/rubygems/test_gem_install_update_options.rb b/test/rubygems/test_gem_install_update_options.rb index fe10fd4949..2f0b911604 100644 --- a/test/rubygems/test_gem_install_update_options.rb +++ b/test/rubygems/test_gem_install_update_options.rb @@ -46,9 +46,8 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase @installer = Gem::Installer.new @gem, @cmd.options @installer.install - assert File.exist?(File.join(Gem.user_dir, 'gems')) - assert File.exist?(File.join(Gem.user_dir, 'gems', - @spec.full_name)) + assert_path_exists File.join(Gem.user_dir, 'gems') + assert_path_exists File.join(Gem.user_dir, 'gems', @spec.full_name) end def test_user_install_disabled_read_only @@ -59,11 +58,13 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase refute @cmd.options[:user_install] - File.chmod 0755, @userhome + FileUtils.chmod 0755, @userhome FileUtils.chmod 0000, @gemhome + Gem.use_paths @gemhome, @userhome + assert_raises(Gem::FilePermissionError) do - @installer = Gem::Installer.new @gem, @cmd.options + Gem::Installer.new(@gem, @cmd.options).install end end ensure diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 554865da90..249b195fd7 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -8,6 +8,25 @@ require 'rubygems/installer_test_case' class TestGemInstaller < Gem::InstallerTestCase + def setup + super + + if __name__ !~ /^test_install(_|$)/ then + @gemhome = @installer_tmp + Gem.use_paths @installer_tmp + + @spec = Gem::Specification.find_by_name 'a' + @user_spec = Gem::Specification.find_by_name 'b' + + @installer.spec = @spec + @installer.gem_home = @installer_tmp + @installer.gem_dir = @spec.gem_dir + @user_installer.spec = @user_spec + @user_installer.gem_home = @installer_tmp + end + end + + def test_app_script_text @spec.version = 2 util_make_exec @spec, '' @@ -108,7 +127,7 @@ load Gem.bin_path('a', 'executable', version) def test_extract_files format = Object.new def format.file_entries - [[{'size' => 7, 'mode' => 0400, 'path' => 'thefile'}, 'thefile']] + [[{'size' => 7, 'mode' => 0400, 'path' => 'thefile'}, 'content']] end @installer.format = format @@ -116,7 +135,7 @@ load Gem.bin_path('a', 'executable', version) @installer.extract_files thefile_path = File.join(util_gem_dir, 'thefile') - assert_equal 'thefile', File.read(thefile_path) + assert_equal 'content', File.read(thefile_path) unless Gem.win_platform? then assert_equal 0400, File.stat(thefile_path).mode & 0777 @@ -145,8 +164,9 @@ load Gem.bin_path('a', 'executable', version) @installer.extract_files end - assert_equal "attempt to install file into \"../thefile\" under #{util_gem_dir.inspect}", - e.message + dir = util_gem_dir + expected = "attempt to install file into \"../thefile\" under #{dir}" + assert_equal expected, e.message assert_equal false, File.file?(File.join(@tempdir, '../thefile')), "You may need to remove this file if you broke the test once" end @@ -163,7 +183,7 @@ load Gem.bin_path('a', 'executable', version) @installer.extract_files end - assert_equal 'attempt to install file into "/thefile"', e.message + assert_equal 'attempt to install file into /thefile', e.message assert_equal false, File.file?(File.join('/thefile')), "You may need to remove this file if you broke the test once" end @@ -241,7 +261,7 @@ load Gem.bin_path('a', 'executable', version) @installer.wrappers = true @spec.executables = %w[executable] - gem_dir = File.join "#{@gemhome}2", 'gems', @spec.full_name + gem_dir = File.join("#{@gemhome}2", "gems", @spec.full_name) gem_bindir = File.join gem_dir, 'bin' FileUtils.mkdir_p gem_bindir File.open File.join(gem_bindir, 'executable'), 'w' do |f| @@ -253,7 +273,7 @@ load Gem.bin_path('a', 'executable', version) @installer.generate_bin - installed_exec = File.join("#{@gemhome}2", 'bin', 'executable') + installed_exec = File.join("#{@gemhome}2", "bin", 'executable') assert_equal true, File.exist?(installed_exec) assert_equal mask, File.stat(installed_exec).mode unless win_platform? @@ -279,14 +299,14 @@ load Gem.bin_path('a', 'executable', version) if win_platform? skip('test_generate_bin_script_no_perms skipped on MS Windows') else - File.chmod 0000, util_inst_bindir + FileUtils.chmod 0000, util_inst_bindir assert_raises Gem::FilePermissionError do @installer.generate_bin end end ensure - File.chmod 0700, util_inst_bindir unless $DEBUG + FileUtils.chmod 0755, util_inst_bindir unless ($DEBUG or win_platform?) end def test_generate_bin_script_no_shebang @@ -346,7 +366,7 @@ load Gem.bin_path('a', 'executable', version) @installer.generate_bin assert_equal true, File.directory?(util_inst_bindir) - installed_exec = File.join(util_inst_bindir, 'executable') + installed_exec = File.join util_inst_bindir, 'executable' assert_equal true, File.symlink?(installed_exec) assert_equal(File.join(util_gem_dir, 'bin', 'executable'), File.readlink(installed_exec)) @@ -371,14 +391,14 @@ load Gem.bin_path('a', 'executable', version) if win_platform? skip('test_generate_bin_symlink_no_perms skipped on MS Windows') else - File.chmod 0000, util_inst_bindir + FileUtils.chmod 0000, util_inst_bindir assert_raises Gem::FilePermissionError do @installer.generate_bin end end ensure - File.chmod 0700, util_inst_bindir unless $DEBUG + FileUtils.chmod 0755, util_inst_bindir unless ($DEBUG or win_platform?) end def test_generate_bin_symlink_update_newer @@ -404,10 +424,10 @@ load Gem.bin_path('a', 'executable', version) @spec.version = 3 util_make_exec - @installer.gem_dir = File.join util_gem_dir @spec + @installer.gem_dir = util_gem_dir @spec @installer.generate_bin installed_exec = File.join(util_inst_bindir, 'executable') - assert_equal(File.join(util_gem_bindir(@spec), 'executable'), + assert_equal(@spec.bin_file('executable'), File.readlink(installed_exec), "Ensure symlink moved to latest version") end @@ -441,8 +461,9 @@ load Gem.bin_path('a', 'executable', version) @installer.generate_bin - installed_exec = File.join(util_inst_bindir, 'executable') - assert_equal(File.join(util_gem_dir, 'bin', 'executable'), + installed_exec = File.join util_inst_bindir, 'executable' + expected = File.join util_gem_dir, 'bin', 'executable' + assert_equal(expected, File.readlink(installed_exec), "Ensure symlink not moved") end @@ -455,7 +476,7 @@ load Gem.bin_path('a', 'executable', version) @installer.gem_dir = util_gem_dir @installer.generate_bin - installed_exec = File.join(util_inst_bindir, 'executable') + installed_exec = File.join util_inst_bindir, 'executable' assert_equal true, File.exist?(installed_exec) @spec = Gem::Specification.new do |s| @@ -522,7 +543,7 @@ load Gem.bin_path('a', 'executable', version) Dir.mkdir util_inst_bindir util_build_gem spec - FileUtils.mv Gem.cache_gem(spec.file_name, @gemhome), @tempdir + FileUtils.mv spec.cache_file, @tempdir installer = Gem::Installer.new gem @@ -535,7 +556,7 @@ load Gem.bin_path('a', 'executable', version) util_clear_gems gemdir = File.join @gemhome, 'gems', @spec.full_name - cache_file = Gem.cache_gem(@spec.file_name, @gemhome) + cache_file = File.join @gemhome, 'cache', @spec.file_name stub_exe = File.join @gemhome, 'bin', 'executable' rakefile = File.join gemdir, 'ext', 'a', 'Rakefile' @@ -555,12 +576,14 @@ load Gem.bin_path('a', 'executable', version) assert File.exist?(cache_file), 'cache file must exist' end + @newspec = nil build_rake_in do use_ui @ui do - assert_equal @spec, @installer.install + @newspec = @installer.install end end + assert_equal @spec, @newspec assert File.exist? gemdir assert File.exist?(stub_exe), 'gem executable must exist' @@ -576,7 +599,7 @@ load Gem.bin_path('a', 'executable', version) spec_file = File.join(@gemhome, 'specifications', @spec.spec_name) - assert_equal spec_file, @spec.loaded_from + assert_equal spec_file, @newspec.loaded_from assert File.exist?(spec_file) assert_same @installer, @post_build_hook_arg @@ -656,17 +679,17 @@ load Gem.bin_path('a', 'executable', version) gemhome2 = "#{@gemhome}2" @spec.add_dependency 'b' - b2 = quick_spec 'b', 2 + quick_gem 'b', 2 FileUtils.mv @gemhome, gemhome2 - Gem.source_index.gems.delete b2.full_name - source_index = Gem::SourceIndex.from_gems_in File.join(gemhome2, - 'specifications') + + Gem::Specification.dirs = [gemhome2] # TODO: switch all dirs= to use_paths util_setup_gem - @installer = Gem::Installer.new @gem, :install_dir => gemhome2, - :source_index => source_index + @installer = Gem::Installer.new @gem, :install_dir => gemhome2 + + gem_home = Gem.dir build_rake_in do use_ui @ui do @@ -675,6 +698,7 @@ load Gem.bin_path('a', 'executable', version) end assert File.exist?(File.join(gemhome2, 'gems', @spec.full_name)) + assert_equal gem_home, Gem.dir end def test_install_force @@ -712,7 +736,7 @@ load Gem.bin_path('a', 'executable', version) end def test_install_missing_dirs - FileUtils.rm_f Gem.cache_dir + FileUtils.rm_f File.join(Gem.dir, 'cache') FileUtils.rm_f File.join(Gem.dir, 'docs') FileUtils.rm_f File.join(Gem.dir, 'specifications') @@ -722,11 +746,11 @@ load Gem.bin_path('a', 'executable', version) @installer.install end - File.directory? Gem.cache_dir + File.directory? File.join(Gem.dir, 'cache') File.directory? File.join(Gem.dir, 'docs') File.directory? File.join(Gem.dir, 'specifications') - assert File.exist?(Gem.cache_gem(@spec.file_name, @gemhome)) + assert File.exist?(File.join(@gemhome, 'cache', @spec.file_name)) assert File.exist?(File.join(@gemhome, 'specifications', @spec.spec_name)) end @@ -812,8 +836,9 @@ load Gem.bin_path('a', 'executable', version) @spec.post_install_message = 'I am a shiny gem!' use_ui @ui do - Dir.chdir @tempdir do Gem::Builder.new(@spec).build end + path = Gem::Builder.new(@spec).build + @installer = Gem::Installer.new path @installer.install end @@ -838,7 +863,7 @@ load Gem.bin_path('a', 'executable', version) util_build_gem spec - gem = Gem.cache_gem(spec.file_name, @gemhome) + gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.new gem @@ -1002,6 +1027,10 @@ load Gem.bin_path('a', 'executable', version) assert_equal @spec, eval(File.read(spec_file)) end + def test_dir + assert_match @installer.dir, %r!/installer/gems/a-2$! + end + def old_ruby_required spec = quick_spec 'old_ruby_required', '1' do |s| s.required_ruby_version = '= 1.4.6' @@ -1009,20 +1038,17 @@ load Gem.bin_path('a', 'executable', version) util_build_gem spec - Gem.cache_gem(spec.file_name, @gemhome) + spec.cache_file end def util_execless @spec = quick_spec 'z' + util_build_gem @spec - gem = File.join @tempdir, @spec.file_name - - @installer = util_installer @spec, gem, @gemhome + @installer = util_installer @spec, @gemhome end def mask 0100755 & (~File.umask) end - end - diff --git a/test/rubygems/test_gem_package_tar_output.rb b/test/rubygems/test_gem_package_tar_output.rb index 77f31852f9..01b4a0fa3a 100644 --- a/test/rubygems/test_gem_package_tar_output.rb +++ b/test/rubygems/test_gem_package_tar_output.rb @@ -6,6 +6,7 @@ require 'rubygems/package/tar_test_case' require 'rubygems/package/tar_output' +require 'rubygems/security' class TestGemPackageTarOutput < Gem::Package::TarTestCase diff --git a/test/rubygems/test_gem_path_support.rb b/test/rubygems/test_gem_path_support.rb new file mode 100644 index 0000000000..7fb0ccacc5 --- /dev/null +++ b/test/rubygems/test_gem_path_support.rb @@ -0,0 +1,64 @@ +###################################################################### +# This file is imported from the rubygems project. +# DO NOT make modifications in this repo. They _will_ be reverted! +# File a patch instead and assign it to Ryan Davis or Eric Hodel. +###################################################################### + +require 'rubygems/test_case' +require 'rubygems' +require 'fileutils' + +class TestGemPathSupport < Gem::TestCase + def setup + super + + ENV["GEM_HOME"] = @tempdir + ENV["GEM_PATH"] = [@tempdir, "something"].join(File::PATH_SEPARATOR) + end + + def test_initialize + ps = Gem::PathSupport.new + + assert_equal ENV["GEM_HOME"], ps.home + + expected = util_path + assert_equal expected, ps.path, "defaults to GEM_PATH" + end + + def test_initialize_home + ps = Gem::PathSupport.new "GEM_HOME" => "#{@tempdir}/foo" + + assert_equal File.join(@tempdir, "foo"), ps.home + + expected = util_path + [File.join(@tempdir, 'foo')] + assert_equal expected, ps.path + end + + def test_initialize_path + ps = Gem::PathSupport.new "GEM_PATH" => %W[#{@tempdir}/foo #{@tempdir}/bar] + + assert_equal ENV["GEM_HOME"], ps.home + + expected = [ + File.join(@tempdir, 'foo'), + File.join(@tempdir, 'bar'), + ENV["GEM_HOME"], + ] + + assert_equal expected, ps.path + end + + def test_initialize_home_path + ps = Gem::PathSupport.new("GEM_HOME" => "#{@tempdir}/foo", + "GEM_PATH" => %W[#{@tempdir}/foo #{@tempdir}/bar]) + + assert_equal File.join(@tempdir, "foo"), ps.home + + expected = [File.join(@tempdir, 'foo'), File.join(@tempdir, 'bar')] + assert_equal expected, ps.path + end + + def util_path + ENV["GEM_PATH"].split(File::PATH_SEPARATOR) + end +end diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb index 485bab72a2..f46a20fb41 100644 --- a/test/rubygems/test_gem_platform.rb +++ b/test/rubygems/test_gem_platform.rb @@ -144,7 +144,7 @@ class TestGemPlatform < Gem::TestCase def test_empty platform = Gem::Platform.new 'cpu-other_platform1' assert_respond_to platform, :empty? - assert_equal false, platform.empty? + assert_equal false, Deprecate.skip_during { platform.empty? } end def test_to_s diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index 66fb682c6c..e039bb76bd 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -99,7 +99,7 @@ gems: # REFACTOR: copied from test_gem_dependency_installer.rb @gems_dir = File.join @tempdir, 'gems' - @cache_dir = Gem.cache_dir(@gemhome) + @cache_dir = File.join @gemhome, "cache" FileUtils.mkdir @gems_dir # TODO: why does the remote fetcher need it written to disk? @@ -152,7 +152,7 @@ gems: fetcher.fetch_size 'gems.example.com/yaml' end - assert_equal 'uri scheme is invalid', e.message + assert_equal 'uri scheme is invalid: nil', e.message end def test_fetch_size_socket_error @@ -209,7 +209,7 @@ gems: fetcher = util_fuck_with_fetcher a1_data - a1_cache_gem = Gem.cache_gem(@a1.file_name, @gemhome) + a1_cache_gem = @a1.cache_file assert_equal a1_cache_gem, fetcher.download(@a1, 'http://gems.example.com') assert_equal("http://gems.example.com/gems/a-1.gem", fetcher.instance_variable_get(:@test_arg).to_s) @@ -221,8 +221,7 @@ gems: inst = Gem::RemoteFetcher.fetcher - assert_equal Gem.cache_gem(@a1.file_name, @gemhome), - inst.download(@a1, 'http://gems.example.com') + assert_equal @a1.cache_file, inst.download(@a1, 'http://gems.example.com') end def test_download_local @@ -234,8 +233,7 @@ gems: inst = Gem::RemoteFetcher.fetcher end - assert_equal Gem.cache_gem(@a1.file_name, @gemhome), - inst.download(@a1, local_path) + assert_equal @a1.cache_file, inst.download(@a1, local_path) end def test_download_local_space @@ -249,21 +247,19 @@ gems: inst = Gem::RemoteFetcher.fetcher end - assert_equal Gem.cache_gem(@a1.file_name, @gemhome), - inst.download(@a1, local_path) + assert_equal @a1.cache_file, inst.download(@a1, local_path) end def test_download_install_dir - a1_data = nil - File.open @a1_gem, 'rb' do |fp| - a1_data = fp.read + a1_data = File.open @a1_gem, 'rb' do |fp| + fp.read end fetcher = util_fuck_with_fetcher a1_data install_dir = File.join @tempdir, 'more_gems' - a1_cache_gem = Gem.cache_gem(@a1.file_name, install_dir) + a1_cache_gem = File.join install_dir, "cache", @a1.file_name FileUtils.mkdir_p(File.dirname(a1_cache_gem)) actual = fetcher.download(@a1, 'http://gems.example.com', install_dir) @@ -279,7 +275,7 @@ gems: FileUtils.mv @a1_gem, @tempdir local_path = File.join @tempdir, @a1.file_name inst = nil - File.chmod 0555, Gem.cache_dir(@gemhome) + FileUtils.chmod 0555, @a1.cache_dir Dir.chdir @tempdir do inst = Gem::RemoteFetcher.fetcher @@ -288,19 +284,20 @@ gems: assert_equal File.join(@tempdir, @a1.file_name), inst.download(@a1, local_path) ensure - File.chmod 0755, Gem.cache_dir(@gemhome) + FileUtils.chmod 0755, @a1.cache_dir end def test_download_read_only - File.chmod 0555, Gem.cache_dir(@gemhome) - File.chmod 0555, File.join(@gemhome) + FileUtils.chmod 0555, @a1.cache_dir + FileUtils.chmod 0555, @gemhome fetcher = util_fuck_with_fetcher File.read(@a1_gem) fetcher.download(@a1, 'http://gems.example.com') - assert File.exist?(Gem.cache_gem(@a1.file_name, Gem.user_dir)) + a1_cache_gem = File.join Gem.user_dir, "cache", @a1.file_name + assert File.exist? a1_cache_gem ensure - File.chmod 0755, @gemhome - File.chmod 0755, Gem.cache_dir(@gemhome) + FileUtils.chmod 0755, @gemhome + FileUtils.chmod 0755, @a1.cache_dir end end @@ -319,7 +316,7 @@ gems: fetcher = util_fuck_with_fetcher e1_data, :blow_chunks - e1_cache_gem = Gem.cache_gem(e1.file_name, @gemhome) + e1_cache_gem = e1.cache_file assert_equal e1_cache_gem, fetcher.download(e1, 'http://gems.example.com') @@ -337,7 +334,7 @@ gems: inst = Gem::RemoteFetcher.fetcher end - cache_path = Gem.cache_gem(@a1.file_name, @gemhome) + cache_path = @a1.cache_file FileUtils.mv local_path, cache_path gem = Gem::Format.from_file_by_path cache_path @@ -422,7 +419,7 @@ gems: def test_fetch_path_gzip fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime, head = nil) + def fetcher.fetch_http(uri, mtime, head = nil) Gem.gzip 'foo' end @@ -432,7 +429,7 @@ gems: def test_fetch_path_gzip_unmodified fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime, head = nil) + def fetcher.fetch_http(uri, mtime, head = nil) nil end @@ -442,53 +439,59 @@ gems: def test_fetch_path_io_error fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime, head = nil) + def fetcher.fetch_http(*) raise EOFError end + url = 'http://example.com/uri' + e = assert_raises Gem::RemoteFetcher::FetchError do - fetcher.fetch_path 'uri' + fetcher.fetch_path url end - assert_equal 'EOFError: EOFError (uri)', e.message - assert_equal 'uri', e.uri + assert_equal "EOFError: EOFError (#{url})", e.message + assert_equal url, e.uri end def test_fetch_path_socket_error fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime, head = nil) + def fetcher.fetch_http(uri, mtime, head = nil) raise SocketError end + url = 'http://example.com/uri' + e = assert_raises Gem::RemoteFetcher::FetchError do - fetcher.fetch_path 'uri' + fetcher.fetch_path url end - assert_equal 'SocketError: SocketError (uri)', e.message - assert_equal 'uri', e.uri + assert_equal "SocketError: SocketError (#{url})", e.message + assert_equal url, e.uri end def test_fetch_path_system_call_error fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime = nil, head = nil) + def fetcher.fetch_http(uri, mtime = nil, head = nil) raise Errno::ECONNREFUSED, 'connect(2)' end + url = 'http://example.com/uri' + e = assert_raises Gem::RemoteFetcher::FetchError do - fetcher.fetch_path 'uri' + fetcher.fetch_path url end - assert_match %r|ECONNREFUSED:.*connect\(2\) \(uri\)\z|, + assert_match %r|ECONNREFUSED:.*connect\(2\) \(#{Regexp.escape url}\)\z|, e.message - assert_equal 'uri', e.uri + assert_equal url, e.uri end def test_fetch_path_unmodified fetcher = Gem::RemoteFetcher.new nil - def fetcher.open_uri_or_path(uri, mtime, head = nil) + def fetcher.fetch_http(uri, mtime, head = nil) nil end @@ -551,16 +554,18 @@ gems: end end - def test_open_uri_or_path + def test_fetch_http fetcher = Gem::RemoteFetcher.new nil + url = 'http://gems.example.com/redirect' conn = Object.new def conn.started?() true end def conn.request(req) + url = 'http://gems.example.com/redirect' unless defined? @requested then @requested = true res = Net::HTTPMovedPermanently.new nil, 301, nil - res.add_field 'Location', 'http://gems.example.com/real_path' + res.add_field 'Location', url res else res = Net::HTTPOK.new nil, 200, nil @@ -572,19 +577,21 @@ gems: conn = { "#{Thread.current.object_id}:gems.example.com:80" => conn } fetcher.instance_variable_set :@connections, conn - data = fetcher.open_uri_or_path 'http://gems.example.com/redirect' + data = fetcher.fetch_http URI.parse(url) assert_equal 'real_path', data end - def test_open_uri_or_path_limited_redirects + def test_fetch_http_redirects fetcher = Gem::RemoteFetcher.new nil + url = 'http://gems.example.com/redirect' 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', 'http://gems.example.com/redirect' + res.add_field 'Location', url res end @@ -592,11 +599,10 @@ gems: fetcher.instance_variable_set :@connections, conn e = assert_raises Gem::RemoteFetcher::FetchError do - fetcher.open_uri_or_path 'http://gems.example.com/redirect' + fetcher.fetch_http URI.parse(url) end - assert_equal 'too many redirects (http://gems.example.com/redirect)', - e.message + assert_equal "too many redirects (#{url})", e.message end def test_request @@ -631,6 +637,85 @@ gems: 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 use_ui @ui do self.class.enable_yaml = false @@ -753,5 +838,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_requirement.rb b/test/rubygems/test_gem_requirement.rb index c8490de199..b646171673 100644 --- a/test/rubygems/test_gem_requirement.rb +++ b/test/rubygems/test_gem_requirement.rb @@ -256,6 +256,19 @@ class TestGemRequirement < Gem::TestCase refute_satisfied_by "2.0", "~> 1.4.4" end + def test_specific + refute req('> 1') .specific? + refute req('>= 1').specific? + + assert req('!= 1').specific? + assert req('< 1') .specific? + assert req('<= 1').specific? + assert req('= 1') .specific? + assert req('~> 1').specific? + + assert req('> 1', '> 2').specific? # GIGO + end + def test_bad refute_satisfied_by "", "> 0.1" refute_satisfied_by "1.2.3", "!= 1.2.3" diff --git a/test/rubygems/test_gem_server.rb b/test/rubygems/test_gem_server.rb index 3fad8c486e..bd4d960ecc 100644 --- a/test/rubygems/test_gem_server.rb +++ b/test/rubygems/test_gem_server.rb @@ -9,12 +9,10 @@ require 'rubygems/server' require 'stringio' class Gem::Server - attr_accessor :source_index attr_reader :server end class TestGemServer < Gem::TestCase - def setup super @@ -41,52 +39,64 @@ class TestGemServer < Gem::TestCase data = StringIO.new "GET /Marshal.#{Gem.marshal_version} HTTP/1.0\r\n\r\n" @req.parse data - @server.Marshal @req, @res + Deprecate.skip_during do + @server.Marshal @req, @res + end assert_equal 200, @res.status, @res.body assert_match %r| \d\d:\d\d:\d\d |, @res['date'] assert_equal 'application/octet-stream', @res['content-type'] - si = Gem::SourceIndex.new - si.add_specs @a1, @a2 + Deprecate.skip_during do + si = Gem::SourceIndex.new + si.add_specs @a1, @a2 - assert_equal si, Marshal.load(@res.body) + assert_equal si, Marshal.load(@res.body) + end end def test_Marshal_Z data = StringIO.new "GET /Marshal.#{Gem.marshal_version}.Z HTTP/1.0\r\n\r\n" @req.parse data - @server.Marshal @req, @res + Deprecate.skip_during do + @server.Marshal @req, @res + end assert_equal 200, @res.status, @res.body assert_match %r| \d\d:\d\d:\d\d |, @res['date'] assert_equal 'application/x-deflate', @res['content-type'] - si = Gem::SourceIndex.new - si.add_specs @a1, @a2 + Deprecate.skip_during do + si = Gem::SourceIndex.new + si.add_specs @a1, @a2 - assert_equal si, Marshal.load(Gem.inflate(@res.body)) + assert_equal si, Marshal.load(Gem.inflate(@res.body)) + end end def test_latest_specs data = StringIO.new "GET /latest_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n" @req.parse data - @server.latest_specs @req, @res + Deprecate.skip_during do + @server.latest_specs @req, @res + end assert_equal 200, @res.status, @res.body assert_match %r| \d\d:\d\d:\d\d |, @res['date'] assert_equal 'application/octet-stream', @res['content-type'] assert_equal [['a', Gem::Version.new(2), Gem::Platform::RUBY]], - Marshal.load(@res.body) + Marshal.load(@res.body) end def test_latest_specs_gz data = StringIO.new "GET /latest_specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n" @req.parse data - @server.latest_specs @req, @res + Deprecate.skip_during do + @server.latest_specs @req, @res + end assert_equal 200, @res.status, @res.body assert_match %r| \d\d:\d\d:\d\d |, @res['date'] @@ -227,6 +237,4 @@ class TestGemServer < Gem::TestCase @server.instance_variable_set :@server, webrick end - end - diff --git a/test/rubygems/test_gem_silent_ui.rb b/test/rubygems/test_gem_silent_ui.rb index 8005b3b1cc..1968a89b28 100644 --- a/test/rubygems/test_gem_silent_ui.rb +++ b/test/rubygems/test_gem_silent_ui.rb @@ -55,7 +55,7 @@ class TestGemSilentUI < Gem::TestCase assert_empty out, 'No output' assert_empty err, 'No output' - + out, err = capture_io do use_ui @sui do value = @sui.ask_yes_no 'Problem?', true @@ -66,7 +66,7 @@ class TestGemSilentUI < Gem::TestCase assert_empty err, 'No output' assert value, 'Value is true' - + out, err = capture_io do use_ui @sui do value = @sui.ask_yes_no 'Problem?', false diff --git a/test/rubygems/test_gem_source_index.rb b/test/rubygems/test_gem_source_index.rb index 89e2ea3894..462ecbe8fe 100644 --- a/test/rubygems/test_gem_source_index.rb +++ b/test/rubygems/test_gem_source_index.rb @@ -7,397 +7,250 @@ require 'rubygems/test_case' require 'rubygems/source_index' require 'rubygems/config_file' +require 'rubygems/deprecate' class TestGemSourceIndex < Gem::TestCase - def setup super util_setup_fake_fetcher - end - - def test_self_from_gems_in - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.rm_r spec_dir - - FileUtils.mkdir_p spec_dir - - a1 = quick_spec 'a', '1' do |spec| spec.author = 'author 1' end - - spec_file = File.join spec_dir, a1.spec_name - - File.open spec_file, 'w' do |fp| - fp.write a1.to_ruby - end - - si = Gem::SourceIndex.from_gems_in spec_dir - - assert_equal [spec_dir], si.spec_dirs - assert_equal [a1.full_name], si.gems.keys - end - - def test_self_load_specification - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.rm_r spec_dir - - FileUtils.mkdir_p spec_dir - a1 = quick_spec 'a', '1' do |spec| spec.author = 'author 1' end - - spec_file = File.join spec_dir, a1.spec_name - - File.open spec_file, 'w' do |fp| - fp.write a1.to_ruby - end - - spec = Gem::SourceIndex.load_specification spec_file - - assert_equal a1.author, spec.author + @source_index = Deprecate.skip_during { Gem.source_index } end - def test_self_load_specification_utf_8 - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.rm_r spec_dir - - FileUtils.mkdir_p spec_dir - - spec_file = File.join spec_dir, "utf-8.gemspec" - spec_data = <<-SPEC -Gem::Specification.new do |s| - s.name = %q{utf} - s.version = "8" + def test_find_name + Deprecate.skip_during do + assert_equal [@a1, @a2, @a3a], @source_index.find_name('a') + assert_equal [@a2], @source_index.find_name('a', '= 2') + assert_equal [], @source_index.find_name('bogusstring') + assert_equal [], @source_index.find_name('a', '= 3') - s.required_rubygems_version = Gem::Requirement.new(">= 0") - s.authors = ["\317\200"] - s.date = %q{2008-09-10} - s.description = %q{This is a test description} - s.email = %q{example@example.com} - s.has_rdoc = true - s.homepage = %q{http://example.com} - s.require_paths = ["lib"] - s.rubygems_version = %q{1.2.0} - s.summary = %q{this is a summary} + source_index = Gem::SourceIndex.new + source_index.add_spec @a1 + source_index.add_spec @a2 - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 2 + assert_equal [@a1], source_index.find_name(@a1.name, '= 1') - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - else + r1 = Gem::Requirement.create '= 1' + assert_equal [@a1], source_index.find_name(@a1.name, r1) end - else end -end - SPEC - - spec_data.force_encoding 'UTF-8' - - File.open spec_file, 'w' do |io| io.write spec_data end - - spec = Gem::SourceIndex.load_specification spec_file - - pi = "\317\200" - pi.force_encoding 'UTF-8' if pi.respond_to? :force_encoding - - assert_equal pi, spec.author - end if Gem.ruby_version > Gem::Version.new('1.9') - def test_self_load_specification_exception - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.mkdir_p spec_dir - - spec_file = File.join spec_dir, 'a-1.gemspec' - - File.open spec_file, 'w' do |fp| - fp.write 'raise Exception, "epic fail"' - end - - out, err = capture_io do - assert_equal nil, Gem::SourceIndex.load_specification(spec_file) + def test_find_name_empty_cache + Deprecate.skip_during do + empty_source_index = Gem::SourceIndex.new + assert_equal [], empty_source_index.find_name("foo") end - - assert_equal '', out - - expected = "Invalid gemspec in [#{spec_file}]: epic fail\n" - assert_equal expected, err end - def test_self_load_specification_interrupt - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.mkdir_p spec_dir - - spec_file = File.join spec_dir, 'a-1.gemspec' - - File.open spec_file, 'w' do |fp| - fp.write 'raise Interrupt, "^C"' - end - - use_ui @ui do - assert_raises Interrupt do - Gem::SourceIndex.load_specification(spec_file) + # HACK: deprecated impl is failing tests, but I may want to port it over + def test_latest_specs + Deprecate.skip_during do + p1_ruby = quick_spec 'p', '1' + p1_platform = quick_spec 'p', '1' do |spec| + spec.platform = Gem::Platform::CURRENT end - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - end - - def test_self_load_specification_syntax_error - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.mkdir_p spec_dir - - spec_file = File.join spec_dir, 'a-1.gemspec' - - File.open spec_file, 'w' do |fp| - fp.write '1 +' - end - - out, err = capture_io do - assert_equal nil, Gem::SourceIndex.load_specification(spec_file) - end - - assert_equal '', out - - assert_match(/syntax error/, err) - end - - def test_self_load_specification_system_exit - spec_dir = File.join @gemhome, 'specifications' - - FileUtils.mkdir_p spec_dir - spec_file = File.join spec_dir, 'a-1.gemspec' - - File.open spec_file, 'w' do |fp| - fp.write 'raise SystemExit, "bye-bye"' - end - - use_ui @ui do - assert_raises SystemExit do - Gem::SourceIndex.load_specification(spec_file) + a1_platform = quick_spec @a1.name, (@a1.version) do |s| + s.platform = Gem::Platform.new 'x86-my_platform1' end - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - end - - def test_create_from_directory - # TODO - end - def test_find_name - assert_equal [@a1, @a2, @a3a], @source_index.find_name('a') - assert_equal [@a2], @source_index.find_name('a', '= 2') - assert_equal [], @source_index.find_name('bogusstring') - assert_equal [], @source_index.find_name('a', '= 3') - - source_index = Gem::SourceIndex.new - source_index.add_spec @a1 - source_index.add_spec @a2 - - assert_equal [@a1], source_index.find_name(@a1.name, '= 1') - - r1 = Gem::Requirement.create '= 1' - assert_equal [@a1], source_index.find_name(@a1.name, r1) - end - - def test_find_name_empty_cache - empty_source_index = Gem::SourceIndex.new({}) - assert_equal [], empty_source_index.find_name("foo") - end - - def test_latest_specs - p1_ruby = quick_spec 'p', '1' - p1_platform = quick_spec 'p', '1' do |spec| - spec.platform = Gem::Platform::CURRENT - end - - a1_platform = quick_spec @a1.name, (@a1.version) do |s| - s.platform = Gem::Platform.new 'x86-my_platform1' - end + a2_platform = quick_spec @a2.name, (@a2.version) do |s| + s.platform = Gem::Platform.new 'x86-my_platform1' + end - a2_platform = quick_spec @a2.name, (@a2.version) do |s| - s.platform = Gem::Platform.new 'x86-my_platform1' - end + a2_platform_other = quick_spec @a2.name, (@a2.version) do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end - a2_platform_other = quick_spec @a2.name, (@a2.version) do |s| - s.platform = Gem::Platform.new 'x86-other_platform1' - end + a3_platform_other = quick_spec @a2.name, (@a2.version.bump) do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end - a3_platform_other = quick_spec @a2.name, (@a2.version.bump) do |s| - s.platform = Gem::Platform.new 'x86-other_platform1' + @source_index.add_spec p1_ruby + @source_index.add_spec p1_platform + @source_index.add_spec a1_platform + @source_index.add_spec a2_platform + @source_index.add_spec a2_platform_other + @source_index.add_spec a3_platform_other + + expected = [ + @a2.full_name, + a2_platform.full_name, + a3_platform_other.full_name, + @b2.full_name, + @c1_2.full_name, + @a_evil9.full_name, + p1_ruby.full_name, + p1_platform.full_name, + @pl1.full_name + ].sort + + latest_specs = @source_index.latest_specs.map { |s| s.full_name }.sort + + assert_equal expected, latest_specs end - - @source_index.add_spec p1_ruby - @source_index.add_spec p1_platform - @source_index.add_spec a1_platform - @source_index.add_spec a2_platform - @source_index.add_spec a2_platform_other - @source_index.add_spec a3_platform_other - - expected = [ - @a2.full_name, - a2_platform.full_name, - a3_platform_other.full_name, - @c1_2.full_name, - @a_evil9.full_name, - p1_ruby.full_name, - p1_platform.full_name, - ].sort - - latest_specs = @source_index.latest_specs.map { |s| s.full_name }.sort - - assert_equal expected, latest_specs end def test_load_gems_in - spec_dir1 = File.join @gemhome, 'specifications' - spec_dir2 = File.join @tempdir, 'gemhome2', 'specifications' + Deprecate.skip_during do + spec_dir1 = File.join @gemhome, 'specifications' + spec_dir2 = File.join @tempdir, 'gemhome2', 'specifications' - FileUtils.rm_r spec_dir1 + FileUtils.rm_r spec_dir1 - FileUtils.mkdir_p spec_dir1 - FileUtils.mkdir_p spec_dir2 + FileUtils.mkdir_p spec_dir1 + FileUtils.mkdir_p spec_dir2 - a1 = quick_spec 'a', '1' do |spec| spec.author = 'author 1' end - a2 = quick_spec 'a', '1' do |spec| spec.author = 'author 2' end + a1 = quick_spec 'a', '1' do |spec| spec.author = 'author 1' end + a2 = quick_spec 'a', '1' do |spec| spec.author = 'author 2' end - File.open File.join(spec_dir1, a1.spec_name), 'w' do |fp| - fp.write a1.to_ruby - end + path1 = File.join(spec_dir1, a1.spec_name) + path2 = File.join(spec_dir2, a2.spec_name) - File.open File.join(spec_dir2, a2.spec_name), 'w' do |fp| - fp.write a2.to_ruby - end + File.open path1, 'w' do |fp| + fp.write a1.to_ruby + end + + File.open path2, 'w' do |fp| + fp.write a2.to_ruby + end - @source_index.load_gems_in spec_dir1, spec_dir2 + @source_index.load_gems_in File.dirname(path1), File.dirname(path2) - assert_equal a1.author, @source_index.specification(a1.full_name).author + assert_equal a1.author, @source_index.specification(a1.full_name).author + end end + # REFACTOR: move to test_gem_commands_outdated_command.rb def test_outdated - util_setup_spec_fetcher + Deprecate.skip_during do + util_setup_spec_fetcher - assert_equal [], @source_index.outdated + assert_equal [], @source_index.outdated - updated = quick_spec @a2.name, (@a2.version.bump) - util_setup_spec_fetcher updated + updated = quick_spec @a2.name, (@a2.version.bump) + util_setup_spec_fetcher updated - assert_equal [updated.name], @source_index.outdated + assert_equal [updated.name], @source_index.outdated - updated_platform = quick_spec @a2.name, (updated.version.bump) do |s| - s.platform = Gem::Platform.new 'x86-other_platform1' - end + updated_platform = quick_spec @a2.name, (updated.version.bump) do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end - util_setup_spec_fetcher updated, updated_platform + util_setup_spec_fetcher updated, updated_platform - assert_equal [updated_platform.name], @source_index.outdated + assert_equal [updated_platform.name], @source_index.outdated + end end def test_prerelease_specs_kept_in_right_place - gem_a1_alpha = quick_spec 'abba', '1.a' - @source_index.add_spec gem_a1_alpha - - refute @source_index.latest_specs.include?(gem_a1_alpha) - assert @source_index.latest_specs(true).include?(gem_a1_alpha) - assert @source_index.find_name(gem_a1_alpha.full_name).empty? - assert @source_index.prerelease_specs.include?(gem_a1_alpha) + Deprecate.skip_during do + gem_a1_alpha = quick_spec 'abba', '1.a' + @source_index.add_spec gem_a1_alpha + + refute_includes @source_index.latest_specs, gem_a1_alpha + assert_includes @source_index.latest_specs(true), gem_a1_alpha + assert_empty @source_index.find_name gem_a1_alpha.full_name + assert_includes @source_index.prerelease_specs, gem_a1_alpha + end end def test_refresh_bang - a1_spec = File.join @gemhome, "specifications", @a1.spec_name - - FileUtils.mv a1_spec, @tempdir + Deprecate.skip_during do + a1_spec = File.join @gemhome, "specifications", @a1.spec_name - source_index = Gem::SourceIndex.from_installed_gems + FileUtils.mv a1_spec, @tempdir - refute source_index.gems.include?(@a1.full_name) + Gem::Specification.reset + Gem.send :class_variable_set, :@@source_index, nil + source_index = Gem.source_index - FileUtils.mv File.join(@tempdir, @a1.spec_name), a1_spec + refute_includes source_index.gems.keys.sort, @a1.full_name - source_index.refresh! - - assert source_index.gems.include?(@a1.full_name) - end + FileUtils.mv File.join(@tempdir, @a1.spec_name), a1_spec - def test_refresh_bang_not_from_dir - source_index = Gem::SourceIndex.new - - e = assert_raises RuntimeError do source_index.refresh! - end - assert_equal 'source index not created from disk', e.message + assert source_index.gems.include?(@a1.full_name) + end end def test_remove_spec - deleted = @source_index.remove_spec 'a-1' + Deprecate.skip_during do + si = Gem.source_index - assert_equal %w[a-2 a-3.a a_evil-9 c-1.2], - @source_index.all_gems.values.map { |s| s.full_name }.sort + expected = si.gems.keys.sort - deleted = @source_index.remove_spec 'a-3.a' + expected.delete "a-1" + @source_index.remove_spec 'a-1' - assert_equal %w[a-2 a_evil-9 c-1.2], - @source_index.all_gems.values.map { |s| s.full_name }.sort + assert_equal expected, si.gems.keys.sort + + expected.delete "a-3.a" + @source_index.remove_spec 'a-3.a' + + assert_equal expected, si.gems.keys.sort + end end def test_search - requirement = Gem::Requirement.create '= 9' - with_version = Gem::Dependency.new(/^a/, requirement) - assert_equal [@a_evil9], @source_index.search(with_version) + Deprecate.skip_during do + requirement = Gem::Requirement.create '= 9' + with_version = Gem::Dependency.new(/^a/, requirement) + assert_equal [@a_evil9], @source_index.search(with_version) - with_default = Gem::Dependency.new(/^a/, Gem::Requirement.default) - assert_equal [@a1, @a2, @a3a, @a_evil9], @source_index.search(with_default) + with_default = Gem::Dependency.new(/^a/, Gem::Requirement.default) + assert_equal [@a1, @a2, @a3a, @a_evil9], @source_index.search(with_default) - c1_1_dep = Gem::Dependency.new 'c', '~> 1.1' - assert_equal [@c1_2], @source_index.search(c1_1_dep) + c1_1_dep = Gem::Dependency.new 'c', '~> 1.1' + assert_equal [@c1_2], @source_index.search(c1_1_dep) + end end def test_search_platform - util_set_arch 'x86-my_platform1' + Deprecate.skip_during do + util_set_arch 'x86-my_platform1' - a1 = quick_spec 'a', '1' - a1_mine = quick_spec 'a', '1' do |s| - s.platform = Gem::Platform.new 'x86-my_platform1' - end - a1_other = quick_spec 'a', '1' do |s| - s.platform = Gem::Platform.new 'x86-other_platform1' - end + a1 = quick_spec 'a', '1' + a1_mine = quick_spec 'a', '1' do |s| + s.platform = Gem::Platform.new 'x86-my_platform1' + end + a1_other = quick_spec 'a', '1' do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end - si = Gem::SourceIndex.new(a1.full_name => a1, a1_mine.full_name => a1_mine, - a1_other.full_name => a1_other) + si = Gem::SourceIndex.new + si.add_specs a1, a1_mine, a1_other - dep = Gem::Dependency.new 'a', Gem::Requirement.new('1') + dep = Gem::Dependency.new 'a', Gem::Requirement.new('1') - gems = si.search dep, true + gems = si.search dep, true - assert_equal [a1, a1_mine], gems.sort + assert_equal [a1, a1_mine], gems.sort + end end def test_signature - sig = @source_index.gem_signature('foo-1.2.3') - assert_equal 64, sig.length - assert_match(/^[a-f0-9]{64}$/, sig) + Deprecate.skip_during do + sig = @source_index.gem_signature('foo-1.2.3') + assert_equal 64, sig.length + assert_match(/^[a-f0-9]{64}$/, sig) + end end def test_specification - assert_equal @a1, @source_index.specification(@a1.full_name) + Deprecate.skip_during do + assert_equal @a1, @source_index.specification(@a1.full_name) - assert_nil @source_index.specification("foo-1.2.4") + assert_nil @source_index.specification("foo-1.2.4") + end end def test_index_signature - sig = @source_index.index_signature - assert_match(/^[a-f0-9]{64}$/, sig) + Deprecate.skip_during do + sig = @source_index.index_signature + assert_match(/^[a-f0-9]{64}$/, sig) + end end - end - diff --git a/test/rubygems/test_gem_spec_fetcher.rb b/test/rubygems/test_gem_spec_fetcher.rb index de7bd9a0fd..073b082b06 100644 --- a/test/rubygems/test_gem_spec_fetcher.rb +++ b/test/rubygems/test_gem_spec_fetcher.rb @@ -16,43 +16,43 @@ class TestGemSpecFetcher < Gem::TestCase util_setup_fake_fetcher - @a_pre = quick_spec 'a', '1.a' - @source_index.add_spec @pl1 - @source_index.add_spec @a_pre + @a_pre = new_spec 'a', '1.a' - @specs = @source_index.gems.sort.map do |name, spec| - [spec.name, spec.version, spec.original_platform] - end.sort + install_specs @a_pre - @latest_specs = @source_index.latest_specs.sort.map do |spec| - [spec.name, spec.version, spec.original_platform] - end + Gem::Specification.remove_spec @b2 - @prerelease_specs = @source_index.prerelease_gems.sort.map do |name, spec| + @specs = Gem::Specification.map { |spec| [spec.name, spec.version, spec.original_platform] - end.sort + }.sort - @fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] = - util_gzip(Marshal.dump(@specs)) + # TODO: couldn't all of this come from the fake spec fetcher? + @latest_specs = Gem::Specification.latest_specs.sort.map { |spec| + [spec.name, spec.version, spec.original_platform] + } - @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = - util_gzip(Marshal.dump(@latest_specs)) + prerelease = Gem::Specification.find_all { |s| s.version.prerelease? } + @prerelease_specs = prerelease.map { |spec| + [spec.name, spec.version, spec.original_platform] + }.sort - @fetcher.data["#{@gem_repo}prerelease_specs.#{Gem.marshal_version}.gz"] = - util_gzip(Marshal.dump(@prerelease_specs)) + v = Gem.marshal_version + s_zip = util_gzip(Marshal.dump(@specs)) + l_zip = util_gzip(Marshal.dump(@latest_specs)) + p_zip = util_gzip(Marshal.dump(@prerelease_specs)) + @fetcher.data["#{@gem_repo}specs.#{v}.gz"] = s_zip + @fetcher.data["#{@gem_repo}latest_specs.#{v}.gz"] = l_zip + @fetcher.data["#{@gem_repo}prerelease_specs.#{v}.gz"] = p_zip @sf = Gem::SpecFetcher.new end def test_fetch_all - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.spec_name}.rz"] = - util_zip(Marshal.dump(@a1)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.spec_name}.rz"] = - util_zip(Marshal.dump(@a2)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.spec_name}.rz"] = - util_zip(Marshal.dump(@a_pre)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a3a.spec_name}.rz"] = - util_zip(Marshal.dump(@a3a)) + d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" + @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) + @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) + @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) + @fetcher.data["#{d}#{@a3a.spec_name}.rz"] = util_zip(Marshal.dump(@a3a)) dep = Gem::Dependency.new 'a', 1 @@ -70,12 +70,10 @@ class TestGemSpecFetcher < Gem::TestCase end def test_fetch_latest - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.spec_name}.rz"] = - util_zip(Marshal.dump(@a1)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.spec_name}.rz"] = - util_zip(Marshal.dump(@a2)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.spec_name}.rz"] = - util_zip(Marshal.dump(@a_pre)) + d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" + @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) + @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) + @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) dep = Gem::Dependency.new 'a', 1 specs_and_sources = @sf.fetch dep @@ -88,15 +86,12 @@ class TestGemSpecFetcher < Gem::TestCase end def test_fetch_prerelease - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.spec_name}.rz"] = - util_zip(Marshal.dump(@a1)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.spec_name}.rz"] = - util_zip(Marshal.dump(@a2)) - @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.spec_name}.rz"] = - util_zip(Marshal.dump(@a_pre)) + d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" + @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) + @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) + @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) - dep = Gem::Dependency.new 'a', '1.a' - specs_and_sources = @sf.fetch dep, false, true, true + specs_and_sources = @sf.fetch dep('a', '1.a'), false, true, true spec_names = specs_and_sources.map do |spec, source_uri| [spec.full_name, source_uri] @@ -293,11 +288,11 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@uri], specs.keys - assert_equal([["a", Gem::Version.new("1"), "ruby"], - ["a", Gem::Version.new("2"), "ruby"], - ["a_evil", Gem::Version.new("9"), "ruby"], - ["c", Gem::Version.new("1.2"), "ruby"], - ["pl", Gem::Version.new("1"), "i386-linux"]], + assert_equal([["a", Gem::Version.new("1"), "ruby"], + ["a", Gem::Version.new("2"), "ruby"], + ["a_evil", Gem::Version.new("9"), "ruby"], + ["c", Gem::Version.new("1.2"), "ruby"], + ["pl", Gem::Version.new("1"), "i386-linux"]], specs[@uri].sort) end @@ -347,19 +342,17 @@ class TestGemSpecFetcher < Gem::TestCase end def test_load_specs - specs = @sf.load_specs @uri, 'specs' - expected = [ - ['a', Gem::Version.new('1.a'), Gem::Platform::RUBY], + ['a', Gem::Version.new('1.a'), Gem::Platform::RUBY], ['a', Gem::Version.new(1), Gem::Platform::RUBY], ['a', Gem::Version.new(2), Gem::Platform::RUBY], - ['a', Gem::Version.new('3.a'), Gem::Platform::RUBY], + ['a', Gem::Version.new('3.a'), Gem::Platform::RUBY], ['a_evil', Gem::Version.new(9), Gem::Platform::RUBY], ['c', Gem::Version.new('1.2'), Gem::Platform::RUBY], ['pl', Gem::Version.new(1), 'i386-linux'], ] - assert_equal expected, specs + assert_equal expected, @sf.load_specs(@uri, 'specs') cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80' assert File.exist?(cache_dir), "#{cache_dir} does not exist" diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index d7f5772259..ef52f0a50e 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -35,8 +35,8 @@ Gem::Specification.new do |s| s.version = %q{0.4.0} s.has_rdoc = true s.summary = %q{A Hash which automatically computes keys.} - s.files = ["lib/keyedlist.rb"] - s.require_paths = ["lib"] + s.files = [%q{lib/keyedlist.rb}] + s.require_paths = [%q{lib}] s.autorequire = %q{keyedlist} s.author = %q{Florian Gross} s.email = %q{flgr@ccan.de} @@ -46,11 +46,9 @@ end def setup super - # TODO: there is no reason why the spec tests need to write to disk - @a1 = quick_gem 'a', '1' do |s| + @a1 = quick_spec 'a', '1' do |s| s.executable = 'exec' s.extensions << 'ext/a/extconf.rb' - s.has_rdoc = 'true' s.test_file = 'test/suite.rb' s.requirements << 'A working computer' s.rubyforge_project = 'example' @@ -64,15 +62,10 @@ end s.files = %w[lib/code.rb] end - @a2 = quick_gem 'a', '2' do |s| + @a2 = quick_spec 'a', '2' do |s| s.files = %w[lib/code.rb] end - FileUtils.mkdir_p File.join(@tempdir, 'bin') - File.open File.join(@tempdir, 'bin', 'exec'), 'w' do |fp| - fp.puts "#!#{Gem.ruby}" - end - @current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION end @@ -83,7 +76,6 @@ end bindir cert_chain date - default_executable dependencies description email @@ -91,7 +83,6 @@ end extensions extra_rdoc_files files - has_rdoc homepage licenses name @@ -129,18 +120,39 @@ end assert_equal @current_version, new_spec.specification_version end + def test_self_from_yaml_syck_bug + # This is equivalent to (and totally valid) psych 1.0 output and + # causes parse errors on syck. + yaml = @a1.to_yaml + yaml.sub!(/^date:.*/, "date: 2011-04-26 00:00:00.000000000Z") + + new_spec = with_syck do + Gem::Specification.from_yaml yaml + end + + assert_kind_of Time, @a1.date + assert_kind_of Time, new_spec.date + end + def test_self_load - spec = File.join @gemhome, 'specifications', @a2.spec_name - gs = Gem::Specification.load spec + full_path = @a2.spec_file + write_file full_path do |io| + io.write @a2.to_ruby_for_cache + end + + spec = Gem::Specification.load full_path + + @a2.files.clear - assert_equal @a2, gs + assert_equal @a2, spec end def test_self_load_legacy_ruby - spec = eval LEGACY_RUBY_SPEC + spec = Deprecate.skip_during do + eval LEGACY_RUBY_SPEC + end assert_equal 'keyedlist', spec.name assert_equal '0.4.0', spec.version.to_s - assert_equal true, spec.has_rdoc? assert_equal Gem::Specification::TODAY, spec.date assert spec.required_ruby_version.satisfied_by?(Gem::Version.new('1')) assert_equal false, spec.has_unit_tests? @@ -195,8 +207,6 @@ end assert_equal [], spec.requirements assert_equal [], spec.dependencies assert_equal 'bin', spec.bindir - assert_equal true, spec.has_rdoc - assert_equal true, spec.has_rdoc? assert_equal '>= 0', spec.required_ruby_version.to_s assert_equal '>= 0', spec.required_rubygems_version.to_s end @@ -279,9 +289,6 @@ end assert_equal 'bin', spec.bindir assert_same spec.bindir, new_spec.bindir - assert_equal true, spec.has_rdoc - assert_same spec.has_rdoc, new_spec.has_rdoc - assert_equal '>= 0', spec.required_ruby_version.to_s assert_same spec.required_ruby_version, new_spec.required_ruby_version @@ -290,6 +297,23 @@ end new_spec.required_rubygems_version end + def test_initialize_copy_broken + spec = Gem::Specification.new do |s| + s.name = 'a' + s.version = '1' + end + + spec.instance_variable_set :@licenses, :blah + spec.loaded_from = '/path/to/file' + + e = assert_raises Gem::FormatException do + spec.dup + end + + assert_equal 'a-1 has an invalid value for @licenses', e.message + assert_equal '/path/to/file', e.file_path + end + def test__dump @a2.platform = Gem::Platform.local @a2.instance_variable_set :@original_platform, 'old_platform' @@ -338,37 +362,33 @@ end def test_date_equals_date @a1.date = Date.new(2003, 9, 17) - assert_equal Time.local(2003, 9, 17, 0,0,0), @a1.date + assert_equal Time.utc(2003, 9, 17, 0,0,0), @a1.date end def test_date_equals_string @a1.date = '2003-09-17' - assert_equal Time.local(2003, 9, 17, 0,0,0), @a1.date + assert_equal Time.utc(2003, 9, 17, 0,0,0), @a1.date + end + + def test_date_equals_string_bad + assert_raises Gem::InvalidSpecificationException do + @a1.date = '9/11/2003' + end end def test_date_equals_time @a1.date = Time.local(2003, 9, 17, 0,0,0) - assert_equal Time.local(2003, 9, 17, 0,0,0), @a1.date + assert_equal Time.utc(2003, 9, 17, 0,0,0), @a1.date end def test_date_equals_time_local - # HACK PDT - @a1.date = Time.local(2003, 9, 17, 19,50,0) - assert_equal Time.local(2003, 9, 17, 0,0,0), @a1.date + @a1.date = Time.local(2003, 9, 17, 19,50,0) # may not pass in utc >= +4 + assert_equal Time.utc(2003, 9, 17, 0,0,0), @a1.date end def test_date_equals_time_utc - # HACK PDT - @a1.date = Time.local(2003, 9, 17, 19,50,0) - assert_equal Time.local(2003, 9, 17, 0,0,0), @a1.date - end - - def test_default_executable - assert_equal 'exec', @a1.default_executable - - @a1.default_executable = nil - @a1.instance_variable_set :@executables, nil - assert_equal nil, @a1.default_executable + @a1.date = Time.utc(2003, 9, 17, 19,50,0) + assert_equal Time.utc(2003, 9, 17, 0,0,0), @a1.date end def test_dependencies @@ -391,60 +411,20 @@ end end def test_eql_eh - g1 = quick_spec 'gem' - g2 = quick_spec 'gem' + g1 = new_spec 'gem', 1 + g2 = new_spec 'gem', 1 assert_equal g1, g2 assert_equal g1.hash, g2.hash assert_equal true, g1.eql?(g2) end - def test_equals2 - assert_equal @a1, @a1 - assert_equal @a1, @a1.dup - refute_equal @a1, @a2 - refute_equal @a1, Object.new - end - - # The cgikit specification was reported to be causing trouble in at least - # one version of RubyGems, so we test explicitly for it. - def test_equals2_cgikit - cgikit = Gem::Specification.new do |s| - s.name = %q{cgikit} - s.version = "1.1.0" - s.date = %q{2004-03-13} - s.summary = %q{CGIKit is a componented-oriented web application } + - %q{framework like Apple Computers WebObjects. } + - %{This framework services Model-View-Controller architecture } + - %q{programming by components based on a HTML file, a definition } + - %q{file and a Ruby source. } - s.email = %q{info@spice-of-life.net} - s.homepage = %q{http://www.spice-of-life.net/download/cgikit/} - s.autorequire = %q{cgikit} - s.bindir = nil - s.has_rdoc = true - s.required_ruby_version = nil - s.platform = nil - s.files = ["lib/cgikit", "lib/cgikit.rb", "lib/cgikit/components", "..."] - end - - assert_equal cgikit, cgikit - end - - def test_equals2_default_executable - spec = @a1.dup - spec.default_executable = 'xx' - - refute_equal @a1, spec - refute_equal spec, @a1 - end - - def test_equals2_extensions + def test_eql_eh_extensions spec = @a1.dup spec.extensions = 'xx' - refute_equal @a1, spec - refute_equal spec, @a1 + refute_operator @a1, :eql?, spec + refute_operator spec, :eql?, @a1 end def test_executables @@ -542,9 +522,26 @@ end assert_kind_of Integer, @a1.hash end + def test_for_cache + @a2.add_runtime_dependency 'b', '1' + @a2.dependencies.first.instance_variable_set :@type, nil + @a2.required_rubygems_version = Gem::Requirement.new '> 0' + @a2.test_files = %w[test/test_b.rb] + + refute_empty @a2.files + refute_empty @a2.test_files + + spec = @a2.for_cache + + assert_empty spec.files + assert_empty spec.test_files + + refute_empty @a2.files + refute_empty @a2.test_files + end + def test_full_gem_path - assert_equal File.join(@gemhome, 'gems', @a1.full_name), - @a1.full_gem_path + assert_equal File.join(@gemhome, 'gems', @a1.full_name), @a1.full_gem_path @a1.original_platform = 'mswin32' @@ -553,11 +550,11 @@ end end def test_full_gem_path_double_slash - gemhome = @gemhome.sub(/\w\//, '\&/') - @a1.loaded_from = File.join gemhome, 'specifications', @a1.spec_name + gemhome = @gemhome.to_s.sub(/\w\//, '\&/') + @a1.loaded_from = File.join gemhome, "specifications", @a1.spec_name - assert_equal File.join(@gemhome, 'gems', @a1.full_name), - @a1.full_gem_path + expected = File.join @gemhome, "gems", @a1.full_name + assert_equal expected, @a1.full_gem_path end def test_full_name @@ -589,21 +586,6 @@ end end end - def test_has_rdoc_eh - assert @a1.has_rdoc? - end - - def test_has_rdoc_equals - - use_ui @ui do - @a1.has_rdoc = false - end - - assert_equal '', @ui.output - - assert_equal true, @a1.has_rdoc - end - def test_hash assert_equal @a1.hash, @a1.hash assert_equal @a1.hash, @a1.dup.hash @@ -611,15 +593,14 @@ end end def test_installation_path - assert_equal @gemhome, @a1.installation_path + Deprecate.skip_during do + assert_equal @gemhome, @a1.installation_path - @a1.instance_variable_set :@loaded_from, nil + @a1.instance_variable_set :@loaded_from, nil + @a1.instance_variable_set :@loaded, false - e = assert_raises Gem::Exception do - @a1.installation_path + assert_nil @a1.installation_path end - - assert_equal 'spec a-1 is not from an installed gem', e.message end def test_lib_files @@ -717,8 +698,8 @@ end end def test_spaceship_name - s1 = quick_spec 'a', '1' - s2 = quick_spec 'b', '1' + s1 = new_spec 'a', '1' + s2 = new_spec 'b', '1' assert_equal(-1, (s1 <=> s2)) assert_equal( 0, (s1 <=> s1)) @@ -726,8 +707,8 @@ end end def test_spaceship_platform - s1 = quick_spec 'a', '1' - s2 = quick_spec 'a', '1' do |s| + s1 = new_spec 'a', '1' + s2 = new_spec 'a', '1' do |s| s.platform = Gem::Platform.new 'x86-my_platform1' end @@ -737,8 +718,8 @@ end end def test_spaceship_version - s1 = quick_spec 'a', '1' - s2 = quick_spec 'a', '2' + s1 = new_spec 'a', '1' + s2 = new_spec 'a', '2' assert_equal( -1, (s1 <=> s2)) assert_equal( 0, (s1 <=> s1)) @@ -773,13 +754,13 @@ Gem::Specification.new do |s| s.version = \"2\" s.required_rubygems_version = Gem::Requirement.new(\"> 0\") if s.respond_to? :required_rubygems_version= - s.authors = [\"A User\"] + s.authors = [%q{A User}] s.date = %q{#{Gem::Specification::TODAY.strftime "%Y-%m-%d"}} s.description = %q{This is a test description} s.email = %q{example@example.com} - s.files = [\"lib/code.rb\"] + s.files = [%q{lib/code.rb}] s.homepage = %q{http://example.com} - s.require_paths = [\"lib\"] + s.require_paths = [%q{lib}] s.rubygems_version = %q{#{Gem::VERSION}} s.summary = %q{this is a summary} @@ -820,12 +801,12 @@ Gem::Specification.new do |s| s.version = \"2\" s.required_rubygems_version = Gem::Requirement.new(\"> 0\") if s.respond_to? :required_rubygems_version= - s.authors = [\"A User\"] + s.authors = [%q{A User}] s.date = %q{#{Gem::Specification::TODAY.strftime "%Y-%m-%d"}} s.description = %q{This is a test description} s.email = %q{example@example.com} s.homepage = %q{http://example.com} - s.require_paths = [\"lib\"] + s.require_paths = [%q{lib}] s.rubygems_version = %q{#{Gem::VERSION}} s.summary = %q{this is a summary} @@ -868,22 +849,21 @@ Gem::Specification.new do |s| s.platform = Gem::Platform.new(#{expected_platform}) s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version= - s.authors = [\"A User\"] + s.authors = [%q{A User}] s.date = %q{#{Gem::Specification::TODAY.strftime "%Y-%m-%d"}} - s.default_executable = %q{exec} s.description = %q{This is a test description} s.email = %q{example@example.com} - s.executables = [\"exec\"] - s.extensions = [\"ext/a/extconf.rb\"] - s.files = [\"lib/code.rb\", \"test/suite.rb\", \"bin/exec\", \"ext/a/extconf.rb\"] + s.executables = [%q{exec}] + s.extensions = [%q{ext/a/extconf.rb}] + s.files = [%q{lib/code.rb}, %q{test/suite.rb}, %q{bin/exec}, %q{ext/a/extconf.rb}] s.homepage = %q{http://example.com} - s.licenses = [\"MIT\"] - s.require_paths = [\"lib\"] - s.requirements = [\"A working computer\"] + s.licenses = [%q{MIT}] + s.require_paths = [%q{lib}] + s.requirements = [%q{A working computer}] s.rubyforge_project = %q{example} s.rubygems_version = %q{#{Gem::VERSION}} s.summary = %q{this is a summary} - s.test_files = [\"test/suite.rb\"] + s.test_files = [%q{test/suite.rb}] if s.respond_to? :specification_version then s.specification_version = 3 @@ -913,7 +893,9 @@ end end def test_to_ruby_legacy - gemspec1 = eval LEGACY_RUBY_SPEC + gemspec1 = Deprecate.skip_during do + eval LEGACY_RUBY_SPEC + end ruby_code = gemspec1.to_ruby gemspec2 = eval ruby_code @@ -936,7 +918,7 @@ end refute_match '!!null', yaml_str - same_spec = YAML.load(yaml_str) + same_spec = Gem::Specification.from_yaml(yaml_str) assert_equal @a1, same_spec end @@ -945,7 +927,7 @@ end @a1.platform = Gem::Platform.local yaml_str = @a1.to_yaml - same_spec = YAML.load(yaml_str) + same_spec = Gem::Specification.from_yaml(yaml_str) assert_equal Gem::Platform.local, same_spec.platform @@ -984,41 +966,48 @@ end end end + def x s; s.gsub(/xxx/, ''); end + def w; x "WARxxxNING"; end + def t; x "TOxxxDO"; end + def f; x "FxxxIXME"; end + def test_validate_authors util_setup_validate Dir.chdir @tempdir do - @a1.authors = [] + @a1.authors = [""] use_ui @ui do @a1.validate end - assert_equal "WARNING: no author specified\n", @ui.error, 'error' + assert_equal "#{w}: no author specified\n", @ui.error, 'error' @a1.authors = [Object.new] + assert_equal [], @a1.authors + e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal 'authors must be Array of Strings', e.message + assert_equal "authors may not be empty", e.message - @a1.authors = ['FIXME (who is writing this software)'] + @a1.authors = ["#{f} (who is writing this software)"] e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not an author', e.message + assert_equal %{"#{f}" or "#{t}" is not an author}, e.message - @a1.authors = ['TODO (who is writing this software)'] + @a1.authors = ["#{t} (who is writing this software)"] e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not an author', e.message + assert_equal %{"#{f}" or "#{t}" is not an author}, e.message end end @@ -1032,7 +1021,7 @@ end @a1.validate end - assert_equal "WARNING: deprecated autorequire specified\n", + assert_equal "#{w}: deprecated autorequire specified\n", @ui.error, 'error' end end @@ -1047,34 +1036,34 @@ end @a1.validate end - assert_equal "WARNING: no description specified\n", @ui.error, 'error' + assert_equal "#{w}: no description specified\n", @ui.error, "error" @ui = Gem::MockGemUi.new - @a1.summary = 'this is my summary' + @a1.summary = "this is my summary" @a1.description = @a1.summary use_ui @ui do @a1.validate end - assert_equal "WARNING: description and summary are identical\n", - @ui.error, 'error' + assert_equal "#{w}: description and summary are identical\n", + @ui.error, "error" - @a1.description = 'FIXME (describe your package)' + @a1.description = "#{f} (describe your package)" e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not a description', e.message + assert_equal %{"#{f}" or "#{t}" is not a description}, e.message - @a1.description = 'TODO (describe your package)' + @a1.description = "#{t} (describe your package)" e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not a description', e.message + assert_equal %{"#{f}" or "#{t}" is not a description}, e.message end end @@ -1082,35 +1071,33 @@ end util_setup_validate Dir.chdir @tempdir do - @a1.email = '' + @a1.email = "" use_ui @ui do @a1.validate end - assert_equal "WARNING: no email specified\n", @ui.error, 'error' + assert_equal "#{w}: no email specified\n", @ui.error, "error" - @a1.email = 'FIXME (your e-mail)' + @a1.email = "FIxxxXME (your e-mail)".sub(/xxx/, "") e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not an email address', e.message + assert_equal %{"#{f}" or "#{t}" is not an email}, e.message - @a1.email = 'TODO (your e-mail)' + @a1.email = "#{t} (your e-mail)" e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not an email address', e.message + assert_equal %{"#{f}" or "#{t}" is not an email}, e.message end end def test_validate_empty - util_setup_validate - e = assert_raises Gem::InvalidSpecificationException do Gem::Specification.new.validate end @@ -1134,7 +1121,7 @@ end assert_equal %w[exec], @a1.executables assert_equal '', @ui.output, 'output' - assert_equal "WARNING: bin/exec is missing #! line\n", @ui.error, 'error' + assert_equal "#{w}: bin/exec is missing #! line\n", @ui.error, 'error' end def test_validate_empty_require_paths @@ -1183,7 +1170,7 @@ end @a1.validate end - assert_equal "WARNING: no homepage specified\n", @ui.error, 'error' + assert_equal "#{w}: no homepage specified\n", @ui.error, 'error' @ui = Gem::MockGemUi.new @@ -1193,7 +1180,7 @@ end @a1.validate end - assert_equal "WARNING: no homepage specified\n", @ui.error, 'error' + assert_equal "#{w}: no homepage specified\n", @ui.error, 'error' @a1.homepage = 'over at my cool site' @@ -1216,6 +1203,26 @@ end assert_equal 'invalid value for attribute name: ":json"', e.message end + def test_validate_non_nil + util_setup_validate + + Dir.chdir @tempdir do + assert @a1.validate + + Gem::Specification.non_nil_attributes.each do |name| + next if name == :files # set by #normalize + spec = @a1.dup + spec.instance_variable_set "@#{name}", nil + + e = assert_raises Gem::InvalidSpecificationException do + spec.validate + end + + assert_match %r%^#{name}%, e.message + end + end + end + def test_validate_platform_legacy util_setup_validate @@ -1270,23 +1277,23 @@ end @a1.validate end - assert_equal "WARNING: no summary specified\n", @ui.error, 'error' + assert_equal "#{w}: no summary specified\n", @ui.error, 'error' - @a1.summary = 'FIXME (describe your package)' + @a1.summary = "#{f} (describe your package)" e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not a summary', e.message + assert_equal %{"#{f}" or "#{t}" is not a summary}, e.message - @a1.summary = 'TODO (describe your package)' + @a1.summary = "#{t} (describe your package)" e = assert_raises Gem::InvalidSpecificationException do @a1.validate end - assert_equal '"FIXME" or "TODO" is not a summary', e.message + assert_equal %{"#{f}" or "#{t}" is not a summary}, e.message end end @@ -1310,6 +1317,67 @@ end specfile.delete end + ## + # KEEP p-1-x86-darwin-8 + # KEEP p-1 + # KEEP c-1.2 + # KEEP a_evil-9 + # a-1 + # a-1-x86-my_platform-1 + # KEEP a-2 + # a-2-x86-other_platform-1 + # KEEP a-2-x86-my_platform-1 + # a-3.a + # KEEP a-3-x86-other_platform-1 + + def test_latest_specs + util_clear_gems + util_setup_fake_fetcher + + quick_spec 'p', '1' + + p1_curr = quick_spec 'p', '1' do |spec| + spec.platform = Gem::Platform::CURRENT + end + + quick_spec @a1.name, @a1.version do |s| + s.platform = Gem::Platform.new 'x86-my_platform1' + end + + quick_spec @a1.name, @a1.version do |s| + s.platform = Gem::Platform.new 'x86-third_platform1' + end + + quick_spec @a2.name, @a2.version do |s| + s.platform = Gem::Platform.new 'x86-my_platform1' + end + + quick_spec @a2.name, @a2.version do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end + + quick_spec @a2.name, @a2.version.bump do |s| + s.platform = Gem::Platform.new 'x86-other_platform1' + end + + Gem::Specification.remove_spec @b2 + Gem::Specification.remove_spec @pl1 + + expected = %W[ + a-2 + a-2-x86-my_platform-1 + a-3-x86-other_platform-1 + a_evil-9 + c-1.2 + p-1 + #{p1_curr.full_name} + ] + + latest_specs = Gem::Specification.latest_specs.map(&:full_name).sort + + assert_equal expected, latest_specs + end + def util_setup_deps @gem = quick_spec "awesome", "1.0" do |awesome| awesome.add_runtime_dependency "bonobo", [] @@ -1322,13 +1390,36 @@ end def util_setup_validate Dir.chdir @tempdir do - FileUtils.mkdir_p File.join('ext', 'a') - FileUtils.mkdir_p 'lib' - FileUtils.mkdir_p 'test' + FileUtils.mkdir_p File.join("ext", "a") + FileUtils.mkdir_p "lib" + FileUtils.mkdir_p "test" + FileUtils.mkdir_p "bin" + + FileUtils.touch File.join("ext", "a", "extconf.rb") + FileUtils.touch File.join("lib", "code.rb") + FileUtils.touch File.join("test", "suite.rb") - FileUtils.touch File.join('ext', 'a', 'extconf.rb') - FileUtils.touch File.join('lib', 'code.rb') - FileUtils.touch File.join('test', 'suite.rb') + File.open "bin/exec", "w" do |fp| + fp.puts "#!#{Gem.ruby}" + end + end + end + + def with_syck + begin + require "yaml" + old_engine = YAML::ENGINE.yamler + YAML::ENGINE.yamler = 'syck' + rescue NameError + # probably on 1.8, ignore + end + + yield + ensure + begin + YAML::ENGINE.yamler = old_engine + rescue NameError + # ignore end end end diff --git a/test/rubygems/test_gem_text.rb b/test/rubygems/test_gem_text.rb index 775f1e9d12..7324e42b46 100644 --- a/test/rubygems/test_gem_text.rb +++ b/test/rubygems/test_gem_text.rb @@ -26,6 +26,21 @@ class TestGemText < Gem::TestCase assert_equal " text to wrap", format_text("text to wrap", 40, 2) end + def test_format_text_trailing # for two spaces after . + text = <<-TEXT +This line is really, really long. So long, in fact, that it is more than eighty characters long! The purpose of this line is for testing wrapping behavior because sometimes people don't wrap their text to eighty characters. Without the wrapping, the text might not look good in the RSS feed. + TEXT + + expected = <<-EXPECTED +This line is really, really long. So long, in fact, that it is more than +eighty characters long! The purpose of this line is for testing wrapping +behavior because sometimes people don't wrap their text to eighty characters. +Without the wrapping, the text might not look good in the RSS feed. + EXPECTED + + assert_equal expected, format_text(text, 78) + end + def test_levenshtein_distance_add assert_equal 2, levenshtein_distance("zentest", "zntst") assert_equal 2, levenshtein_distance("zntst", "zentest") diff --git a/test/rubygems/test_gem_uninstaller.rb b/test/rubygems/test_gem_uninstaller.rb index 0c08f42d01..93a6f6535b 100644 --- a/test/rubygems/test_gem_uninstaller.rb +++ b/test/rubygems/test_gem_uninstaller.rb @@ -14,26 +14,15 @@ class TestGemUninstaller < Gem::InstallerTestCase @user_spec.executables = ["executable"] - # HACK util_make_exec - user_bin_dir = File.join Gem.user_dir, 'gems', @user_spec.full_name, 'bin' - FileUtils.mkdir_p user_bin_dir - exec_path = File.join user_bin_dir, "executable" - open exec_path, 'w' do |f| - f.puts "#!/usr/bin/ruby" - end - - user_bin_dir = File.join Gem.user_dir, 'bin' - FileUtils.mkdir_p user_bin_dir - exec_path = File.join user_bin_dir, "executable" - open exec_path, 'w' do |f| - f.puts "#!/usr/bin/ruby" - end - build_rake_in do use_ui ui do @installer.install @user_installer.install - Gem::Uninstaller.new(@user_spec.name, :executables => false).uninstall + + Gem.use_paths @gemhome, Gem.user_dir + + @spec = Gem::Specification.find_by_name 'a' + @user_spec = Gem::Specification.find_by_name 'b' end end end @@ -44,6 +33,18 @@ class TestGemUninstaller < Gem::InstallerTestCase assert_match %r|/foo/bar$|, uninstaller.instance_variable_get(:@gem_home) end + def test_remove_all + uninstaller = Gem::Uninstaller.new nil + + ui = Gem::MockGemUi.new "y\n" + + use_ui ui do + uninstaller.remove_all [@spec] + end + + refute_path_exists @spec.gem_dir + end + def test_remove_executables_force_keep uninstaller = Gem::Uninstaller.new nil, :executables => false @@ -114,14 +115,13 @@ class TestGemUninstaller < Gem::InstallerTestCase end exec_path = File.join Gem.user_dir, 'bin', 'executable' - assert_equal false, File.exist?(exec_path), 'removed exec from bin dir' + refute File.exist?(exec_path), 'removed exec from bin dir' assert_equal "Removing executable\n", @ui.output ensure Gem::Installer.exec_format = nil end - def test_path_ok_eh uninstaller = Gem::Uninstaller.new nil @@ -131,7 +131,7 @@ class TestGemUninstaller < Gem::InstallerTestCase def test_path_ok_eh_legacy uninstaller = Gem::Uninstaller.new nil - @spec.loaded_from.gsub! @spec.full_name, '\&-legacy' + @spec.loaded_from = @spec.loaded_from.gsub @spec.full_name, '\&-legacy' @spec.platform = 'legacy' assert_equal true, uninstaller.path_ok?(@gemhome, @spec) @@ -190,26 +190,42 @@ class TestGemUninstaller < Gem::InstallerTestCase end def test_uninstall_user - uninstaller = Gem::Uninstaller.new @user_spec.name, :executables => true, - :user_install => true + @user_spec = Gem::Specification.find_by_name 'b' + + uninstaller = Gem::Uninstaller.new(@user_spec.name, + :executables => true, + :user_install => true) gem_dir = File.join Gem.user_dir, 'gems', @user_spec.full_name Gem.pre_uninstall do - assert File.exist?(gem_dir), 'gem_dir should exist' + assert_path_exists gem_dir end Gem.post_uninstall do - refute File.exist?(gem_dir), 'gem_dir should not exist' + refute_path_exists gem_dir end uninstaller.uninstall - refute File.exist?(gem_dir) + refute_path_exists gem_dir assert_same uninstaller, @pre_uninstall_hook_arg assert_same uninstaller, @post_uninstall_hook_arg end -end + def test_uninstall_selection_greater_than_one + util_make_gems + + list = Gem::Specification.find_all_by_name('a') + + uninstaller = Gem::Uninstaller.new('a') + + use_ui Gem::MockGemUi.new("2\n") do + uninstaller.uninstall + end + updated_list = Gem::Specification.find_all_by_name('a') + assert_equal list.length - 1, updated_list.length + end +end diff --git a/test/rubygems/test_kernel.rb b/test/rubygems/test_kernel.rb index d3714a2c59..32658c5543 100644 --- a/test/rubygems/test_kernel.rb +++ b/test/rubygems/test_kernel.rb @@ -46,10 +46,9 @@ class TestKernel < Gem::TestCase gem 'a', '= 2' end - assert_match(/activate a \(= 2\)/, ex.message) + assert_equal "can't activate a-2, already activated a-1", ex.message assert_match(/activated a-1/, ex.message) assert_equal 'a', ex.name - assert_equal Gem::Requirement.new('= 2'), ex.requirement assert $:.any? { |p| %r{a-1/lib} =~ p } refute $:.any? { |p| %r{a-2/lib} =~ p } -- cgit v1.2.3