diff --git a/ChangeLog b/ChangeLog index 2af603b700..6022c34e80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +Tue Nov 19 09:33:52 2013 Eric Hodel + + * lib/rubygems: Update to RubyGems master 6a3d9f9. Changes include: + + Compatibly renamed Gem::DependencyResolver to Gem::Resolver. + + Added support for git gems in gem.deps.rb and Gemfile. + + Fixed resolver bugs. + + * test/rubygems: ditto. + + * lib/rubygems/LICENSE.txt: Updated to license from RubyGems trunk. + [ruby-trunk - Bug #9086] + + * lib/rubygems/commands/which_command.rb: RubyGems now indicates + failure when any file is missing. [ruby-trunk - Bug #9004] + + * lib/rubygems/ext/builder: Extensions are now installed into the + extension install directory and the first directory in the require + path from the gem. This allows backwards compatibility with msgpack + and other gems that calculate full require paths. + [ruby-trunk - Bug #9106] + + Tue Nov 19 07:21:56 2013 Tanaka Akira * configure.in (LOCALTIME_OVERFLOW_PROBLEM): Define it for cross diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 1c84356bd7..2e8ad7bba1 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = '2.2.0' + VERSION = '2.2.0.preview.2' end # Must be first since it unloads the prelude from 1.9.2 @@ -302,7 +302,6 @@ module Gem # The path where gem executables are to be installed. def self.bindir(install_dir=Gem.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 @@ -362,16 +361,21 @@ module Gem Zlib::Deflate.deflate data end - # DOC: needs doc'd or :nodoc'd + # Retrieve the PathSupport object that RubyGems uses to + # lookup files. + def self.paths @paths ||= Gem::PathSupport.new end - # DOC: needs doc'd or :nodoc'd + # Initialize the filesystem paths to use from +env+. + # +env+ is a hash-like object (typically ENV) that + # is queried for 'GEM_HOME', 'GEM_PATH', and 'GEM_SPEC_CACHE' + def self.paths=(env) clear_paths @paths = Gem::PathSupport.new env - Gem::Specification.dirs = @paths.path # FIX: home is at end + Gem::Specification.dirs = @paths.path end ## @@ -380,12 +384,10 @@ module Gem # FIXME deprecate these once everything else has been done -ebh def self.dir - # TODO: raise "no" paths.home end def self.path - # TODO: raise "no" paths.path end @@ -552,42 +554,30 @@ module Gem private_class_method :find_home + # FIXME deprecate these in 3.0 + ## # Zlib::GzipReader wrapper that unzips +data+. def self.gunzip(data) - # TODO: move to utils - require 'stringio' - require 'zlib' - data = StringIO.new data - - unzipped = Zlib::GzipReader.new(data).read - unzipped.force_encoding Encoding::BINARY if Object.const_defined? :Encoding - unzipped + require 'rubygems/util' + Gem::Util.gunzip data end ## # Zlib::GzipWriter wrapper that zips +data+. def self.gzip(data) - # TODO: move to utils - require 'stringio' - require 'zlib' - zipped = StringIO.new - zipped.set_encoding Encoding::BINARY if Object.const_defined? :Encoding - - Zlib::GzipWriter.wrap zipped do |io| io.write data end - - zipped.string + require 'rubygems/util' + Gem::Util.gzip data end ## # A Zlib::Inflate#inflate wrapper def self.inflate(data) - # TODO: move to utils - require 'zlib' - Zlib::Inflate.inflate data + require 'rubygems/util' + Gem::Util.inflate data end ## @@ -693,7 +683,6 @@ module Gem file = $1 lineno = $2.to_i - # TODO: it is ALWAYS joined! STUPID! [file, lineno] end @@ -974,7 +963,6 @@ module Gem paths = nil if paths == [nil] paths = paths.first if Array === Array(paths).first self.paths = { "GEM_HOME" => home, "GEM_PATH" => paths } - # TODO: self.paths = home, paths end ## @@ -1169,7 +1157,8 @@ module Gem autoload :ConfigFile, 'rubygems/config_file' autoload :Dependency, 'rubygems/dependency' autoload :DependencyList, 'rubygems/dependency_list' - autoload :DependencyResolver, 'rubygems/dependency_resolver' + autoload :Resolver, 'rubygems/resolver' + autoload :DependencyResolver, 'rubygems/resolver' autoload :PathSupport, 'rubygems/path_support' autoload :Platform, 'rubygems/platform' autoload :RequestSet, 'rubygems/request_set' diff --git a/lib/rubygems/LICENSE.txt b/lib/rubygems/LICENSE.txt index db88c5e118..8a0a51dec1 100644 --- a/lib/rubygems/LICENSE.txt +++ b/lib/rubygems/LICENSE.txt @@ -1,53 +1,54 @@ RubyGems is copyrighted free software by Chad Fowler, Rich Kilmer, Jim Weirich and others. You can redistribute it and/or modify it under -either the terms of the GPL (see the GPL.txt file), or the conditions -below: +either the terms of the MIT license (see the file MIT.txt), or the +conditions below: - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. +1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: +2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: - a) place your modifications in the Public Domain or otherwise - make them Freely Available, such as by posting said - modifications to Usenet or an equivalent medium, or by allowing - the author to include your modifications in the software. + a. place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. - b) use the modified software only within your corporation or - organization. + b. use the modified software only within your corporation or + organization. - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided. + c. give non-standard executables non-standard names, with + instructions on where to get the original software distribution. - d) make other distribution arrangements with the author. + d. make other distribution arrangements with the author. - 3. You may distribute the software in object code or executable - form, provided that you do at least ONE of the following: +3. You may distribute the software in object code or executable + form, provided that you do at least ONE of the following: - a) distribute the executables and library files of the software, - together with instructions (in the manual page or equivalent) - on where to get the original distribution. + a. distribute the executables and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. - b) accompany the distribution with the machine-readable source of - the software. + b. accompany the distribution with the machine-readable source of + the software. - c) give non-standard executables non-standard names, with - instructions on where to get the original software distribution. + c. give non-standard executables non-standard names, with + instructions on where to get the original software distribution. - d) make other distribution arrangements with the author. + d. make other distribution arrangements with the author. - 4. You may modify and include the part of the software into any other - software (possibly commercial). +4. You may modify and include the part of the software into any other + software (possibly commercial). - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. +5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + +6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. diff --git a/lib/rubygems/available_set.rb b/lib/rubygems/available_set.rb index bb0b3a3abe..4ab4d77716 100644 --- a/lib/rubygems/available_set.rb +++ b/lib/rubygems/available_set.rb @@ -116,7 +116,7 @@ class Gem::AvailableSet ## # - # Used by the DependencyResolver, the protocol to use a AvailableSet as a + # Used by the Resolver, the protocol to use a AvailableSet as a # search Set. def find_all(req) @@ -127,7 +127,7 @@ class Gem::AvailableSet end match.map do |t| - Gem::DependencyResolver::InstalledSpecification.new(self, t.spec, t.source) + Gem::Resolver::InstalledSpecification.new(self, t.spec, t.source) end end diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb index a29ed0aa6d..4f96fcac3d 100644 --- a/lib/rubygems/basic_specification.rb +++ b/lib/rubygems/basic_specification.rb @@ -107,7 +107,7 @@ class Gem::BasicSpecification File.join full_gem_path, path end - full_paths << extension_install_dir unless @extensions.empty? + full_paths.unshift extension_install_dir unless @extensions.empty? full_paths end @@ -155,6 +155,10 @@ class Gem::BasicSpecification raise NotImplementedError end + def raw_require_paths # :nodoc: + @require_paths + end + ## # Paths in the gem to add to $LOAD_PATH when this gem is # activated. @@ -179,7 +183,7 @@ class Gem::BasicSpecification File.join '..', '..', 'extensions', Gem::Platform.local.to_s, Gem.extension_api_version, full_name - @require_paths + [relative_extension_install_dir] + [relative_extension_install_dir].concat @require_paths end ## diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index ad90b37fdc..68a2fad129 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -56,6 +56,12 @@ class Gem::Commands::InstallCommand < Gem::Command o[:install_as_default] = v end + add_option(:"Install/Update", '--explain', + 'Rather than install the gems, indicate which would', + 'be installed') do |v,o| + o[:explain] = v + end + @installed_specs = nil end @@ -185,8 +191,23 @@ to write the specification by hand. For example: return if options[:conservative] and not Gem::Dependency.new(name, version).matching_specs.empty? + req = Gem::Requirement.create(version) + inst = Gem::DependencyInstaller.new options - inst.install name, Gem::Requirement.create(version) + + if options[:explain] + request_set = inst.resolve_dependencies name, req + + puts "Gems to install:" + + request_set.specs.map { |s| s.full_name }.sort.each do |s| + puts " #{s}" + end + + return + else + inst.install name, req + end @installed_specs.push(*inst.installed_gems) diff --git a/lib/rubygems/commands/which_command.rb b/lib/rubygems/commands/which_command.rb index 18706afdf5..96eeb86288 100644 --- a/lib/rubygems/commands/which_command.rb +++ b/lib/rubygems/commands/which_command.rb @@ -35,7 +35,7 @@ requiring to see why it does not behave as you expect. end def execute - found = false + found = true options[:args].each do |arg| arg = arg.sub(/#{Regexp.union(*Gem.suffixes)}$/, '') @@ -56,9 +56,10 @@ requiring to see why it does not behave as you expect. if paths.empty? then alert_error "Can't find ruby library file or shared library #{arg}" + + found &&= false else say paths - found = true end end diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index 22ff6f5cb7..e404d42b3a 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -1,6 +1,5 @@ require 'rubygems' require 'rubygems/dependency_list' -require 'rubygems/dependency_resolver' require 'rubygems/package' require 'rubygems/installer' require 'rubygems/spec_fetcher' @@ -196,7 +195,7 @@ class Gem::DependencyInstaller # sources. Gems are sorted with newer gems preferred over older gems, and # local gems preferred over remote gems. - def find_gems_with_sources dep # :nodoc: + def find_gems_with_sources dep, best_only=false # :nodoc: set = Gem::AvailableSet.new if consider_local? @@ -211,7 +210,26 @@ class Gem::DependencyInstaller if consider_remote? begin - found, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep + # TODO this is pulled from #spec_for_dependency to allow + # us to filter tuples before fetching specs. + # + tuples, errors = Gem::SpecFetcher.fetcher.search_for_dependency dep + + if best_only && !tuples.empty? + tuples.sort! { |a,b| b[0].version <=> a[0].version } + tuples = [tuples.first] + end + + specs = [] + tuples.each do |tup, source| + begin + spec = source.fetch_spec(tup) + rescue Gem::RemoteFetcher::FetchError => e + errors << Gem::SourceFetchProblem.new(source, e) + else + specs << [spec, source] + end + end if @errors @errors += errors @@ -219,7 +237,7 @@ class Gem::DependencyInstaller @errors = errors end - set << found + set << specs rescue Gem::RemoteFetcher::FetchError => e # FIX if there is a problem talking to the network, we either need to always tell @@ -271,7 +289,7 @@ class Gem::DependencyInstaller dep = Gem::Dependency.new gem_name, version dep.prerelease = true if prerelease - set = find_gems_with_sources(dep) + set = find_gems_with_sources(dep, true) set.match_platform! end @@ -402,7 +420,7 @@ class Gem::DependencyInstaller request_set = as.to_request_set install_development_deps request_set.soft_missing = @force - installer_set = Gem::DependencyResolver::InstallerSet.new @domain + installer_set = Gem::Resolver::InstallerSet.new @domain installer_set.always_install.concat request_set.always_install installer_set.ignore_installed = @only_install_dir @@ -411,7 +429,7 @@ class Gem::DependencyInstaller request_set.soft_missing = true end - composed_set = Gem::DependencyResolver.compose_sets as, installer_set + composed_set = Gem::Resolver.compose_sets as, installer_set request_set.resolve composed_set diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb index 0de337f7de..2cb8901b4d 100644 --- a/lib/rubygems/doctor.rb +++ b/lib/rubygems/doctor.rb @@ -1,6 +1,5 @@ require 'rubygems' require 'rubygems/user_interaction' -require 'pathname' ## # Cleans up after a partially-failed uninstall or for an invalid @@ -39,7 +38,7 @@ class Gem::Doctor # If +dry_run+ is true no files or directories will be removed. def initialize gem_repository, dry_run = false - @gem_repository = Pathname(gem_repository) + @gem_repository = gem_repository @dry_run = dry_run @installed_specs = nil @@ -97,26 +96,29 @@ class Gem::Doctor # Removes files in +sub_directory+ with +extension+ def doctor_child sub_directory, extension # :nodoc: - directory = @gem_repository + sub_directory + directory = File.join(@gem_repository, sub_directory) - directory.children.sort.each do |child| - next unless child.exist? + Dir.entries(directory).sort.each do |ent| + next if ent == "." || ent == ".." - basename = child.basename(extension).to_s + child = File.join(directory, ent) + next unless File.exists?(child) + + basename = File.basename(child, extension) next if installed_specs.include? basename next if /^rubygems-\d/ =~ basename next if 'specifications' == sub_directory and 'default' == basename - type = child.directory? ? 'directory' : 'file' + type = File.directory?(child) ? 'directory' : 'file' action = if @dry_run then 'Extra' else - child.rmtree + FileUtils.rm_r(child) 'Removed' end - say "#{action} #{type} #{sub_directory}/#{child.basename}" + say "#{action} #{type} #{sub_directory}/#{File.basename(child)}" end rescue Errno::ENOENT # ignore diff --git a/lib/rubygems/errors.rb b/lib/rubygems/errors.rb index 3c5486a800..fc9bfbc0dc 100644 --- a/lib/rubygems/errors.rb +++ b/lib/rubygems/errors.rb @@ -73,12 +73,27 @@ module Gem # data from a source class SourceFetchProblem < ErrorReason + + ## + # Creates a new SourceFetchProblem for the given +source+ and +error+. + def initialize(source, error) @source = source @error = error end - attr_reader :source, :error + ## + # The source that had the fetch problem. + + attr_reader :source + + ## + # The fetch error which is an Exception subclass. + + attr_reader :error + + ## + # An English description of the error. def wordy "Unable to download data from #{@source.uri} - #{@error.message}" diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 6d92b144b6..ee3d8fecdf 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -23,7 +23,7 @@ class Gem::DependencyError < Gem::Exception; end class Gem::DependencyRemovalException < Gem::Exception; end ## -# Raised by Gem::DependencyResolver when a Gem::DependencyConflict reaches the +# Raised by Gem::Resolver when a Gem::Dependency::Conflict reaches the # toplevel. Indicates which dependencies were incompatible through #conflict # and #conflicting_dependencies @@ -117,7 +117,7 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException end ## -# Raised by Gem::DependencyResolver when dependencies conflict and create the +# Raised by Gem::Resolver when dependencies conflict and create the # inability to find a valid possible spec for a request. class Gem::ImpossibleDependenciesError < Gem::Exception @@ -211,20 +211,20 @@ class Gem::SystemExitException < SystemExit end ## -# Raised by DependencyResolver when a dependency requests a gem for which +# Raised by Resolver when a dependency requests a gem for which # there is no spec. class Gem::UnsatisfiableDependencyError < Gem::Exception ## # The unsatisfiable dependency. This is a - # Gem::DependencyResolver::DependencyRequest, not a Gem::Dependency + # Gem::Resolver::DependencyRequest, not a Gem::Dependency attr_reader :dependency ## # Creates a new UnsatisfiableDepedencyError for the unsatisfiable - # Gem::DependencyResolver::DependencyRequest +dep+ + # Gem::Resolver::DependencyRequest +dep+ def initialize dep, platform_mismatch=nil if platform_mismatch and !platform_mismatch.empty? diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 761505636c..e9244c760c 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -149,6 +149,7 @@ EOF extension ||= '' # I wish I knew why this line existed extension_dir = File.expand_path File.join @gem_dir, File.dirname(extension) + lib_dir = File.join @spec.full_gem_path, @spec.raw_require_paths.first builder = builder_for extension @@ -158,7 +159,7 @@ EOF CHDIR_MUTEX.synchronize do Dir.chdir extension_dir do results = builder.build(extension, @gem_dir, dest_path, - results, @build_args) + results, @build_args, lib_dir) say results.join("\n") if Gem.configuration.really_verbose end diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb index 17bd6c296e..24531bc75c 100644 --- a/lib/rubygems/ext/cmake_builder.rb +++ b/lib/rubygems/ext/cmake_builder.rb @@ -1,7 +1,7 @@ require 'rubygems/command' class Gem::Ext::CmakeBuilder < Gem::Ext::Builder - def self.build(extension, directory, dest_path, results) + def self.build(extension, directory, dest_path, results, args=[], lib_dir=nil) unless File.exist?('Makefile') then cmd = "cmake . -DCMAKE_INSTALL_PREFIX=#{dest_path}" cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty? diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb index 2a542e6bd0..f66e39387a 100644 --- a/lib/rubygems/ext/configure_builder.rb +++ b/lib/rubygems/ext/configure_builder.rb @@ -6,7 +6,7 @@ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder - def self.build(extension, directory, dest_path, results, args=[]) + def self.build(extension, directory, dest_path, results, args=[], lib_dir=nil) unless File.exist?('Makefile') then cmd = "sh ./configure --prefix=#{dest_path}" cmd << " #{args.join ' '}" unless args.empty? diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index 9a656a30a3..6e736d8062 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -10,7 +10,7 @@ require 'tempfile' class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder FileEntry = FileUtils::Entry_ # :nodoc: - def self.build(extension, directory, dest_path, results, args=[]) + def self.build(extension, directory, dest_path, results, args=[], lib_dir=nil) tmp_dest = Dir.mktmpdir(".gem.", ".") t = nil @@ -44,6 +44,12 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder if tmp_dest FileEntry.new(tmp_dest).traverse do |ent| + # TODO remove in RubyGems 3 + if lib_dir then + libent = ent.class.new lib_dir, ent.rel + libent.exist? or ent.copy libent.path + end + destent = ent.class.new(dest_path, ent.rel) destent.exist? or File.rename(ent.path, destent.path) end diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index 984c54bc1b..2093bcabdd 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -6,7 +6,7 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder - def self.build(extension, directory, dest_path, results, args=[]) + def self.build(extension, directory, dest_path, results, args=[], lib_dir=nil) if File.basename(extension) =~ /mkrf_conf/i then cmd = "#{Gem.ruby} #{File.basename extension}" cmd << " #{args.join " "}" unless args.empty? diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index b96c77033a..c6816e8f0f 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -90,7 +90,7 @@ class Gem::RemoteFetcher rescue Resolv::ResolvError uri else - URI.parse "#{res.target}#{uri.path}" + URI.parse "#{uri.scheme}://#{res.target}#{uri.path}" end end diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 3a997f32ee..42d457063f 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -1,6 +1,5 @@ require 'rubygems' require 'rubygems/dependency' -require 'rubygems/dependency_resolver' require 'rubygems/dependency_list' require 'rubygems/installer' require 'tsort' @@ -31,6 +30,11 @@ class Gem::RequestSet attr_accessor :development + ## + # The set of git gems imported via load_gemdeps. + + attr_reader :git_set # :nodoc: + ## # Sets used for resolution @@ -61,6 +65,7 @@ class Gem::RequestSet @always_install = [] @dependency_names = {} @development = false + @git_set = nil @requests = [] @sets = [] @soft_missing = false @@ -184,7 +189,8 @@ class Gem::RequestSet # Load a dependency management file. def load_gemdeps path, without_groups = [] - @vendor_set = Gem::DependencyResolver::VendorSet.new + @git_set = Gem::Resolver::GitSet.new + @vendor_set = Gem::Resolver::VendorSet.new gf = Gem::RequestSet::GemDependencyAPI.new self, path gf.without_groups = without_groups if without_groups @@ -195,13 +201,14 @@ class Gem::RequestSet # Resolve the requested dependencies and return an Array of Specification # objects to be activated. - def resolve set = Gem::DependencyResolver::IndexSet.new + def resolve set = Gem::Resolver::IndexSet.new @sets << set + @sets << @git_set @sets << @vendor_set - set = Gem::DependencyResolver.compose_sets(*@sets) + set = Gem::Resolver.compose_sets(*@sets) - resolver = Gem::DependencyResolver.new @dependencies, set + resolver = Gem::Resolver.new @dependencies, set resolver.development = @development resolver.soft_missing = @soft_missing @@ -213,7 +220,7 @@ class Gem::RequestSet # and return an Array of Specification objects to be activated. def resolve_current - resolve Gem::DependencyResolver::CurrentSet.new + resolve Gem::Resolver::CurrentSet.new end def sorted_requests diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb index e8f3138990..8e29eb87e5 100644 --- a/lib/rubygems/request_set/gem_dependency_api.rb +++ b/lib/rubygems/request_set/gem_dependency_api.rb @@ -107,6 +107,11 @@ class Gem::RequestSet::GemDependencyAPI :x64_mingw_21 => :only, } + ## + # A set of gems that are loaded via the +:git+ option to #gem + + attr_reader :git_set # :nodoc: + ## # A Hash containing gem names and files to require from those gems. @@ -130,13 +135,55 @@ class Gem::RequestSet::GemDependencyAPI @set = set @path = path - @current_groups = nil - @current_platform = nil - @default_sources = true - @requires = Hash.new { |h, name| h[name] = [] } - @vendor_set = @set.vendor_set - @gem_sources = {} - @without_groups = [] + @current_groups = nil + @current_platform = nil + @current_repository = nil + @default_sources = true + @git_set = @set.git_set + @requires = Hash.new { |h, name| h[name] = [] } + @vendor_set = @set.vendor_set + @gem_sources = {} + @without_groups = [] + end + + ## + # Adds +dependencies+ to the request set if any of the +groups+ are allowed. + # This is used for gemspec dependencies. + + def add_dependencies groups, dependencies # :nodoc: + return unless (groups & @without_groups).empty? + + dependencies.each do |dep| + @set.gem dep.name, *dep.requirement + end + end + + private :add_dependencies + + ## + # Finds a gemspec with the given +name+ that lives at +path+. + + def find_gemspec name, path # :nodoc: + glob = File.join path, "#{name}.gemspec" + + spec_files = Dir[glob] + + case spec_files.length + when 1 then + spec_file = spec_files.first + + spec = Gem::Specification.load spec_file + + return spec if spec + + raise ArgumentError, "invalid gemspec #{spec_file}" + when 0 then + raise ArgumentError, "no gemspecs found at #{Dir.pwd}" + else + raise ArgumentError, + "found multiple gemspecs at #{Dir.pwd}, " + + "use the name: option to specify the one you want" + end end ## @@ -160,7 +207,13 @@ class Gem::RequestSet::GemDependencyAPI options = requirements.pop if requirements.last.kind_of?(Hash) options ||= {} - source_set = gem_path name, options + options[:git] = @current_repository if @current_repository + + source_set = false + + source_set ||= gem_path name, options + source_set ||= gem_git name, options + source_set ||= gem_github name, options return unless gem_platforms options @@ -181,6 +234,54 @@ class Gem::RequestSet::GemDependencyAPI @set.gem name, *requirements end + ## + # Handles the git: option from +options+ for gem +name+. + # + # Returns +true+ if the path option was handled. + + def gem_git name, options # :nodoc: + if gist = options.delete(:gist) then + options[:git] = "https://gist.github.com/#{gist}.git" + end + + return unless repository = options.delete(:git) + + raise ArgumentError, + "duplicate source git: #{repository} for gem #{name}" if + @gem_sources.include? name + + reference = nil + reference ||= options.delete :ref + reference ||= options.delete :branch + reference ||= options.delete :tag + reference ||= 'master' + + submodules = options.delete :submodules + + @git_set.add_git_gem name, repository, reference, submodules + + @gem_sources[name] = repository + + true + end + + private :gem_git + + ## + # Handles the github: option from +options+ for gem +name+. + # + # Returns +true+ if the path option was handled. + + def gem_github name, options # :nodoc: + return unless path = options.delete(:github) + + options[:git] = "git://github.com/#{path}.git" + + gem_git name, options + + true + end + ## # Handles the :group and :groups +options+ for the gem with the given # +name+. @@ -269,6 +370,15 @@ class Gem::RequestSet::GemDependencyAPI private :gem_requires + def git repository + @current_repository = repository + + yield + + ensure + @current_repository = nil + end + ## # Returns the basename of the file the dependencies were loaded from @@ -276,6 +386,29 @@ class Gem::RequestSet::GemDependencyAPI File.basename @path end + ## + # :category: Gem Dependencies DSL + # + # Loads dependencies from a gemspec file. + + def gemspec options = {} + name = options.delete(:name) || '{,*}' + path = options.delete(:path) || '.' + development_group = options.delete(:development_group) || :development + + spec = find_gemspec name, path + + groups = gem_group spec.name, {} + + add_dependencies groups, spec.runtime_dependencies + + groups << development_group + + add_dependencies groups, spec.development_dependencies + + gem_requires spec.name, options + end + ## # :category: Gem Dependencies DSL # Block form for placing a dependency in the given +groups+. diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb index a9c419549d..0073bfdcc5 100644 --- a/lib/rubygems/request_set/lockfile.rb +++ b/lib/rubygems/request_set/lockfile.rb @@ -1,5 +1,3 @@ -require 'pathname' - class Gem::RequestSet::Lockfile ## @@ -46,8 +44,8 @@ class Gem::RequestSet::Lockfile def initialize request_set, gem_deps_file @set = request_set - @gem_deps_file = Pathname(gem_deps_file).expand_path - @gem_deps_dir = @gem_deps_file.dirname + @gem_deps_file = File.expand_path(gem_deps_file) + @gem_deps_dir = File.dirname(@gem_deps_file) @current_token = nil @line = 0 @@ -62,7 +60,7 @@ class Gem::RequestSet::Lockfile @set.dependencies.sort.map do |dependency| source = @requests.find do |req| req.name == dependency.name and - req.spec.class == Gem::DependencyResolver::VendorSpecification + req.spec.class == Gem::Resolver::VendorSpecification end source_dep = '!' if source @@ -102,15 +100,26 @@ class Gem::RequestSet::Lockfile out << nil end + def relative_path_from(dest, base) + dest = File.expand_path(dest) + base = File.expand_path(base) + + if dest.index(base) == 0 + return dest[base.size+1..-1] + else + dest + end + end + def add_PATH out # :nodoc: return unless path_requests = - @spec_groups.delete(Gem::DependencyResolver::VendorSpecification) + @spec_groups.delete(Gem::Resolver::VendorSpecification) out << "PATH" path_requests.each do |request| - directory = Pathname(request.spec.source.uri).expand_path + directory = File.expand_path(request.spec.source.uri) - out << " remote: #{directory.relative_path_from @gem_deps_dir}" + out << " remote: #{relative_path_from directory, @gem_deps_dir}" out << " specs:" out << " #{request.name} (#{request.version})" end @@ -208,7 +217,7 @@ class Gem::RequestSet::Lockfile skip :newline - set = Gem::DependencyResolver::LockSet.new source + set = Gem::Resolver::LockSet.new source while not @tokens.empty? and :text == peek.first do _, name, = get :text diff --git a/lib/rubygems/dependency_resolver.rb b/lib/rubygems/resolver.rb similarity index 78% rename from lib/rubygems/dependency_resolver.rb rename to lib/rubygems/resolver.rb index 35fbe925ad..2669cc4f24 100644 --- a/lib/rubygems/dependency_resolver.rb +++ b/lib/rubygems/resolver.rb @@ -12,7 +12,7 @@ require 'net/http' # objects which indicate all the specs that should be activated to meet the # all the requirements. -class Gem::DependencyResolver +class Gem::Resolver ## # Contains all the conflicts encountered while doing resolution @@ -38,20 +38,20 @@ class Gem::DependencyResolver when 1 then sets.first else - Gem::DependencyResolver::ComposedSet.new(*sets) + Gem::Resolver::ComposedSet.new(*sets) end end ## - # Provide a DependencyResolver that queries only against the already + # Provide a Resolver that queries only against the already # installed gems. def self.for_current_gems needed - new needed, Gem::DependencyResolver::CurrentSet.new + new needed, Gem::Resolver::CurrentSet.new end ## - # Create DependencyResolver object which will resolve the tree starting + # Create Resolver object which will resolve the tree starting # with +needed+ Dependency objects. # # +set+ is an object that provides where to look for specifications to @@ -59,7 +59,7 @@ class Gem::DependencyResolver # rubygems.org. def initialize needed, set = nil - @set = set || Gem::DependencyResolver::IndexSet.new + @set = set || Gem::Resolver::IndexSet.new @needed = needed @conflicts = [] @@ -68,6 +68,15 @@ class Gem::DependencyResolver @soft_missing = false end + DEBUG_RESOLVER = !ENV['DEBUG_RESOLVER'].nil? + + def explain(stage, *data) + if DEBUG_RESOLVER + d = data.map { |x| x.inspect }.join(", ") + STDOUT.printf "%20s %s\n", stage.to_s.upcase, d + end + end + ## # Creates an ActivationRequest for the given +dep+ and the last +possible+ # specification. @@ -77,8 +86,10 @@ class Gem::DependencyResolver def activation_request dep, possible # :nodoc: spec = possible.pop + explain :activate, [spec.full_name, possible.size] + activation_request = - Gem::DependencyResolver::ActivationRequest.new spec, dep, possible + Gem::Resolver::ActivationRequest.new spec, dep, possible return spec, activation_request end @@ -86,7 +97,7 @@ class Gem::DependencyResolver def requests s, act, reqs=nil s.dependencies.reverse_each do |d| next if d.type == :development and not @development - reqs = Gem::List.new Gem::DependencyResolver::DependencyRequest.new(d, act), reqs + reqs.add Gem::Resolver::DependencyRequest.new(d, act) end @set.prefetch reqs @@ -100,18 +111,18 @@ class Gem::DependencyResolver def resolve @conflicts = [] - needed = nil + needed = RequirementList.new @needed.reverse_each do |n| - request = Gem::DependencyResolver::DependencyRequest.new n, nil + request = Gem::Resolver::DependencyRequest.new n, nil - needed = Gem::List.new request, needed + needed.add request end res = resolve_for needed, nil raise Gem::DependencyResolutionError, res if - res.kind_of? Gem::DependencyResolver::DependencyConflict + res.kind_of? Gem::Resolver::Conflict res.to_a end @@ -128,6 +139,8 @@ class Gem::DependencyResolver until states.empty? do state = states.pop + explain :consider, state.dep, conflict.failed_dep + if conflict.for_spec? state.spec state.conflicts << [state.spec, conflict] return state @@ -162,11 +175,11 @@ class Gem::DependencyResolver # Otherwise, issue it on the requester's request itself. if existing.others_possible? or existing.request.requester.nil? then conflict = - Gem::DependencyResolver::DependencyConflict.new dep, existing + Gem::Resolver::Conflict.new dep, existing else - depreq = existing.request.requester.request + depreq = dep.requester.request conflict = - Gem::DependencyResolver::DependencyConflict.new depreq, existing, dep + Gem::Resolver::Conflict.new depreq, existing, dep end @conflicts << conflict unless @conflicts.include? conflict @@ -182,7 +195,7 @@ class Gem::DependencyResolver # +spec+ is the Specification for this state. # +possible+ is List of DependencyRequest objects that can be tried to # find a complete set. - # +conflicts+ is a [DependencyRequest, DependencyConflict] hit tried to + # +conflicts+ is a [DependencyRequest, Conflict] hit tried to # activate the state. # State = Struct.new(:needed, :specs, :dep, :spec, :possibles, :conflicts) do @@ -218,9 +231,9 @@ class Gem::DependencyResolver # The State objects that are used to attempt the activation tree. states = [] - while needed - dep = needed.value - needed = needed.tail + while !needed.empty? + dep = needed.remove + explain :try, [dep, dep.requester ? dep.requester.request : :toplevel] # If there is already a spec activated for the requested name... if specs && existing = specs.find { |s| dep.name == s.name } @@ -228,6 +241,7 @@ class Gem::DependencyResolver next if dep.matches_spec? existing conflict = handle_conflict dep, existing + explain :conflict, conflict.explain state = find_conflict_state conflict, states @@ -292,7 +306,9 @@ class Gem::DependencyResolver # We may need to try all of +possible+, so we setup state to unwind back # to current +needed+ and +specs+ so we can try another. This is code is # what makes conflict resolution possible. - states << State.new(needed, specs, dep, spec, possible, []) + states << State.new(needed.dup, specs, dep, spec, possible, []) + + explain :states, states.map { |s| s.dep } needed = requests spec, act, needed specs = Gem::List.prepend specs, act @@ -341,24 +357,32 @@ class Gem::DependencyResolver end -require 'rubygems/dependency_resolver/activation_request' -require 'rubygems/dependency_resolver/dependency_conflict' -require 'rubygems/dependency_resolver/dependency_request' +## +# TODO remove in RubyGems 3 -require 'rubygems/dependency_resolver/set' -require 'rubygems/dependency_resolver/api_set' -require 'rubygems/dependency_resolver/composed_set' -require 'rubygems/dependency_resolver/best_set' -require 'rubygems/dependency_resolver/current_set' -require 'rubygems/dependency_resolver/index_set' -require 'rubygems/dependency_resolver/installer_set' -require 'rubygems/dependency_resolver/lock_set' -require 'rubygems/dependency_resolver/vendor_set' +Gem::DependencyResolver = Gem::Resolver # :nodoc: -require 'rubygems/dependency_resolver/specification' -require 'rubygems/dependency_resolver/spec_specification' -require 'rubygems/dependency_resolver/api_specification' -require 'rubygems/dependency_resolver/index_specification' -require 'rubygems/dependency_resolver/installed_specification' -require 'rubygems/dependency_resolver/vendor_specification' +require 'rubygems/resolver/activation_request' +require 'rubygems/resolver/conflict' +require 'rubygems/resolver/dependency_request' +require 'rubygems/resolver/requirement_list' + +require 'rubygems/resolver/set' +require 'rubygems/resolver/api_set' +require 'rubygems/resolver/composed_set' +require 'rubygems/resolver/best_set' +require 'rubygems/resolver/current_set' +require 'rubygems/resolver/git_set' +require 'rubygems/resolver/index_set' +require 'rubygems/resolver/installer_set' +require 'rubygems/resolver/lock_set' +require 'rubygems/resolver/vendor_set' + +require 'rubygems/resolver/specification' +require 'rubygems/resolver/spec_specification' +require 'rubygems/resolver/api_specification' +require 'rubygems/resolver/git_specification' +require 'rubygems/resolver/index_specification' +require 'rubygems/resolver/installed_specification' +require 'rubygems/resolver/vendor_specification' diff --git a/lib/rubygems/dependency_resolver/activation_request.rb b/lib/rubygems/resolver/activation_request.rb similarity index 94% rename from lib/rubygems/dependency_resolver/activation_request.rb rename to lib/rubygems/resolver/activation_request.rb index c5d1e24d85..ca82ac408a 100644 --- a/lib/rubygems/dependency_resolver/activation_request.rb +++ b/lib/rubygems/resolver/activation_request.rb @@ -3,7 +3,7 @@ # Also contains a dependency that was used to introduce this # activation. -class Gem::DependencyResolver::ActivationRequest +class Gem::Resolver::ActivationRequest attr_reader :request @@ -19,7 +19,7 @@ class Gem::DependencyResolver::ActivationRequest case other when Gem::Specification @spec == other - when Gem::DependencyResolver::ActivationRequest + when Gem::Resolver::ActivationRequest @spec == other.spec && @request == other.request else false @@ -70,7 +70,7 @@ class Gem::DependencyResolver::ActivationRequest def installed? case @spec - when Gem::DependencyResolver::VendorSpecification then + when Gem::Resolver::VendorSpecification then true else this_spec = full_spec diff --git a/lib/rubygems/dependency_resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb similarity index 91% rename from lib/rubygems/dependency_resolver/api_set.rb rename to lib/rubygems/resolver/api_set.rb index 9dd34562b1..60bf911063 100644 --- a/lib/rubygems/dependency_resolver/api_set.rb +++ b/lib/rubygems/resolver/api_set.rb @@ -2,7 +2,7 @@ # The global rubygems pool, available via the rubygems.org API. # Returns instances of APISpecification. -class Gem::DependencyResolver::APISet < Gem::DependencyResolver::Set +class Gem::Resolver::APISet < Gem::Resolver::Set ## # The URI for the dependency API this APISet uses. @@ -28,7 +28,7 @@ class Gem::DependencyResolver::APISet < Gem::DependencyResolver::Set versions(req.name).each do |ver| if req.dependency.match? req.name, ver[:number] - res << Gem::DependencyResolver::APISpecification.new(self, ver) + res << Gem::Resolver::APISpecification.new(self, ver) end end diff --git a/lib/rubygems/dependency_resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb similarity index 91% rename from lib/rubygems/dependency_resolver/api_specification.rb rename to lib/rubygems/resolver/api_specification.rb index 5178d7c28e..19611e17d8 100644 --- a/lib/rubygems/dependency_resolver/api_specification.rb +++ b/lib/rubygems/resolver/api_specification.rb @@ -4,7 +4,7 @@ # This is used to avoid loading the full Specification object when all we need # is the name, version, and dependencies. -class Gem::DependencyResolver::APISpecification < Gem::DependencyResolver::Specification +class Gem::Resolver::APISpecification < Gem::Resolver::Specification ## # Creates an APISpecification for the given +set+ from the rubygems.org diff --git a/lib/rubygems/dependency_resolver/best_set.rb b/lib/rubygems/resolver/best_set.rb similarity index 83% rename from lib/rubygems/dependency_resolver/best_set.rb rename to lib/rubygems/resolver/best_set.rb index 987eea552e..533a0db58f 100644 --- a/lib/rubygems/dependency_resolver/best_set.rb +++ b/lib/rubygems/resolver/best_set.rb @@ -3,7 +3,7 @@ # # It combines IndexSet and APISet -class Gem::DependencyResolver::BestSet < Gem::DependencyResolver::ComposedSet +class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet ## # Creates a BestSet for the given +sources+ or Gem::sources if none are diff --git a/lib/rubygems/dependency_resolver/composed_set.rb b/lib/rubygems/resolver/composed_set.rb similarity index 76% rename from lib/rubygems/dependency_resolver/composed_set.rb rename to lib/rubygems/resolver/composed_set.rb index aeecf047b8..e4aa15e4d0 100644 --- a/lib/rubygems/dependency_resolver/composed_set.rb +++ b/lib/rubygems/resolver/composed_set.rb @@ -1,4 +1,4 @@ -class Gem::DependencyResolver::ComposedSet < Gem::DependencyResolver::Set +class Gem::Resolver::ComposedSet < Gem::Resolver::Set attr_reader :sets # :nodoc: diff --git a/lib/rubygems/dependency_resolver/dependency_conflict.rb b/lib/rubygems/resolver/conflict.rb similarity index 91% rename from lib/rubygems/dependency_resolver/dependency_conflict.rb rename to lib/rubygems/resolver/conflict.rb index 092f000cdb..b081972658 100644 --- a/lib/rubygems/dependency_resolver/dependency_conflict.rb +++ b/lib/rubygems/resolver/conflict.rb @@ -2,7 +2,7 @@ # Used internally to indicate that a dependency conflicted # with a spec that would be activated. -class Gem::DependencyResolver::DependencyConflict +class Gem::Resolver::Conflict attr_reader :activated @@ -23,6 +23,10 @@ class Gem::DependencyResolver::DependencyConflict @failed_dep == other.failed_dep end + def explain + "" + end + ## # Return the 2 dependency objects that conflicted @@ -94,3 +98,5 @@ class Gem::DependencyResolver::DependencyConflict end +Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict + diff --git a/lib/rubygems/dependency_resolver/current_set.rb b/lib/rubygems/resolver/current_set.rb similarity index 73% rename from lib/rubygems/dependency_resolver/current_set.rb rename to lib/rubygems/resolver/current_set.rb index ef15c9d7f3..4e8d34026b 100644 --- a/lib/rubygems/dependency_resolver/current_set.rb +++ b/lib/rubygems/resolver/current_set.rb @@ -3,7 +3,7 @@ # all the normal settings that control where to look # for installed gems. -class Gem::DependencyResolver::CurrentSet < Gem::DependencyResolver::Set +class Gem::Resolver::CurrentSet < Gem::Resolver::Set def find_all req req.dependency.matching_specs diff --git a/lib/rubygems/dependency_resolver/dependency_request.rb b/lib/rubygems/resolver/dependency_request.rb similarity index 92% rename from lib/rubygems/dependency_resolver/dependency_request.rb rename to lib/rubygems/resolver/dependency_request.rb index 36b77ab558..e63b443c62 100644 --- a/lib/rubygems/dependency_resolver/dependency_request.rb +++ b/lib/rubygems/resolver/dependency_request.rb @@ -2,7 +2,7 @@ # Used Internally. Wraps a Dependency object to also track which spec # contained the Dependency. -class Gem::DependencyResolver::DependencyRequest +class Gem::Resolver::DependencyRequest attr_reader :dependency @@ -17,7 +17,7 @@ class Gem::DependencyResolver::DependencyRequest case other when Gem::Dependency @dependency == other - when Gem::DependencyResolver::DependencyRequest + when Gem::Resolver::DependencyRequest @dependency == other.dependency && @requester == other.requester else false diff --git a/lib/rubygems/resolver/git_set.rb b/lib/rubygems/resolver/git_set.rb new file mode 100644 index 0000000000..3c38d3dca0 --- /dev/null +++ b/lib/rubygems/resolver/git_set.rb @@ -0,0 +1,81 @@ +## +# A GitSet represents gems that are sourced from git repositories. +# +# This is used for gem dependency file support. +# +# Example: +# +# set = Gem::Resolver::GitSet.new +# set.add_git_gem 'rake', 'git://example/rake.git', tag: 'rake-10.1.0' + +class Gem::Resolver::GitSet < Gem::Resolver::Set + + ## + # Contains repositories needing submodules + + attr_reader :need_submodules # :nodoc: + + ## + # A Hash containing git gem names for keys and a Hash of repository and + # git commit reference as values. + + attr_reader :repositories # :nodoc: + + ## + # A hash of gem names to Gem::Resolver::GitSpecifications + + attr_reader :specs # :nodoc: + + def initialize # :nodoc: + @git = ENV['git'] || 'git' + @need_submodules = {} + @repositories = {} + @specs = {} + end + + def add_git_gem name, repository, reference, submodules # :nodoc: + @repositories[name] = [repository, reference] + @need_submodules[repository] = submodules + end + + ## + # Finds all git gems matching +req+ + + def find_all req + @repositories.keys.select do |name| + name == req.name + end.map do |name| + @specs[name] || load_spec(name) + end.select do |spec| + req.matches_spec? spec + end + end + + def load_spec name + repository, reference = @repositories[name] + + source = Gem::Source::Git.new name, repository, reference + + spec = source.load_spec name + + git_spec = + Gem::Resolver::GitSpecification.new self, spec, source + + @specs[name] = git_spec + end + + ## + # Prefetches specifications from the git repositories in this set. + + def prefetch reqs + names = reqs.map { |req| req.name } + + @repositories.each_key do |name| + next unless names.include? name + + load_spec name + end + end + +end + diff --git a/lib/rubygems/resolver/git_specification.rb b/lib/rubygems/resolver/git_specification.rb new file mode 100644 index 0000000000..ac8d4e9aeb --- /dev/null +++ b/lib/rubygems/resolver/git_specification.rb @@ -0,0 +1,16 @@ +## +# A GitSpecification represents a gem that is sourced from a git repository +# and is being loaded through a gem dependencies file through the +git:+ +# option. + +class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification + + def == other # :nodoc: + self.class === other and + @set == other.set and + @spec == other.spec and + @source == other.source + end + +end + diff --git a/lib/rubygems/dependency_resolver/index_set.rb b/lib/rubygems/resolver/index_set.rb similarity index 85% rename from lib/rubygems/dependency_resolver/index_set.rb rename to lib/rubygems/resolver/index_set.rb index 04d6ec816f..0ba3c78a44 100644 --- a/lib/rubygems/dependency_resolver/index_set.rb +++ b/lib/rubygems/resolver/index_set.rb @@ -2,7 +2,7 @@ # The global rubygems pool represented via the traditional # source index. -class Gem::DependencyResolver::IndexSet < Gem::DependencyResolver::Set +class Gem::Resolver::IndexSet < Gem::Resolver::Set def initialize source = nil # :nodoc: @f = @@ -38,7 +38,7 @@ class Gem::DependencyResolver::IndexSet < Gem::DependencyResolver::Set @all[name].each do |uri, n| if req.dependency.match? n then - res << Gem::DependencyResolver::IndexSpecification.new( + res << Gem::Resolver::IndexSpecification.new( self, n.name, n.version, uri, n.platform) end end diff --git a/lib/rubygems/dependency_resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb similarity index 93% rename from lib/rubygems/dependency_resolver/index_specification.rb rename to lib/rubygems/resolver/index_specification.rb index 9b4057f0c8..56fecb5753 100644 --- a/lib/rubygems/dependency_resolver/index_specification.rb +++ b/lib/rubygems/resolver/index_specification.rb @@ -3,7 +3,7 @@ # delay needed to download full Specification objects when only the +name+ # and +version+ are needed. -class Gem::DependencyResolver::IndexSpecification < Gem::DependencyResolver::Specification +class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification ## # An IndexSpecification is created from the index format described in `gem diff --git a/lib/rubygems/dependency_resolver/installed_specification.rb b/lib/rubygems/resolver/installed_specification.rb similarity index 87% rename from lib/rubygems/dependency_resolver/installed_specification.rb rename to lib/rubygems/resolver/installed_specification.rb index 4b591661a8..647ff7499a 100644 --- a/lib/rubygems/dependency_resolver/installed_specification.rb +++ b/lib/rubygems/resolver/installed_specification.rb @@ -2,7 +2,7 @@ # An InstalledSpecification represents a gem that is already installed # locally. -class Gem::DependencyResolver::InstalledSpecification < Gem::DependencyResolver::SpecSpecification +class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification def == other # :nodoc: self.class === other and diff --git a/lib/rubygems/dependency_resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb similarity index 91% rename from lib/rubygems/dependency_resolver/installer_set.rb rename to lib/rubygems/resolver/installer_set.rb index 801b60a8bb..73d9e39651 100644 --- a/lib/rubygems/dependency_resolver/installer_set.rb +++ b/lib/rubygems/resolver/installer_set.rb @@ -2,7 +2,7 @@ # A set of gems for installation sourced from remote sources and local .gem # files -class Gem::DependencyResolver::InstallerSet < Gem::DependencyResolver::Set +class Gem::Resolver::InstallerSet < Gem::Resolver::Set ## # List of Gem::Specification objects that must always be installed. @@ -64,14 +64,14 @@ class Gem::DependencyResolver::InstallerSet < Gem::DependencyResolver::Set dep.matching_specs.each do |gemspec| next if @always_install.include? gemspec - res << Gem::DependencyResolver::InstalledSpecification.new(self, gemspec) + res << Gem::Resolver::InstalledSpecification.new(self, gemspec) end unless @ignore_installed if consider_local? then local_source = Gem::Source::Local.new if spec = local_source.find_gem(name, dep.requirement) then - res << Gem::DependencyResolver::IndexSpecification.new( + res << Gem::Resolver::IndexSpecification.new( self, spec.name, spec.version, local_source, spec.platform) end end @@ -81,7 +81,7 @@ class Gem::DependencyResolver::InstallerSet < Gem::DependencyResolver::Set @all[name].each do |remote_source, n| if dep.match? n then - res << Gem::DependencyResolver::IndexSpecification.new( + res << Gem::Resolver::IndexSpecification.new( self, n.name, n.version, remote_source, n.platform) end end diff --git a/lib/rubygems/dependency_resolver/lock_set.rb b/lib/rubygems/resolver/lock_set.rb similarity index 84% rename from lib/rubygems/dependency_resolver/lock_set.rb rename to lib/rubygems/resolver/lock_set.rb index f95c7f0fd6..6885e70945 100644 --- a/lib/rubygems/dependency_resolver/lock_set.rb +++ b/lib/rubygems/resolver/lock_set.rb @@ -1,7 +1,7 @@ ## # A set of gems from a gem dependencies lockfile. -class Gem::DependencyResolver::LockSet < Gem::DependencyResolver::Set +class Gem::Resolver::LockSet < Gem::Resolver::Set attr_reader :specs # :nodoc: @@ -24,8 +24,8 @@ class Gem::DependencyResolver::LockSet < Gem::DependencyResolver::Set version = Gem::Version.new version spec = - Gem::DependencyResolver::IndexSpecification.new self, name, version, - @source, platform + Gem::Resolver::IndexSpecification.new self, name, version, @source, + platform @specs << spec end diff --git a/lib/rubygems/resolver/requirement_list.rb b/lib/rubygems/resolver/requirement_list.rb new file mode 100644 index 0000000000..8123e84fc7 --- /dev/null +++ b/lib/rubygems/resolver/requirement_list.rb @@ -0,0 +1,40 @@ +## +# Used internally to hold the requirements being considered +# while attempting to find a proper activation set. + +class Gem::Resolver::RequirementList + + include Enumerable + + def initialize + @list = [] + end + + def initialize_copy(other) + @list = @list.dup + end + + def add(req) + @list.push req + req + end + + ## + # Enumerates requirements in the list + + def each # :nodoc: + return enum_for __method__ unless block_given? + + @list.each do |requirement| + yield requirement + end + end + + def empty? + @list.empty? + end + + def remove + @list.shift + end +end diff --git a/lib/rubygems/dependency_resolver/set.rb b/lib/rubygems/resolver/set.rb similarity index 64% rename from lib/rubygems/dependency_resolver/set.rb rename to lib/rubygems/resolver/set.rb index 65801871ac..32c137ef6b 100644 --- a/lib/rubygems/dependency_resolver/set.rb +++ b/lib/rubygems/resolver/set.rb @@ -1,13 +1,12 @@ ## -# DependencyResolver sets are used to look up specifications (and their +# Resolver sets are used to look up specifications (and their # dependencies) used in resolution. This set is abstract. -class Gem::DependencyResolver::Set +class Gem::Resolver::Set ## - # The find_all method must be implemented. It returns all - # DependencyResolver Specification objects matching the given - # DependencyRequest +req+. + # The find_all method must be implemented. It returns all Resolver + # Specification objects matching the given DependencyRequest +req+. def find_all req raise NotImplementedError diff --git a/lib/rubygems/dependency_resolver/spec_specification.rb b/lib/rubygems/resolver/spec_specification.rb similarity index 78% rename from lib/rubygems/dependency_resolver/spec_specification.rb rename to lib/rubygems/resolver/spec_specification.rb index cca1d58b9f..0c411bdf5f 100644 --- a/lib/rubygems/dependency_resolver/spec_specification.rb +++ b/lib/rubygems/resolver/spec_specification.rb @@ -1,8 +1,8 @@ ## -# The DependencyResolver::SpecSpecification contains common functionality for -# DependencyResolver specifications that are backed by a Gem::Specification. +# The Resolver::SpecSpecification contains common functionality for +# Resolver specifications that are backed by a Gem::Specification. -class Gem::DependencyResolver::SpecSpecification < Gem::DependencyResolver::Specification +class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification attr_reader :spec # :nodoc: diff --git a/lib/rubygems/dependency_resolver/specification.rb b/lib/rubygems/resolver/specification.rb similarity index 89% rename from lib/rubygems/dependency_resolver/specification.rb rename to lib/rubygems/resolver/specification.rb index 6fbd241316..7dd4c2e829 100644 --- a/lib/rubygems/dependency_resolver/specification.rb +++ b/lib/rubygems/resolver/specification.rb @@ -1,9 +1,9 @@ ## -# A DependencyResolver::Specification contains a subset of the information +# A Resolver::Specification contains a subset of the information # contained in a Gem::Specification. Only the information necessary for # dependency resolution in the resolver is included. -class Gem::DependencyResolver::Specification +class Gem::Resolver::Specification ## # The dependencies of the gem for this specification diff --git a/lib/rubygems/dependency_resolver/vendor_set.rb b/lib/rubygems/resolver/vendor_set.rb similarity index 88% rename from lib/rubygems/dependency_resolver/vendor_set.rb rename to lib/rubygems/resolver/vendor_set.rb index 87eb6fd818..e9cbcd8303 100644 --- a/lib/rubygems/dependency_resolver/vendor_set.rb +++ b/lib/rubygems/resolver/vendor_set.rb @@ -6,14 +6,14 @@ # # Example: # -# set = Gem::DependencyResolver::VendorSet.new +# set = Gem::Resolver::VendorSet.new # # set.add_vendor_gem 'rake', 'vendor/rake' # # The directory vendor/rake must contain an unpacked rake gem along with a # rake.gemspec (watching the given name). -class Gem::DependencyResolver::VendorSet < Gem::DependencyResolver::Set +class Gem::Resolver::VendorSet < Gem::Resolver::Set def initialize # :nodoc: @directories = {} @@ -47,7 +47,7 @@ class Gem::DependencyResolver::VendorSet < Gem::DependencyResolver::Set req.matches_spec? spec end.map do |spec| source = Gem::Source::Vendor.new @directories[spec] - Gem::DependencyResolver::VendorSpecification.new self, spec, source + Gem::Resolver::VendorSpecification.new self, spec, source end end diff --git a/lib/rubygems/dependency_resolver/vendor_specification.rb b/lib/rubygems/resolver/vendor_specification.rb similarity index 77% rename from lib/rubygems/dependency_resolver/vendor_specification.rb rename to lib/rubygems/resolver/vendor_specification.rb index 27b2fd6df2..24e033d084 100644 --- a/lib/rubygems/dependency_resolver/vendor_specification.rb +++ b/lib/rubygems/resolver/vendor_specification.rb @@ -3,7 +3,7 @@ # and is being loaded through a gem dependencies file through the +path:+ # option. -class Gem::DependencyResolver::VendorSpecification < Gem::DependencyResolver::SpecSpecification +class Gem::Resolver::VendorSpecification < Gem::Resolver::SpecSpecification def == other # :nodoc: self.class === other and diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index b39b3ae69d..a40a27594b 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -28,7 +28,9 @@ class Gem::Source case other when Gem::Source::Installed, Gem::Source::Local, - Gem::Source::SpecificFile then + Gem::Source::SpecificFile, + Gem::Source::Git, + Gem::Source::Vendor then -1 when Gem::Source then if !@uri @@ -62,9 +64,9 @@ class Gem::Source fetcher = Gem::RemoteFetcher.fetcher fetcher.fetch_path bundler_api_uri, nil, true rescue Gem::RemoteFetcher::FetchError - Gem::DependencyResolver::IndexSet.new self + Gem::Resolver::IndexSet.new self else - Gem::DependencyResolver::APISet.new bundler_api_uri + Gem::Resolver::APISet.new bundler_api_uri end end @@ -90,12 +92,15 @@ class Gem::Source end end - def fetch_spec(name) + ## + # Fetches a specification for the given +name_tuple+. + + def fetch_spec name_tuple fetcher = Gem::RemoteFetcher.fetcher - spec_file_name = name.spec_name + spec_file_name = name_tuple.spec_name - uri = @uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" + uri = api_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir uri @@ -139,7 +144,7 @@ class Gem::Source file = FILES[type] fetcher = Gem::RemoteFetcher.fetcher file_name = "#{file}.#{Gem.marshal_version}" - spec_path = @uri + "#{file_name}.gz" + spec_path = api_uri + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) retried = false @@ -163,18 +168,22 @@ class Gem::Source def download(spec, dir=Dir.pwd) fetcher = Gem::RemoteFetcher.fetcher - fetcher.download spec, @uri.to_s, dir + fetcher.download spec, api_uri.to_s, dir end def pretty_print q # :nodoc: q.group 2, '[Remote:', ']' do q.breakable q.text @uri.to_s + if api = api_uri + g.text api + end end end end +require 'rubygems/source/git' require 'rubygems/source/installed' require 'rubygems/source/specific_file' require 'rubygems/source/local' diff --git a/lib/rubygems/source/git.rb b/lib/rubygems/source/git.rb new file mode 100644 index 0000000000..8453aa5fd7 --- /dev/null +++ b/lib/rubygems/source/git.rb @@ -0,0 +1,189 @@ +require 'digest' +require 'rubygems/util' + +## +# A git gem for use in a gem dependencies file. +# +# Example: +# +# source = +# Gem::Source::Git.new 'rake', 'git@example:rake.git', 'rake-10.1.0', false +# +# spec = source.load_spec 'rake' +# +# source.checkout + +class Gem::Source::Git < Gem::Source + + ## + # The name of the gem created by this git gem. + + attr_reader :name + + ## + # The commit reference used for checking out this git gem. + + attr_reader :reference + + ## + # The git repository this gem is sourced from. + + attr_reader :repository + + ## + # Does this repository need submodules checked out too? + + attr_reader :need_submodules + + ## + # Creates a new git gem source for a gem with the given +name+ that will be + # loaded from +reference+ in +repository+. If +submodules+ is true, + # submodules will be checked out when the gem is installed. + + def initialize name, repository, reference, submodules = false + super(nil) + + @name = name + @repository = repository + @reference = reference + @need_submodules = submodules + + @git = ENV['git'] || 'git' + end + + def <=> other + case other + when Gem::Source::Git then + 0 + when Gem::Source::Installed then + -1 + when Gem::Source then + 1 + else + nil + end + end + + def == other # :nodoc: + super and + @name == other.name and + @repository == other.repository and + @reference == other.reference and + @need_submodules == other.need_submodules + end + + ## + # Checks out the files for the repository into the install_dir. + + def checkout # :nodoc: + cache + + unless File.exist? install_dir then + system @git, 'clone', '--quiet', '--no-checkout', + repo_cache_dir, install_dir + end + + Dir.chdir install_dir do + system @git, 'fetch', '--quiet', '--force', '--tags', install_dir + + success = system @git, 'reset', '--quiet', '--hard', @reference + + success &&= + system @git, 'submodule', 'update', + '--quiet', '--init', '--recursive' if @need_submodules + + success + end + end + + ## + # Creates a local cache repository for the git gem. + + def cache # :nodoc: + if File.exist? repo_cache_dir then + Dir.chdir repo_cache_dir do + system @git, 'fetch', '--quiet', '--force', '--tags', + @repository, 'refs/heads/*:refs/heads/*' + end + else + system @git, 'clone', '--quiet', '--bare', '--no-hardlinks', + @repository, repo_cache_dir + end + end + + ## + # A short reference for use in git gem directories + + def dir_shortref # :nodoc: + rev_parse[0..11] + end + + ## + # The directory where the git gem will be installed. + + def install_dir # :nodoc: + File.join Gem.dir, 'bundler', 'gems', "#{@name}-#{dir_shortref}" + end + + ## + # Loads a Gem::Specification for +name+ from this git repository. + + def load_spec name + cache + + gemspec_reference = "#{@reference}:#{name}.gemspec" + + Dir.chdir repo_cache_dir do + source = Gem::Util.popen @git, 'show', gemspec_reference + + source.force_encoding Encoding::UTF_8 if Object.const_defined? :Encoding + source.untaint + + begin + spec = eval source, binding, gemspec_reference + + return spec if Gem::Specification === spec + + warn "git gem specification for #{@repository} #{gemspec_reference} is not a Gem::Specification (#{spec.class} instead)." + rescue SignalException, SystemExit + raise + rescue SyntaxError, Exception + warn "invalid git gem specification for #{@repository} #{gemspec_reference}" + end + end + end + + ## + # The directory where the git gem's repository will be cached. + + def repo_cache_dir # :nodoc: + File.join Gem.dir, 'cache', 'bundler', 'git', "#{@name}-#{uri_hash}" + end + + ## + # Converts the git reference for the repository into a commit hash. + + def rev_parse # :nodoc: + # HACK no safe equivalent of ` exists on 1.8.7 + Dir.chdir repo_cache_dir do + Gem::Util.popen(@git, 'rev-parse', @reference).strip + end + end + + ## + # A hash for the git gem based on the git repository URI. + + def uri_hash # :nodoc: + normalized = + if @repository =~ %r%^\w+://(\w+@)?% then + uri = URI(@repository).normalize.to_s.sub %r%/$%,'' + uri.sub(/\A(\w+)/) { $1.downcase } + else + @repository + end + + Digest::SHA1.hexdigest normalized + end + +end + diff --git a/lib/rubygems/source/installed.rb b/lib/rubygems/source/installed.rb index 8e3a3560bf..2661dd6844 100644 --- a/lib/rubygems/source/installed.rb +++ b/lib/rubygems/source/installed.rb @@ -1,6 +1,9 @@ +## +# Represents an installed gem. This is used for dependency resolution. + class Gem::Source::Installed < Gem::Source - def initialize + def initialize # :nodoc: @uri = nil end @@ -9,6 +12,8 @@ class Gem::Source::Installed < Gem::Source def <=> other case other + when Gem::Source::Vendor then + -1 when Gem::Source::Installed then 0 when Gem::Source then diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb index 16a028b2f3..3aae20c8ed 100644 --- a/lib/rubygems/source/local.rb +++ b/lib/rubygems/source/local.rb @@ -1,5 +1,10 @@ +## +# The local source finds gems in the current directory for fulfilling +# dependencies. + class Gem::Source::Local < Gem::Source - def initialize + + def initialize # :nodoc: @specs = nil @api_uri = nil @uri = nil @@ -26,7 +31,7 @@ class Gem::Source::Local < Gem::Source "#<%s specs: %p>" % [self.class, keys] end - def load_specs(type) + def load_specs type # :nodoc: names = [] @specs = {} @@ -68,8 +73,8 @@ class Gem::Source::Local < Gem::Source names end - def find_gem(gem_name, version=Gem::Requirement.default, - prerelease=false) + def find_gem gem_name, version = Gem::Requirement.default, # :nodoc: + prerelease = false load_specs :complete found = [] @@ -91,7 +96,7 @@ class Gem::Source::Local < Gem::Source found.max_by { |s| s.version } end - def fetch_spec(name) + def fetch_spec name # :nodoc: load_specs :complete if data = @specs[name] @@ -101,7 +106,7 @@ class Gem::Source::Local < Gem::Source end end - def download(spec, cache_dir=nil) + def download spec, cache_dir = nil # :nodoc: load_specs :complete @specs.each do |name, data| diff --git a/lib/rubygems/source/specific_file.rb b/lib/rubygems/source/specific_file.rb index 8d328b38c2..a7b6c53542 100644 --- a/lib/rubygems/source/specific_file.rb +++ b/lib/rubygems/source/specific_file.rb @@ -1,4 +1,12 @@ +## +# A source representing a single .gem file. This is used for installation of +# local gems. + class Gem::Source::SpecificFile < Gem::Source + + ## + # Creates a new SpecificFile for the gem in +file+ + def initialize(file) @uri = nil @path = ::File.expand_path(file) @@ -8,19 +16,22 @@ class Gem::Source::SpecificFile < Gem::Source @name = @spec.name_tuple end + ## + # The Gem::Specification extracted from this .gem. + attr_reader :spec - def load_specs(*a) + def load_specs *a # :nodoc: [@name] end - def fetch_spec(name) + def fetch_spec name # :nodoc: return @spec if name == @name raise Gem::Exception, "Unable to find '#{name}'" @spec end - def download(spec, dir=nil) + def download spec, dir = nil # :nodoc: return @path if spec == @spec raise Gem::Exception, "Unable to download '#{spec.full_name}'" end diff --git a/lib/rubygems/source/vendor.rb b/lib/rubygems/source/vendor.rb index f2cf540c8d..244c4201d8 100644 --- a/lib/rubygems/source/vendor.rb +++ b/lib/rubygems/source/vendor.rb @@ -3,8 +3,22 @@ class Gem::Source::Vendor < Gem::Source::Installed - def initialize uri - @uri = uri + ## + # Creates a new Vendor source for a gem that was unpacked at +path+. + + def initialize path + @uri = path + end + + def <=> other + case other + when Gem::Source::Vendor then + 0 + when Gem::Source then + 1 + else + nil + end end end diff --git a/lib/rubygems/source_list.rb b/lib/rubygems/source_list.rb index e6da50c2e5..e01f11cc1e 100644 --- a/lib/rubygems/source_list.rb +++ b/lib/rubygems/source_list.rb @@ -1,5 +1,18 @@ require 'rubygems/source' +## +# The SourceList represents the sources rubygems has been configured to use. +# A source may be created from an array of sources: +# +# Gem::SourceList.from %w[https://rubygems.example https://internal.example] +# +# Or by adding them: +# +# sources = Gem::SourceList.new +# sources.add 'https://rubygems.example' +# +# The most common way to get a SourceList is Gem.sources. + class Gem::SourceList include Enumerable @@ -91,7 +104,7 @@ class Gem::SourceList @sources.empty? end - def ==(other) + def == other # :nodoc: to_a == other end diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 22fa68db69..12b8fb27d8 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -34,6 +34,10 @@ class Gem::SpecFetcher @fetcher = nil + ## + # Default fetcher instance. Use this instead of ::new to reduce object + # allocation. + def self.fetcher @fetcher ||= new end @@ -43,8 +47,8 @@ class Gem::SpecFetcher end ## - # Creates a new SpecFetcher. Ordinarily you want to use - # Gem::SpecFetcher::fetcher which uses the Gem.sources. + # Creates a new SpecFetcher. Ordinarily you want to use the default fetcher + # from Gem::SpecFetcher::fetcher which uses the Gem.sources. # # If you need to retrieve specifications from a different +source+, you can # send it as an argument. @@ -84,7 +88,11 @@ class Gem::SpecFetcher rejected_specs = {} if dependency.prerelease? - type = :complete + if dependency.specific? + type = :complete + else + type = :abs_latest + end elsif dependency.latest_version? type = :latest else @@ -223,6 +231,12 @@ class Gem::SpecFetcher tuples_for(source, :prerelease, true) + tuples_for(source, :released) + names.sort + when :abs_latest + names = + tuples_for(source, :prerelease, true) + + tuples_for(source, :latest) + names.sort when :prerelease tuples_for(source, :prerelease) @@ -239,7 +253,11 @@ class Gem::SpecFetcher [list, errors] end - def tuples_for(source, type, gracefully_ignore=false) + ## + # Retrieves NameTuples from +source+ of the given +type+ (:prerelease, + # etc.). If +gracefully_ignore+ is true, errors are ignored. + + def tuples_for(source, type, gracefully_ignore=false) # :nodoc: cache = @caches[type] tuples = diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 308aa6f011..b95e2c0699 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -12,6 +12,7 @@ require 'rubygems/platform' require 'rubygems/deprecate' require 'rubygems/basic_specification' require 'rubygems/stub_specification' +require 'rubygems/util/stringio' # :stopdoc: # date.rb can't be loaded for `make install` due to miniruby @@ -2165,7 +2166,7 @@ class Gem::Specification < Gem::BasicSpecification end ## - # Used by Gem::DependencyResolver to order Gem::Specification objects + # Used by Gem::Resolver to order Gem::Specification objects def source # :nodoc: self @@ -2363,7 +2364,7 @@ class Gem::Specification < Gem::BasicSpecification builder << self ast = builder.tree - io = StringIO.new + io = Gem::StringSink.new io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding Psych::Visitors::Emitter.new(io).accept(ast) diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index b04cbfc1f3..d1b471f619 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -233,6 +233,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase ruby end + @git = ENV['GIT'] || 'git' + Gem.ensure_gem_subdirectories @gemhome @orig_LOAD_PATH = $LOAD_PATH.dup @@ -372,6 +374,64 @@ class Gem::TestCase < MiniTest::Unit::TestCase Gem.pre_uninstall_hooks.clear end + ## + # A git_gem is used with a gem dependencies file. The gem created here + # has no files, just a gem specification for the given +name+ and +version+. + # + # Yields the +specification+ to the block, if given + + def git_gem name = 'a', version = 1 + have_git? + + directory = File.join 'git', name + directory = File.expand_path directory + + git_spec = Gem::Specification.new name, version do |specification| + yield specification if block_given? + end + + FileUtils.mkdir_p directory + + gemspec = "#{name}.gemspec" + + open File.join(directory, gemspec), 'w' do |io| + io.write git_spec.to_ruby + end + + head = nil + + Dir.chdir directory do + unless File.exist? '.git' then + system @git, 'init', '--quiet' + system @git, 'config', 'user.name', 'RubyGems Tests' + system @git, 'config', 'user.email', 'rubygems@example' + end + + system @git, 'add', gemspec + system @git, 'commit', '-a', '-m', 'a non-empty commit message', '--quiet' + head = Gem::Util.popen('git', 'rev-parse', 'master').strip + end + + return name, git_spec.version, directory, head + end + + ## + # Skips this test unless you have a git executable + + def have_git? + return if in_path? @git + + skip 'cannot find git executable, use GIT environment variable to set' + end + + def in_path? executable # :nodoc: + return true if %r%\A([A-Z]:|/)% =~ executable and File.exist? executable + + ENV['PATH'].split(File::PATH_SEPARATOR).any? do |directory| + File.exist? File.join directory, executable + end + end + ## # Builds and installs the Gem::Specification +spec+ @@ -1082,21 +1142,21 @@ Also, a list: end ## - # Constructs a Gem::DependencyResolver::DependencyRequest from a + # Constructs a Gem::Resolver::DependencyRequest from a # Gem::Dependency +dep+, a +from_name+ and +from_version+ requesting the # dependency and a +parent+ DependencyRequest def dependency_request dep, from_name, from_version, parent = nil remote = Gem::Source.new @uri - parent ||= Gem::DependencyResolver::DependencyRequest.new \ + parent ||= Gem::Resolver::DependencyRequest.new \ dep, nil - spec = Gem::DependencyResolver::IndexSpecification.new \ + spec = Gem::Resolver::IndexSpecification.new \ nil, from_name, from_version, remote, Gem::Platform::RUBY - activation = Gem::DependencyResolver::ActivationRequest.new spec, parent + activation = Gem::Resolver::ActivationRequest.new spec, parent - Gem::DependencyResolver::DependencyRequest.new dep, activation + Gem::Resolver::DependencyRequest.new dep, activation end ## diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb new file mode 100644 index 0000000000..e862458d21 --- /dev/null +++ b/lib/rubygems/util.rb @@ -0,0 +1,65 @@ +module Gem::Util + ## + # Zlib::GzipReader wrapper that unzips +data+. + + def self.gunzip(data) + require 'zlib' + require 'rubygems/util/stringio' + data = Gem::StringSource.new data + + unzipped = Zlib::GzipReader.new(data).read + unzipped.force_encoding Encoding::BINARY if Object.const_defined? :Encoding + unzipped + end + + ## + # Zlib::GzipWriter wrapper that zips +data+. + + def self.gzip(data) + require 'zlib' + require 'rubygems/util/stringio' + zipped = Gem::StringSink.new + zipped.set_encoding Encoding::BINARY if Object.const_defined? :Encoding + + Zlib::GzipWriter.wrap zipped do |io| io.write data end + + zipped.string + end + + ## + # A Zlib::Inflate#inflate wrapper + + def self.inflate(data) + require 'zlib' + Zlib::Inflate.inflate data + end + + ## + # This calls IO.popen where it accepts an array for a +command+ (Ruby 1.9+) + # and implements an IO.popen-like behavior where it does not accept an array + # for a command. + + def self.popen *command + begin + r, = IO.popen command + rescue TypeError # ruby 1.8 only supports string command + r, w = IO.pipe + + pid = fork do + STDIN.close + STDOUT.reopen w + + exec(*command) + end + + w.close + + Process.wait pid + + r + end + + r.read + end + +end diff --git a/lib/rubygems/util/stringio.rb b/lib/rubygems/util/stringio.rb new file mode 100644 index 0000000000..2ea69617bc --- /dev/null +++ b/lib/rubygems/util/stringio.rb @@ -0,0 +1,34 @@ +class Gem::StringSink + def initialize + @string = "" + end + + attr_reader :string + + def write(s) + @string += s + s.size + end + + def set_encoding(enc) + @string.force_encoding enc + end +end + +class Gem::StringSource + def initialize(str) + @string = str.dup + end + + def read(count=nil) + if count + @string.slice!(0,count) + else + s = @string + @string = "" + s + end + end + + alias_method :readpartial, :read +end diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index fd4d1de5c6..ec7f7299ec 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -1120,7 +1120,7 @@ class TestGem < Gem::TestCase ENV['RUBYGEMS_GEMDEPS'] = "-" - assert_equal [a,b,c], Gem.detect_gemdeps + assert_equal [a,b,c], Gem.detect_gemdeps.sort_by { |s| s.name } end LIB_PATH = File.expand_path "../../../lib".untaint, __FILE__.untaint diff --git a/test/rubygems/test_gem_commands_which_command.rb b/test/rubygems/test_gem_commands_which_command.rb index b19f204c4a..7ce26c861a 100644 --- a/test/rubygems/test_gem_commands_which_command.rb +++ b/test/rubygems/test_gem_commands_which_command.rb @@ -44,7 +44,9 @@ class TestGemCommandsWhichCommand < Gem::TestCase @cmd.handle_options %w[foo_bar missinglib] use_ui @ui do - @cmd.execute + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end end assert_equal "#{@foo_bar.full_gem_path}/lib/foo_bar.rb\n", @ui.output diff --git a/test/rubygems/test_gem_dependency_resolution_error.rb b/test/rubygems/test_gem_dependency_resolution_error.rb index 0ac0b06028..0442082e6a 100644 --- a/test/rubygems/test_gem_dependency_resolution_error.rb +++ b/test/rubygems/test_gem_dependency_resolution_error.rb @@ -5,7 +5,7 @@ class TestGemDependencyResolutionError < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver @spec = util_spec 'a', 2 @@ -14,7 +14,7 @@ class TestGemDependencyResolutionError < Gem::TestCase @activated = @DR::ActivationRequest.new @spec, @a2_req - @conflict = @DR::DependencyConflict.new @a1_req, @activated + @conflict = @DR::Conflict.new @a1_req, @activated @error = Gem::DependencyResolutionError.new @conflict end diff --git a/test/rubygems/test_gem_dependency_resolver_vendor_specification.rb b/test/rubygems/test_gem_dependency_resolver_vendor_specification.rb deleted file mode 100644 index 77d78d1dc7..0000000000 --- a/test/rubygems/test_gem_dependency_resolver_vendor_specification.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'rubygems/test_case' -require 'rubygems/dependency_resolver' - -class TestGemDependencyResolverVendorSpecification < Gem::TestCase - - def setup - super - - @set = Gem::DependencyResolver::VendorSet.new - @spec = Gem::Specification.new 'a', 1 - end - - def test_equals2 - v_spec_a = Gem::DependencyResolver::VendorSpecification.new @set, @spec - - assert_equal v_spec_a, v_spec_a - - spec_b = Gem::Specification.new 'b', 1 - v_spec_b = Gem::DependencyResolver::VendorSpecification.new @set, spec_b - - refute_equal v_spec_a, v_spec_b - - v_set = Gem::DependencyResolver::VendorSet.new - v_spec_s = Gem::DependencyResolver::VendorSpecification.new v_set, @spec - - refute_equal v_spec_a, v_spec_s - - i_set = Gem::DependencyResolver::IndexSet.new - source = Gem::Source.new @gem_repo - i_spec = Gem::DependencyResolver::IndexSpecification.new( - i_set, 'a', v(1), source, Gem::Platform::RUBY) - - refute_equal v_spec_a, i_spec - end - - def test_dependencies - @spec.add_dependency 'b' - @spec.add_dependency 'c' - - v_spec = Gem::DependencyResolver::VendorSpecification.new @set, @spec - - assert_equal [dep('b'), dep('c')], v_spec.dependencies - end - - def test_full_name - v_spec = Gem::DependencyResolver::VendorSpecification.new @set, @spec - - assert_equal 'a-1', v_spec.full_name - end - - def test_name - v_spec = Gem::DependencyResolver::VendorSpecification.new @set, @spec - - assert_equal 'a', v_spec.name - end - - def test_platform - v_spec = Gem::DependencyResolver::VendorSpecification.new @set, @spec - - assert_equal Gem::Platform::RUBY, v_spec.platform - end - - def test_version - spec = Gem::Specification.new 'a', 1 - - v_spec = Gem::DependencyResolver::VendorSpecification.new @set, spec - - assert_equal v(1), v_spec.version - end - -end - diff --git a/test/rubygems/test_gem_ext_builder.rb b/test/rubygems/test_gem_ext_builder.rb index d7e5880a96..3da9bc9e60 100644 --- a/test/rubygems/test_gem_ext_builder.rb +++ b/test/rubygems/test_gem_ext_builder.rb @@ -98,22 +98,26 @@ install: end def test_build_extensions - @spec.extensions << 'extconf.rb' + @spec.extensions << 'ext/extconf.rb' - FileUtils.mkdir_p @spec.gem_dir + ext_dir = File.join @spec.gem_dir, 'ext' - extconf_rb = File.join @spec.gem_dir, 'extconf.rb' + FileUtils.mkdir_p ext_dir + + extconf_rb = File.join ext_dir, 'extconf.rb' open extconf_rb, 'w' do |f| f.write <<-'RUBY' - open 'Makefile', 'w' do |f| - f.puts "clean:\n\techo cleaned" - f.puts "default:\n\techo built" - f.puts "install:\n\techo installed" - end + require 'mkmf' + + create_makefile 'a' RUBY end + ext_lib_dir = File.join ext_dir, 'lib' + FileUtils.mkdir ext_lib_dir + FileUtils.touch File.join ext_lib_dir, 'a.rb' + use_ui @ui do @builder.build_extensions end @@ -121,6 +125,8 @@ install: assert_path_exists @spec.extension_install_dir assert_path_exists @spec.gem_build_complete_path assert_path_exists File.join @spec.extension_install_dir, 'gem_make.out' + assert_path_exists File.join @spec.extension_install_dir, 'a.rb' + assert_path_exists File.join @spec.gem_dir, 'lib', 'a.rb' end def test_build_extensions_none diff --git a/test/rubygems/test_gem_impossible_dependencies_error.rb b/test/rubygems/test_gem_impossible_dependencies_error.rb index 9a0472fa36..f61b86e490 100644 --- a/test/rubygems/test_gem_impossible_dependencies_error.rb +++ b/test/rubygems/test_gem_impossible_dependencies_error.rb @@ -15,10 +15,10 @@ class TestGemImpossibleDependenciesError < Gem::TestCase net_ssh_2_6_5 = dependency_request dep('net-ssh', '~> 2.2.2'), 'net-ssh', '2.6.5', request - conflict1 = Gem::DependencyResolver::DependencyConflict.new \ + conflict1 = Gem::Resolver::Conflict.new \ net_ssh_2_6_5, net_ssh_2_6_5.requester - conflict2 = Gem::DependencyResolver::DependencyConflict.new \ + conflict2 = Gem::Resolver::Conflict.new \ net_ssh_2_2_2, net_ssh_2_2_2.requester conflicts << [net_ssh_2_6_5.requester.spec, conflict1] diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 0abb58b655..f0dd52cd36 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -1004,6 +1004,10 @@ gem 'other', version skip '1.9.2 and earlier mkmf.rb does not create TOUCH' if RUBY_VERSION < '1.9.3' + if RUBY_VERSION == "1.9.3" and RUBY_PATCHLEVEL <= 194 + skip "TOUCH was introduced into 1.9.3 after p194" + end + @spec.require_paths = ["."] @spec.extensions << "extconf.rb" @@ -1038,8 +1042,14 @@ gem 'other', version puts '-' * 78 puts File.read File.join(@gemhome, 'gems', 'a-2', 'Makefile') puts '-' * 78 - puts File.read File.join(@gemhome, 'gems', 'a-2', 'gem_make.out') - puts '-' * 78 + + path = File.join(@gemhome, 'gems', 'a-2', 'gem_make.out') + + if File.exists?(path) + puts File.read(path) + puts '-' * 78 + end + raise end diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index 5f36e71807..7e6d9c7693 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -165,7 +165,7 @@ gems: def test_api_endpoint uri = URI.parse "http://gems.example.com/foo" target = MiniTest::Mock.new - target.expect :target, "http://blah.com" + target.expect :target, "blah.com" dns = MiniTest::Mock.new dns.expect :getresource, target, [String, Object] diff --git a/test/rubygems/test_gem_request_set.rb b/test/rubygems/test_gem_request_set.rb index 9b215c2bc7..531b6c09d1 100644 --- a/test/rubygems/test_gem_request_set.rb +++ b/test/rubygems/test_gem_request_set.rb @@ -7,7 +7,7 @@ class TestGemRequestSet < Gem::TestCase Gem::RemoteFetcher.fetcher = @fetcher = Gem::FakeFetcher.new - @DR = Gem::DependencyResolver + @DR = Gem::Resolver end def test_gem @@ -69,6 +69,7 @@ class TestGemRequestSet < Gem::TestCase assert_equal [dep('a')], rs.dependencies + assert rs.git_set assert rs.vendor_set end @@ -100,6 +101,32 @@ class TestGemRequestSet < Gem::TestCase assert_equal ["a-2", "b-2"], names end + def test_resolve_git + name, _, repository, = git_gem + + rs = Gem::RequestSet.new + + Tempfile.open 'gem.deps.rb' do |io| + io.puts <<-gems_deps_rb + gem "#{name}", :git => "#{repository}" + gems_deps_rb + + io.flush + + rs.load_gemdeps io.path + end + + res = rs.resolve + assert_equal 1, res.size + + names = res.map { |s| s.full_name }.sort + + assert_equal %w[a-1], names + + assert_equal [@DR::IndexSet, @DR::GitSet, @DR::VendorSet], + rs.sets.map { |set| set.class } + end + def test_resolve_incompatible a1 = util_spec 'a', 1 a2 = util_spec 'a', 2 @@ -142,7 +169,7 @@ class TestGemRequestSet < Gem::TestCase assert_equal ["a-1", "b-2"], names - assert_equal [@DR::IndexSet, @DR::VendorSet], + assert_equal [@DR::IndexSet, @DR::GitSet, @DR::VendorSet], rs.sets.map { |set| set.class } end diff --git a/test/rubygems/test_gem_request_set_gem_dependency_api.rb b/test/rubygems/test_gem_request_set_gem_dependency_api.rb index 154449dde2..4286a761cb 100644 --- a/test/rubygems/test_gem_request_set_gem_dependency_api.rb +++ b/test/rubygems/test_gem_request_set_gem_dependency_api.rb @@ -10,9 +10,11 @@ class TestGemRequestSetGemDependencyAPI < Gem::TestCase @set = Gem::RequestSet.new - @vendor_set = Gem::DependencyResolver::VendorSet.new + @git_set = Gem::Resolver::GitSet.new + @vendor_set = Gem::Resolver::VendorSet.new @gda = @GDA.new @set, 'gem.deps.rb' + @gda.instance_variable_set :@git_set, @git_set @gda.instance_variable_set :@vendor_set, @vendor_set end @@ -48,6 +50,18 @@ class TestGemRequestSetGemDependencyAPI < Gem::TestCase Gem.instance_variables.include? :@ruby_version end + def test_gemspec_without_group + @gda.send :add_dependencies, [:development], [dep('a', '= 1')] + + assert_equal [dep('a', '= 1')], @set.dependencies + + @gda.without_groups << :development + + @gda.send :add_dependencies, [:development], [dep('b', '= 2')] + + assert_equal [dep('a', '= 1')], @set.dependencies + end + def test_gem @gda.gem 'a' @@ -56,6 +70,65 @@ class TestGemRequestSetGemDependencyAPI < Gem::TestCase assert_equal %w[a], @gda.requires['a'] end + def test_gem_git + @gda.gem 'a', :git => 'git/a' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git/a master], @git_set.repositories['a'] + end + + def test_gem_git_branch + @gda.gem 'a', :git => 'git/a', :branch => 'other', :tag => 'v1' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git/a other], @git_set.repositories['a'] + end + + def test_gem_git_gist + @gda.gem 'a', :gist => 'a' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[https://gist.github.com/a.git master], + @git_set.repositories['a'] + end + + def test_gem_git_ref + @gda.gem 'a', :git => 'git/a', :ref => 'abcd123', :branch => 'other' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git/a abcd123], @git_set.repositories['a'] + end + + def test_gem_git_submodules + @gda.gem 'a', :git => 'git/a', :submodules => true + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git/a master], @git_set.repositories['a'] + assert_equal %w[git/a], @git_set.need_submodules.keys + end + + def test_gem_git_tag + @gda.gem 'a', :git => 'git/a', :tag => 'v1' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git/a v1], @git_set.repositories['a'] + end + + def test_gem_github + @gda.gem 'a', :github => 'example/repository' + + assert_equal [dep('a')], @set.dependencies + + assert_equal %w[git://github.com/example/repository.git master], + @git_set.repositories['a'] + end + def test_gem_group @gda.gem 'a', :group => :test @@ -284,6 +357,130 @@ class TestGemRequestSetGemDependencyAPI < Gem::TestCase assert_equal [:a, :b, :c, :d], groups.sort_by { |group| group.to_s } end + def test_gemspec + spec = util_spec 'a', 1, 'b' => 2 + spec.add_development_dependency 'c', 3 + + open 'a.gemspec', 'w' do |io| + io.write spec.to_ruby_for_cache + end + + @gda.gemspec + + assert_equal [dep('b', '= 2'), dep('c', '=3')], @set.dependencies + + assert_equal %w[a], @gda.requires['a'] + end + + def test_gemspec_bad + FileUtils.touch 'a.gemspec' + + e = assert_raises ArgumentError do + capture_io do + @gda.gemspec + end + end + + assert_equal 'invalid gemspec ./a.gemspec', e.message + end + + def test_gemspec_development_group + spec = util_spec 'a', 1, 'b' => 2 + spec.add_development_dependency 'c', 3 + + open 'a.gemspec', 'w' do |io| + io.write spec.to_ruby_for_cache + end + + @gda.without_groups << :other + + @gda.gemspec :development_group => :other + + assert_equal [dep('b', '= 2')], @set.dependencies + + assert_equal %w[a], @gda.requires['a'] + end + + def test_gemspec_multiple + open 'a.gemspec', 'w' do |io| + spec = util_spec 'a', 1, 'b' => 2 + io.write spec.to_ruby_for_cache + end + + open 'b.gemspec', 'w' do |io| + spec = util_spec 'b', 2, 'c' => 3 + io.write spec.to_ruby_for_cache + end + + e = assert_raises ArgumentError do + @gda.gemspec + end + + assert_equal "found multiple gemspecs at #{@tempdir}, use the name: option to specify the one you want", e.message + end + + def test_gemspec_name + open 'a.gemspec', 'w' do |io| + spec = util_spec 'a', 1, 'b' => 2 + io.write spec.to_ruby_for_cache + end + + open 'b.gemspec', 'w' do |io| + spec = util_spec 'b', 2, 'c' => 3 + io.write spec.to_ruby_for_cache + end + + @gda.gemspec :name => 'b' + + assert_equal [dep('c', '= 3')], @set.dependencies + end + + def test_gemspec_named + spec = util_spec 'a', 1, 'b' => 2 + + open 'other.gemspec', 'w' do |io| + io.write spec.to_ruby_for_cache + end + + @gda.gemspec + + assert_equal [dep('b', '= 2')], @set.dependencies + end + + def test_gemspec_none + e = assert_raises ArgumentError do + @gda.gemspec + end + + assert_equal "no gemspecs found at #{@tempdir}", e.message + end + + def test_gemspec_path + spec = util_spec 'a', 1, 'b' => 2 + + FileUtils.mkdir 'other' + + open 'other/a.gemspec', 'w' do |io| + io.write spec.to_ruby_for_cache + end + + @gda.gemspec :path => 'other' + + assert_equal [dep('b', '= 2')], @set.dependencies + end + + def test_git + @gda.git 'git://example/repo.git' do + @gda.gem 'a' + @gda.gem 'b' + end + + assert_equal [dep('a'), dep('b')], @set.dependencies + + assert_equal %w[git://example/repo.git master], @git_set.repositories['a'] + assert_equal %w[git://example/repo.git master], @git_set.repositories['b'] + end + def test_group @gda.group :test do @gda.gem 'a' diff --git a/test/rubygems/test_gem_request_set_lockfile.rb b/test/rubygems/test_gem_request_set_lockfile.rb index 9e947f54ec..fcd4ecfaf7 100644 --- a/test/rubygems/test_gem_request_set_lockfile.rb +++ b/test/rubygems/test_gem_request_set_lockfile.rb @@ -13,7 +13,7 @@ class TestGemRequestSetLockfile < Gem::TestCase @set = Gem::RequestSet.new - @vendor_set = Gem::DependencyResolver::VendorSet.new + @vendor_set = Gem::Resolver::VendorSet.new @set.instance_variable_set :@vendor_set, @vendor_set @@ -96,7 +96,7 @@ DEPENDENCIES assert_equal [Gem::Platform::RUBY], @lockfile.platforms lockfile_set = @set.sets.find do |set| - Gem::DependencyResolver::LockSet === set + Gem::Resolver::LockSet === set end assert lockfile_set, 'could not find a LockSet' diff --git a/test/rubygems/test_gem_dependency_resolver.rb b/test/rubygems/test_gem_resolver.rb similarity index 81% rename from test/rubygems/test_gem_dependency_resolver.rb rename to test/rubygems/test_gem_resolver.rb index ceecab6d55..80769de8cf 100644 --- a/test/rubygems/test_gem_dependency_resolver.rb +++ b/test/rubygems/test_gem_resolver.rb @@ -1,12 +1,11 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolver < Gem::TestCase +class TestGemResolver < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver end def make_dep(name, *req) @@ -30,13 +29,17 @@ class TestGemDependencyResolver < Gem::TestCase flunk e.message end + def test_self_compatibility + assert_same Gem::Resolver, Gem::DependencyResolver + end + def test_self_compose_sets_multiple index_set = @DR::IndexSet.new vendor_set = @DR::VendorSet.new composed = @DR.compose_sets index_set, vendor_set - assert_kind_of Gem::DependencyResolver::ComposedSet, composed + assert_kind_of Gem::Resolver::ComposedSet, composed assert_equal [index_set, vendor_set], composed.sets end @@ -66,13 +69,13 @@ class TestGemDependencyResolver < Gem::TestCase def test_handle_conflict a1 = util_spec 'a', 1 - r1 = Gem::DependencyResolver::DependencyRequest.new dep('a', '= 1'), nil - r2 = Gem::DependencyResolver::DependencyRequest.new dep('a', '= 2'), nil - r3 = Gem::DependencyResolver::DependencyRequest.new dep('a', '= 3'), nil + r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil + r2 = Gem::Resolver::DependencyRequest.new dep('a', '= 2'), nil + r3 = Gem::Resolver::DependencyRequest.new dep('a', '= 3'), nil - existing = Gem::DependencyResolver::ActivationRequest.new a1, r1, false + existing = Gem::Resolver::ActivationRequest.new a1, r1, false - res = Gem::DependencyResolver.new [a1] + res = Gem::Resolver.new [a1] res.handle_conflict r2, existing res.handle_conflict r2, existing @@ -92,7 +95,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a, b) - res = Gem::DependencyResolver.new(deps, s) + res = Gem::Resolver.new(deps, s) assert_resolves_to [a, b], res end @@ -109,7 +112,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a, b, c) - res = Gem::DependencyResolver.new(deps, s) + res = Gem::Resolver.new(deps, s) assert_resolves_to [a, b, c], res end @@ -122,13 +125,13 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a" - res = Gem::DependencyResolver.new([ad], s) + res = Gem::Resolver.new([ad], s) assert_resolves_to [a2], res end def test_picks_best_platform - is = Gem::DependencyResolver::IndexSpecification + is = Gem::Resolver::IndexSpecification unknown = Gem::Platform.new 'unknown' a2_p1 = a3_p2 = nil @@ -153,7 +156,7 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a" - res = Gem::DependencyResolver.new([ad], s) + res = Gem::Resolver.new([ad], s) assert_resolves_to [a2_p1], res end @@ -169,7 +172,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, b1, c1) - res = Gem::DependencyResolver.new([ad, bd], s) + res = Gem::Resolver.new([ad, bd], s) assert_resolves_to [a1, b1, c1], res end @@ -186,17 +189,9 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, b1, c1, c2) - res = Gem::DependencyResolver.new([ad, bd], s) + res = Gem::Resolver.new([ad, bd], s) assert_resolves_to [a1, b1, c1], res - - cons = res.conflicts - - assert_equal 1, cons.size - con = cons.first - - assert_equal "c (= 1)", con.dependency.to_s - assert_equal "c-2", con.activated.full_name end def test_conflict_resolution_only_effects_correct_spec @@ -214,7 +209,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, b1, d3, d4, c1, c2) - res = Gem::DependencyResolver.new([ad, bd], s) + res = Gem::Resolver.new([ad, bd], s) assert_resolves_to [a1, b1, c1, d4], res @@ -239,31 +234,31 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, b1, c1, c2) - r = Gem::DependencyResolver.new([ad, bd], s) + r = Gem::Resolver.new([ad, bd], s) e = assert_raises Gem::DependencyResolutionError do r.resolve end - deps = [make_dep("c", "= 2"), make_dep("c", "= 1")] + deps = [make_dep("c", "= 1"), make_dep("c", "= 2")] assert_equal deps, e.conflicting_dependencies con = e.conflict act = con.activated - assert_equal "c-1", act.spec.full_name + assert_equal "c-2", act.spec.full_name parent = act.parent - assert_equal "a-1", parent.spec.full_name + assert_equal "b-1", parent.spec.full_name act = con.requester - assert_equal "b-1", act.spec.full_name + assert_equal "a-1", act.spec.full_name end def test_raises_when_a_gem_is_missing ad = make_dep "a" - r = Gem::DependencyResolver.new([ad], set) + r = Gem::Resolver.new([ad], set) e = assert_raises Gem::UnsatisfiableDepedencyError do r.resolve @@ -280,7 +275,7 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a", "= 3" - r = Gem::DependencyResolver.new([ad], set(a1)) + r = Gem::Resolver.new([ad], set(a1)) e = assert_raises Gem::UnsatisfiableDepedencyError do r.resolve @@ -293,7 +288,7 @@ class TestGemDependencyResolver < Gem::TestCase a1 = util_spec "a", "1" ad = make_dep "a", "= 3" - r = Gem::DependencyResolver.new([ad], set(a1)) + r = Gem::Resolver.new([ad], set(a1)) e = assert_raises Gem::UnsatisfiableDepedencyError do r.resolve @@ -310,7 +305,7 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a", "= 1" - r = Gem::DependencyResolver.new([ad], set(a1)) + r = Gem::Resolver.new([ad], set(a1)) e = assert_raises Gem::UnsatisfiableDepedencyError do r.resolve @@ -333,7 +328,7 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a" bd = make_dep "b" - r = Gem::DependencyResolver.new([ad, bd], s) + r = Gem::Resolver.new([ad, bd], s) e = assert_raises Gem::DependencyResolutionError do r.resolve @@ -345,11 +340,11 @@ class TestGemDependencyResolver < Gem::TestCase assert_equal req('>= 0'), dependency.requirement activated = e.conflict.activated - assert_equal 'c-2', activated.full_name + assert_equal 'c-1', activated.full_name - assert_equal dep('c', '>= 2'), activated.request.dependency + assert_equal dep('c', '= 1'), activated.request.dependency - assert_equal [dep('c', '= 1'), dep('c', '>= 2')], + assert_equal [dep('c', '>= 2'), dep('c', '= 1')], e.conflict.conflicting_dependencies end @@ -363,7 +358,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, b1, c1) - r = Gem::DependencyResolver.new([ad, bd], s) + r = Gem::Resolver.new([ad, bd], s) assert_resolves_to [a1, b1, c1], r end @@ -382,13 +377,13 @@ class TestGemDependencyResolver < Gem::TestCase s = set(lib1, rails, ap, rack100, rack101) - r = Gem::DependencyResolver.new([d1, d2], s) + r = Gem::Resolver.new([d1, d2], s) assert_resolves_to [rails, ap, rack101, lib1], r # check it with the deps reverse too - r = Gem::DependencyResolver.new([d2, d1], s) + r = Gem::Resolver.new([d2, d1], s) assert_resolves_to [lib1, rack101, rails, ap], r end @@ -405,7 +400,7 @@ class TestGemDependencyResolver < Gem::TestCase s = set(a1, a2, a3, a4) - r = Gem::DependencyResolver.new([d1, d2, d3], s) + r = Gem::Resolver.new([d1, d2, d3], s) assert_raises Gem::DependencyResolutionError do r.resolve @@ -423,7 +418,7 @@ class TestGemDependencyResolver < Gem::TestCase a_dep = dep 'a', '~> 1.0' b_dep = dep 'b' - r = Gem::DependencyResolver.new [a_dep, b_dep], s + r = Gem::Resolver.new [a_dep, b_dep], s assert_raises Gem::DependencyResolutionError do r.resolve @@ -444,7 +439,7 @@ class TestGemDependencyResolver < Gem::TestCase a_dep = dep 'a', '= 1' - r = Gem::DependencyResolver.new [a_dep], s + r = Gem::Resolver.new [a_dep], s assert_resolves_to [a1, b1, c1], r end @@ -461,7 +456,7 @@ class TestGemDependencyResolver < Gem::TestCase a_dep = dep 'a', '~> 1.0' b_dep = dep 'b' - r = Gem::DependencyResolver.new [a_dep, b_dep], s + r = Gem::Resolver.new [a_dep, b_dep], s assert_resolves_to [a1, b1], r end @@ -484,7 +479,7 @@ class TestGemDependencyResolver < Gem::TestCase d1 = make_dep "activemerchant" d2 = make_dep "actionmailer" - r = Gem::DependencyResolver.new([d1, d2], s) + r = Gem::Resolver.new([d1, d2], s) assert_resolves_to [merch, mail, sup1], r end @@ -502,13 +497,13 @@ class TestGemDependencyResolver < Gem::TestCase p1 = make_dep "b", "> 0" p2 = make_dep "d", "> 0" - r = Gem::DependencyResolver.new([p1, p2], s) + r = Gem::Resolver.new([p1, p2], s) assert_resolves_to [b1, c1, d2], r end def test_select_local_platforms - r = Gem::DependencyResolver.new nil, nil + r = Gem::Resolver.new nil, nil a1 = util_spec 'a', 1 a1_p1 = util_spec 'a', 1 do |s| s.platform = Gem::Platform.local end @@ -526,7 +521,7 @@ class TestGemDependencyResolver < Gem::TestCase ad = make_dep "a", "= 1" - r = Gem::DependencyResolver.new([ad], set(a1)) + r = Gem::Resolver.new([ad], set(a1)) e = assert_raises Gem::UnsatisfiableDepedencyError do r.resolve diff --git a/test/rubygems/test_gem_dependency_resolver_activation_request.rb b/test/rubygems/test_gem_resolver_activation_request.rb similarity index 89% rename from test/rubygems/test_gem_dependency_resolver_activation_request.rb rename to test/rubygems/test_gem_resolver_activation_request.rb index ac554d128c..54de6bf16a 100644 --- a/test/rubygems/test_gem_dependency_resolver_activation_request.rb +++ b/test/rubygems/test_gem_resolver_activation_request.rb @@ -1,11 +1,11 @@ require 'rubygems/test_case' -class TestGemDependencyResolverActivationRequest < Gem::TestCase +class TestGemResolverActivationRequest < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver @dep = @DR::DependencyRequest.new dep('a', '>= 0'), nil @@ -36,7 +36,7 @@ class TestGemDependencyResolverActivationRequest < Gem::TestCase end def test_installed_eh - v_spec = Gem::DependencyResolver::VendorSpecification.new nil, @a3 + v_spec = Gem::Resolver::VendorSpecification.new nil, @a3 @req = @DR::ActivationRequest.new v_spec, @dep, [@a1, @a2] diff --git a/test/rubygems/test_gem_dependency_resolver_api_set.rb b/test/rubygems/test_gem_resolver_api_set.rb similarity index 74% rename from test/rubygems/test_gem_dependency_resolver_api_set.rb rename to test/rubygems/test_gem_resolver_api_set.rb index ef99b6ca7f..976d861cdf 100644 --- a/test/rubygems/test_gem_dependency_resolver_api_set.rb +++ b/test/rubygems/test_gem_resolver_api_set.rb @@ -1,12 +1,11 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverAPISet < Gem::TestCase +class TestGemResolverAPISet < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver end def test_initialize diff --git a/test/rubygems/test_gem_dependency_resolver_api_specification.rb b/test/rubygems/test_gem_resolver_api_specification.rb similarity index 73% rename from test/rubygems/test_gem_dependency_resolver_api_specification.rb rename to test/rubygems/test_gem_resolver_api_specification.rb index cdbecec822..e61d30c7c6 100644 --- a/test/rubygems/test_gem_dependency_resolver_api_specification.rb +++ b/test/rubygems/test_gem_resolver_api_specification.rb @@ -1,10 +1,9 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverAPISpecification < Gem::TestCase +class TestGemResolverAPISpecification < Gem::TestCase def test_initialize - set = Gem::DependencyResolver::APISet.new + set = Gem::Resolver::APISet.new data = { :name => 'rails', :number => '3.0.3', @@ -15,7 +14,7 @@ class TestGemDependencyResolverAPISpecification < Gem::TestCase ], } - spec = Gem::DependencyResolver::APISpecification.new set, data + spec = Gem::Resolver::APISpecification.new set, data assert_equal 'rails', spec.name assert_equal Gem::Version.new('3.0.3'), spec.version diff --git a/test/rubygems/test_gem_dependency_resolver_best_set.rb b/test/rubygems/test_gem_resolver_best_set.rb similarity index 76% rename from test/rubygems/test_gem_dependency_resolver_best_set.rb rename to test/rubygems/test_gem_resolver_best_set.rb index 20fbf4514f..5bcff4aca7 100644 --- a/test/rubygems/test_gem_dependency_resolver_best_set.rb +++ b/test/rubygems/test_gem_resolver_best_set.rb @@ -1,12 +1,11 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverBestSet < Gem::TestCase +class TestGemResolverBestSet < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver end def test_find_all_index diff --git a/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb b/test/rubygems/test_gem_resolver_conflict.rb similarity index 76% rename from test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb rename to test/rubygems/test_gem_resolver_conflict.rb index 68e17f8a98..3ae2a7cf5f 100644 --- a/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +++ b/test/rubygems/test_gem_resolver_conflict.rb @@ -1,7 +1,10 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverDependencyConflict < Gem::TestCase +class TestGemResolverConflict < Gem::TestCase + + def test_self_compatibility + assert_same Gem::Resolver::Conflict, Gem::Resolver::DependencyConflict + end def test_explanation root = @@ -10,7 +13,7 @@ class TestGemDependencyResolverDependencyConflict < Gem::TestCase dependency_request dep('net-ssh', '>= 2.6.5'), 'net-ssh', '2.2.2', root conflict = - Gem::DependencyResolver::DependencyConflict.new child, child.requester + Gem::Resolver::Conflict.new child, child.requester expected = <<-EXPECTED Activated net-ssh-2.2.2 instead of (>= 2.6.5) via: @@ -21,7 +24,7 @@ class TestGemDependencyResolverDependencyConflict < Gem::TestCase end def test_explanation_user_request - @DR = Gem::DependencyResolver + @DR = Gem::Resolver spec = util_spec 'a', 2 @@ -30,7 +33,7 @@ class TestGemDependencyResolverDependencyConflict < Gem::TestCase activated = @DR::ActivationRequest.new spec, a2_req - conflict = @DR::DependencyConflict.new a1_req, activated + conflict = @DR::Conflict.new a1_req, activated expected = <<-EXPECTED Activated a-2 instead of (= 1) via: @@ -47,7 +50,7 @@ class TestGemDependencyResolverDependencyConflict < Gem::TestCase dependency_request dep('net-ssh', '>= 2.6.5'), 'net-ssh', '2.2.2', root conflict = - Gem::DependencyResolver::DependencyConflict.new child, nil + Gem::Resolver::Conflict.new child, nil assert_equal %w[net-ssh-2.2.2 rye-0.9.8], conflict.request_path end diff --git a/test/rubygems/test_gem_dependency_resolver_dependency_request.rb b/test/rubygems/test_gem_resolver_dependency_request.rb similarity index 63% rename from test/rubygems/test_gem_dependency_resolver_dependency_request.rb rename to test/rubygems/test_gem_resolver_dependency_request.rb index f5b3a6960e..e1a98826fb 100644 --- a/test/rubygems/test_gem_dependency_resolver_dependency_request.rb +++ b/test/rubygems/test_gem_resolver_dependency_request.rb @@ -1,11 +1,11 @@ require 'rubygems/test_case' -class TestGemDependencyResolverDependencyRequest < Gem::TestCase +class TestGemResolverDependencyRequest < Gem::TestCase def setup super - @DR = Gem::DependencyResolver::DependencyRequest + @DR = Gem::Resolver::DependencyRequest end def test_requirement diff --git a/test/rubygems/test_gem_resolver_git_set.rb b/test/rubygems/test_gem_resolver_git_set.rb new file mode 100644 index 0000000000..6943df9ec8 --- /dev/null +++ b/test/rubygems/test_gem_resolver_git_set.rb @@ -0,0 +1,84 @@ +require 'rubygems/test_case' + +class TestGemResolverGitSet < Gem::TestCase + + def setup + super + + @set = Gem::Resolver::GitSet.new + + @reqs = Gem::Resolver::RequirementList.new + end + + def test_add_git_gem + name, version, repository, = git_gem + + @set.add_git_gem name, repository, 'master', false + + dependency = dep 'a' + + specs = @set.find_all dependency + + assert_equal "#{name}-#{version}", specs.first.full_name + + refute @set.need_submodules[repository] + end + + def test_add_git_gem_submodules + name, _, repository, = git_gem + + @set.add_git_gem name, repository, 'master', true + + dependency = dep 'a' + + refute_empty @set.find_all dependency + + assert @set.need_submodules[repository] + end + + def test_find_all + name, _, repository, = git_gem + + @set.add_git_gem name, repository, 'master', false + + dependency = dep 'a', '~> 1.0' + req = Gem::Resolver::ActivationRequest.new dependency, nil + @reqs.add req + + @set.prefetch @reqs + + found = @set.find_all dependency + + assert_equal [@set.specs['a']], found + end + + def test_prefetch + name, _, repository, = git_gem + + @set.add_git_gem name, repository, 'master', false + + dependency = dep name + req = Gem::Resolver::ActivationRequest.new dependency, nil + @reqs.add req + + @set.prefetch @reqs + + refute_empty @set.specs + end + + def test_prefetch_filter + name, _, repository, = git_gem + + @set.add_git_gem name, repository, 'master', false + + dependency = dep 'b' + req = Gem::Resolver::ActivationRequest.new dependency, nil + @reqs.add req + + @set.prefetch @reqs + + assert_empty @set.specs + end + +end + diff --git a/test/rubygems/test_gem_resolver_git_specification.rb b/test/rubygems/test_gem_resolver_git_specification.rb new file mode 100644 index 0000000000..f961a7709a --- /dev/null +++ b/test/rubygems/test_gem_resolver_git_specification.rb @@ -0,0 +1,36 @@ +require 'rubygems/test_case' + +class TestGemResolverGitSpecification < Gem::TestCase + + def setup + super + + @set = Gem::Resolver::GitSet.new + @spec = Gem::Specification.new 'a', 1 + end + + def test_equals2 + g_spec_a = Gem::Resolver::GitSpecification.new @set, @spec + + assert_equal g_spec_a, g_spec_a + + spec_b = Gem::Specification.new 'b', 1 + g_spec_b = Gem::Resolver::GitSpecification.new @set, spec_b + + refute_equal g_spec_a, g_spec_b + + g_set = Gem::Resolver::GitSet.new + g_spec_s = Gem::Resolver::GitSpecification.new g_set, @spec + + refute_equal g_spec_a, g_spec_s + + i_set = Gem::Resolver::IndexSet.new + source = Gem::Source.new @gem_repo + i_spec = Gem::Resolver::IndexSpecification.new( + i_set, 'a', v(1), source, Gem::Platform::RUBY) + + refute_equal g_spec_a, i_spec + end + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_index_set.rb b/test/rubygems/test_gem_resolver_index_set.rb similarity index 75% rename from test/rubygems/test_gem_dependency_resolver_index_set.rb rename to test/rubygems/test_gem_resolver_index_set.rb index 83b7cce501..137e9b5cac 100644 --- a/test/rubygems/test_gem_dependency_resolver_index_set.rb +++ b/test/rubygems/test_gem_resolver_index_set.rb @@ -1,12 +1,11 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverIndexSet < Gem::TestCase +class TestGemResolverIndexSet < Gem::TestCase def setup super - @DR = Gem::DependencyResolver + @DR = Gem::Resolver end def test_initialize diff --git a/test/rubygems/test_gem_dependency_resolver_index_specification.rb b/test/rubygems/test_gem_resolver_index_specification.rb similarity index 70% rename from test/rubygems/test_gem_dependency_resolver_index_specification.rb rename to test/rubygems/test_gem_resolver_index_specification.rb index 751ed34db3..ef474ab2d4 100644 --- a/test/rubygems/test_gem_dependency_resolver_index_specification.rb +++ b/test/rubygems/test_gem_resolver_index_specification.rb @@ -1,15 +1,14 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' require 'rubygems/available_set' -class TestGemDependencyResolverIndexSpecification < Gem::TestCase +class TestGemResolverIndexSpecification < Gem::TestCase def test_initialize - set = Gem::DependencyResolver::IndexSet.new + set = Gem::Resolver::IndexSet.new source = Gem::Source.new @gem_repo version = Gem::Version.new '3.0.3' - spec = Gem::DependencyResolver::IndexSpecification.new( + spec = Gem::Resolver::IndexSpecification.new( set, 'rails', version, source, Gem::Platform::RUBY) assert_equal 'rails', spec.name @@ -20,11 +19,11 @@ class TestGemDependencyResolverIndexSpecification < Gem::TestCase end def test_initialize_platform - set = Gem::DependencyResolver::IndexSet.new + set = Gem::Resolver::IndexSet.new source = Gem::Source::Local.new version = Gem::Version.new '3.0.3' - spec = Gem::DependencyResolver::IndexSpecification.new( + spec = Gem::Resolver::IndexSpecification.new( set, 'rails', version, source, Gem::Platform.local) assert_equal Gem::Platform.local.to_s, spec.platform @@ -39,8 +38,8 @@ class TestGemDependencyResolverIndexSpecification < Gem::TestCase source = Gem::Source.new @gem_repo version = v 2 - set = Gem::DependencyResolver::IndexSet.new - i_spec = Gem::DependencyResolver::IndexSpecification.new \ + set = Gem::Resolver::IndexSet.new + i_spec = Gem::Resolver::IndexSpecification.new \ set, 'a', version, source, Gem::Platform.local spec = i_spec.spec @@ -53,10 +52,10 @@ class TestGemDependencyResolverIndexSpecification < Gem::TestCase Gem::Package.build a_2_p source = Gem::Source::Local.new - set = Gem::DependencyResolver::InstallerSet.new :local + set = Gem::Resolver::InstallerSet.new :local set.always_install << a_2_p - i_spec = Gem::DependencyResolver::IndexSpecification.new \ + i_spec = Gem::Resolver::IndexSpecification.new \ set, 'a', v(2), source, Gem::Platform.local spec = i_spec.spec diff --git a/test/rubygems/test_gem_dependency_resolver_installed_specification.rb b/test/rubygems/test_gem_resolver_installed_specification.rb similarity index 50% rename from test/rubygems/test_gem_dependency_resolver_installed_specification.rb rename to test/rubygems/test_gem_resolver_installed_specification.rb index e1f4262e4b..f9dda29a6c 100644 --- a/test/rubygems/test_gem_dependency_resolver_installed_specification.rb +++ b/test/rubygems/test_gem_resolver_installed_specification.rb @@ -1,14 +1,13 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverInstalledSpecification < Gem::TestCase +class TestGemResolverInstalledSpecification < Gem::TestCase def test_initialize - set = Gem::DependencyResolver::CurrentSet.new + set = Gem::Resolver::CurrentSet.new source_spec = util_spec 'a' - spec = Gem::DependencyResolver::InstalledSpecification.new set, source_spec + spec = Gem::Resolver::InstalledSpecification.new set, source_spec assert_equal 'a', spec.name assert_equal Gem::Version.new(2), spec.version diff --git a/test/rubygems/test_gem_dependency_resolver_installer_set.rb b/test/rubygems/test_gem_resolver_installer_set.rb similarity index 72% rename from test/rubygems/test_gem_dependency_resolver_installer_set.rb rename to test/rubygems/test_gem_resolver_installer_set.rb index 6341c6bc73..af4db646a9 100644 --- a/test/rubygems/test_gem_dependency_resolver_installer_set.rb +++ b/test/rubygems/test_gem_resolver_installer_set.rb @@ -1,7 +1,6 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverInstallerSet < Gem::TestCase +class TestGemResolverInstallerSet < Gem::TestCase def test_load_spec specs = spec_fetcher do |fetcher| @@ -12,7 +11,7 @@ class TestGemDependencyResolverInstallerSet < Gem::TestCase source = Gem::Source.new @gem_repo version = v 2 - set = Gem::DependencyResolver::InstallerSet.new :remote + set = Gem::Resolver::InstallerSet.new :remote spec = set.load_spec 'a', version, Gem::Platform.local, source diff --git a/test/rubygems/test_gem_dependency_resolver_lock_set.rb b/test/rubygems/test_gem_resolver_lock_set.rb similarity index 88% rename from test/rubygems/test_gem_dependency_resolver_lock_set.rb rename to test/rubygems/test_gem_resolver_lock_set.rb index 6142f2b8d0..71b28efd4f 100644 --- a/test/rubygems/test_gem_dependency_resolver_lock_set.rb +++ b/test/rubygems/test_gem_resolver_lock_set.rb @@ -1,14 +1,13 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverLockSet < Gem::TestCase +class TestGemResolverLockSet < Gem::TestCase def setup super @source = Gem::Source.new @gem_repo - @set = Gem::DependencyResolver::LockSet.new @source + @set = Gem::Resolver::LockSet.new @source end def test_add diff --git a/test/rubygems/test_gem_resolver_requirement_list.rb b/test/rubygems/test_gem_resolver_requirement_list.rb new file mode 100644 index 0000000000..3d09ce5f92 --- /dev/null +++ b/test/rubygems/test_gem_resolver_requirement_list.rb @@ -0,0 +1,19 @@ +require 'rubygems/test_case' + +class TestGemResolverRequirementList < Gem::TestCase + + def setup + super + + @list = Gem::Resolver::RequirementList.new + end + + def test_each + @list.add 1 + @list.add 2 + + assert_equal [1, 2], @list.each.to_a + end + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_vendor_set.rb b/test/rubygems/test_gem_resolver_vendor_set.rb similarity index 79% rename from test/rubygems/test_gem_dependency_resolver_vendor_set.rb rename to test/rubygems/test_gem_resolver_vendor_set.rb index 227cf369c8..58519fbf14 100644 --- a/test/rubygems/test_gem_dependency_resolver_vendor_set.rb +++ b/test/rubygems/test_gem_resolver_vendor_set.rb @@ -1,12 +1,11 @@ require 'rubygems/test_case' -require 'rubygems/dependency_resolver' -class TestGemDependencyResolverVendorSet < Gem::TestCase +class TestGemResolverVendorSet < Gem::TestCase def setup super - @set = Gem::DependencyResolver::VendorSet.new + @set = Gem::Resolver::VendorSet.new end def test_add_vendor_gem @@ -39,7 +38,7 @@ class TestGemDependencyResolverVendorSet < Gem::TestCase dependency = dep 'a', '~> 1' - req = Gem::DependencyResolver::DependencyRequest.new dependency, nil + req = Gem::Resolver::DependencyRequest.new dependency, nil found = @set.find_all req @@ -48,7 +47,7 @@ class TestGemDependencyResolverVendorSet < Gem::TestCase source = Gem::Source::Vendor.new directory expected = [ - Gem::DependencyResolver::VendorSpecification.new(@set, spec, source) + Gem::Resolver::VendorSpecification.new(@set, spec, source) ] assert_equal expected, found diff --git a/test/rubygems/test_gem_resolver_vendor_specification.rb b/test/rubygems/test_gem_resolver_vendor_specification.rb new file mode 100644 index 0000000000..d7aca569e2 --- /dev/null +++ b/test/rubygems/test_gem_resolver_vendor_specification.rb @@ -0,0 +1,71 @@ +require 'rubygems/test_case' + +class TestGemResolverVendorSpecification < Gem::TestCase + + def setup + super + + @set = Gem::Resolver::VendorSet.new + @spec = Gem::Specification.new 'a', 1 + end + + def test_equals2 + v_spec_a = Gem::Resolver::VendorSpecification.new @set, @spec + + assert_equal v_spec_a, v_spec_a + + spec_b = Gem::Specification.new 'b', 1 + v_spec_b = Gem::Resolver::VendorSpecification.new @set, spec_b + + refute_equal v_spec_a, v_spec_b + + v_set = Gem::Resolver::VendorSet.new + v_spec_s = Gem::Resolver::VendorSpecification.new v_set, @spec + + refute_equal v_spec_a, v_spec_s + + i_set = Gem::Resolver::IndexSet.new + source = Gem::Source.new @gem_repo + i_spec = Gem::Resolver::IndexSpecification.new( + i_set, 'a', v(1), source, Gem::Platform::RUBY) + + refute_equal v_spec_a, i_spec + end + + def test_dependencies + @spec.add_dependency 'b' + @spec.add_dependency 'c' + + v_spec = Gem::Resolver::VendorSpecification.new @set, @spec + + assert_equal [dep('b'), dep('c')], v_spec.dependencies + end + + def test_full_name + v_spec = Gem::Resolver::VendorSpecification.new @set, @spec + + assert_equal 'a-1', v_spec.full_name + end + + def test_name + v_spec = Gem::Resolver::VendorSpecification.new @set, @spec + + assert_equal 'a', v_spec.name + end + + def test_platform + v_spec = Gem::Resolver::VendorSpecification.new @set, @spec + + assert_equal Gem::Platform::RUBY, v_spec.platform + end + + def test_version + spec = Gem::Specification.new 'a', 1 + + v_spec = Gem::Resolver::VendorSpecification.new @set, spec + + assert_equal v(1), v_spec.version + end + +end + diff --git a/test/rubygems/test_gem_source.rb b/test/rubygems/test_gem_source.rb index 3ed40a625a..d207bcac7f 100644 --- a/test/rubygems/test_gem_source.rb +++ b/test/rubygems/test_gem_source.rb @@ -44,13 +44,13 @@ class TestGemSource < Gem::TestCase set = @source.dependency_resolver_set - assert_kind_of Gem::DependencyResolver::APISet, set + assert_kind_of Gem::Resolver::APISet, set end def test_dependency_resolver_set_marshal_api set = @source.dependency_resolver_set - assert_kind_of Gem::DependencyResolver::IndexSet, set + assert_kind_of Gem::Resolver::IndexSet, set end def test_fetch_spec diff --git a/test/rubygems/test_gem_source_git.rb b/test/rubygems/test_gem_source_git.rb new file mode 100644 index 0000000000..78c415a9d3 --- /dev/null +++ b/test/rubygems/test_gem_source_git.rb @@ -0,0 +1,153 @@ +require 'rubygems/test_case' +require 'rubygems/source' + +class TestGemSourceGit < Gem::TestCase + + def setup + super + + @name, @version, @repository, @head = git_gem + + @hash = Digest::SHA1.hexdigest @repository + + @source = Gem::Source::Git.new @name, @repository, 'master', false + end + + def test_checkout + @source.checkout + + assert_path_exists File.join @source.install_dir, 'a.gemspec' + end + + def test_checkout_submodules + source = Gem::Source::Git.new @name, @repository, 'master', true + + git_gem 'b' + + Dir.chdir 'git/a' do + system @git, 'submodule', '--quiet', 'add', File.expand_path('../b'), 'b' + system @git, 'commit', '--quiet', '-m', 'add submodule b' + end + + source.checkout + + assert_path_exists File.join source.install_dir, 'a.gemspec' + assert_path_exists File.join source.install_dir, 'b/b.gemspec' + end + + def test_cache + assert @source.cache + + assert_path_exists @source.repo_cache_dir + + Dir.chdir @source.repo_cache_dir do + assert_equal @head, Gem::Util.popen(@git, 'rev-parse', 'master').strip + end + end + + def test_dir_shortref + @source.cache + + assert_equal @head[0..11], @source.dir_shortref + end + + def test_equals2 + assert_equal @source, @source + + assert_equal @source, @source.dup + + source = + Gem::Source::Git.new @source.name, @source.repository, 'other', false + + refute_equal @source, source + + source = + Gem::Source::Git.new @source.name, 'repo/other', @source.reference, false + + refute_equal @source, source + + source = + Gem::Source::Git.new 'b', @source.repository, @source.reference, false + + refute_equal @source, source + + source = + Gem::Source::Git.new @source.name, @source.repository, @source.reference, + true + + refute_equal @source, source + end + + def test_load_spec + spec = @source.load_spec @name + + assert_equal "#{@name}-#{@version}", spec.full_name + end + + def test_install_dir + @source.cache + + expected = File.join Gem.dir, 'bundler', 'gems', "a-#{@head[0..11]}" + + assert_equal expected, @source.install_dir + end + + def test_repo_cache_dir + expected = + File.join Gem.dir, 'cache', 'bundler', 'git', "a-#{@hash}" + + assert_equal expected, @source.repo_cache_dir + end + + def test_rev_parse + @source.cache + + assert_equal @head, @source.rev_parse + + Dir.chdir @repository do + system @git, 'checkout', '--quiet', '-b', 'other' + end + + master_head = @head + + git_gem 'a', 2 + + source = Gem::Source::Git.new @name, @repository, 'other', false + + source.cache + + refute_equal master_head, source.rev_parse + end + + def test_spaceship + git = Gem::Source::Git.new 'a', 'git/a', 'master', false + remote = Gem::Source.new @gem_repo + installed = Gem::Source::Installed.new + + assert_equal( 0, git. <=>(git), 'git <=> git') + + assert_equal( 1, git. <=>(remote), 'git <=> remote') + assert_equal(-1, remote. <=>(git), 'remote <=> git') + + assert_equal( 1, installed.<=>(git), 'installed <=> git') + assert_equal(-1, git. <=>(installed), 'git <=> installed') + end + + def test_uri_hash + assert_equal @hash, @source.uri_hash + + source = + Gem::Source::Git.new 'a', 'http://git@example/repo.git', 'master', false + + assert_equal '291c4caac7feba8bb64c297987028acb3dde6cfe', + source.uri_hash + + source = + Gem::Source::Git.new 'a', 'HTTP://git@EXAMPLE/repo.git', 'master', false + + assert_equal '291c4caac7feba8bb64c297987028acb3dde6cfe', + source.uri_hash + end + +end + diff --git a/test/rubygems/test_gem_source_vendor.rb b/test/rubygems/test_gem_source_vendor.rb index 17403a1fc8..3f4121e5f6 100644 --- a/test/rubygems/test_gem_source_vendor.rb +++ b/test/rubygems/test_gem_source_vendor.rb @@ -9,5 +9,19 @@ class TestGemSourceVendor < Gem::TestCase assert_equal 'vendor/foo', source.uri end + def test_spaceship + vendor = Gem::Source::Vendor.new 'vendor/foo' + remote = Gem::Source.new @gem_repo + installed = Gem::Source::Installed.new + + assert_equal( 0, vendor. <=>(vendor), 'vendor <=> vendor') + + assert_equal( 1, vendor. <=>(remote), 'vendor <=> remote') + assert_equal(-1, remote. <=>(vendor), 'remote <=> vendor') + + assert_equal( 1, vendor. <=>(installed), 'vendor <=> installed') + assert_equal(-1, installed.<=>(vendor), 'installed <=> vendor') + end + end diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 75ea4092b7..3924191db9 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1733,7 +1733,7 @@ dependencies: [] full_gem_path = Pathname(@ext.full_gem_path) relative_install_dir = ext_install_dir.relative_path_from full_gem_path - assert_equal ['lib', relative_install_dir.to_s], @ext.require_paths + assert_equal [relative_install_dir.to_s, 'lib'], @ext.require_paths ensure RbConfig::CONFIG['ENABLE_SHARED'] = enable_shared end @@ -1744,8 +1744,8 @@ dependencies: [] @ext.require_path = 'lib' expected = [ - File.join(@gemhome, 'gems', @ext.original_name, 'lib'), @ext.extension_install_dir, + File.join(@gemhome, 'gems', @ext.original_name, 'lib'), ] assert_equal expected, @ext.full_require_paths diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb index bb04fb4dcc..50621e28ae 100644 --- a/test/rubygems/test_gem_stub_specification.rb +++ b/test/rubygems/test_gem_stub_specification.rb @@ -31,7 +31,7 @@ class TestStubSpecification < Gem::TestCase assert_equal 'stub_e', stub.name assert_equal v(2), stub.version assert_equal Gem::Platform::RUBY, stub.platform - assert_equal ['lib', relative_install_dir], stub.require_paths + assert_equal [relative_install_dir, 'lib'], stub.require_paths assert_equal %w[ext/stub_e/extconf.rb], stub.extensions end @@ -78,8 +78,8 @@ class TestStubSpecification < Gem::TestCase stub = stub_with_extension expected = [ - File.join(stub.full_gem_path, 'lib'), stub.extension_install_dir, + File.join(stub.full_gem_path, 'lib'), ] assert_equal expected, stub.full_require_paths diff --git a/test/rubygems/test_gem_util.rb b/test/rubygems/test_gem_util.rb new file mode 100644 index 0000000000..bf67b14d38 --- /dev/null +++ b/test/rubygems/test_gem_util.rb @@ -0,0 +1,11 @@ +require 'rubygems/test_case' +require 'rubygems/util' + +class TestGemUtil < Gem::TestCase + + def test_class_popen + assert_equal "0\n", Gem::Util.popen(Gem.ruby, '-e', 'p 0') + end + +end +