diff options
author | drbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-12-08 01:22:39 +0000 |
---|---|---|
committer | drbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-12-08 01:22:39 +0000 |
commit | 7ed9b794b4e3f3f9874f2ce19401461596d8a2c0 (patch) | |
tree | 5caaf13685de34b09d2949709a77b4c650b62741 /lib | |
parent | 866b438c21ff05dfeabba8bc9aa9850e415be607 (diff) |
* lib/rubygems: Update to RubyGems master 14749ce. This fixes bugs
handling of gem dependencies lockfiles (Gemfile.lock).
* test/rubygems: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44054 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rubygems/request_set.rb | 10 | ||||
-rw-r--r-- | lib/rubygems/request_set/gem_dependency_api.rb | 42 | ||||
-rw-r--r-- | lib/rubygems/request_set/lockfile.rb | 220 | ||||
-rw-r--r-- | lib/rubygems/requirement.rb | 18 | ||||
-rw-r--r-- | lib/rubygems/resolver.rb | 40 | ||||
-rw-r--r-- | lib/rubygems/resolver/git_set.rb | 26 | ||||
-rw-r--r-- | lib/rubygems/resolver/lock_set.rb | 6 | ||||
-rw-r--r-- | lib/rubygems/resolver/lock_specification.rb | 58 | ||||
-rw-r--r-- | lib/rubygems/resolver/requirement_list.rb | 25 | ||||
-rw-r--r-- | lib/rubygems/resolver/stats.rb | 44 | ||||
-rw-r--r-- | lib/rubygems/source.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/source/git.rb | 10 | ||||
-rw-r--r-- | lib/rubygems/source/lock.rb | 4 | ||||
-rw-r--r-- | lib/rubygems/test_case.rb | 8 | ||||
-rw-r--r-- | lib/rubygems/test_utilities.rb | 27 |
15 files changed, 473 insertions, 68 deletions
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 54e4d9dee4..68a8112c37 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -158,6 +158,10 @@ class Gem::RequestSet specs.map { |s| s.full_name }.sort.each do |s| puts " #{s}" end + + if Gem.configuration.really_verbose + @resolver.stats.display + end else installed = install options, &block @@ -169,6 +173,8 @@ class Gem::RequestSet end def install_into dir, force = true, options = {} + gem_home, ENV['GEM_HOME'] = ENV['GEM_HOME'], dir + existing = force ? [] : specs_in(dir) existing.delete_if { |s| @always_install.include? s } @@ -195,6 +201,8 @@ class Gem::RequestSet end installed + ensure + ENV['GEM_HOME'] = gem_home end ## @@ -229,6 +237,8 @@ class Gem::RequestSet resolver.development = @development resolver.soft_missing = @soft_missing + @resolver = resolver + @requests = resolver.resolve end diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb index 0c27b1a61a..efce979177 100644 --- a/lib/rubygems/request_set/gem_dependency_api.rb +++ b/lib/rubygems/request_set/gem_dependency_api.rb @@ -221,13 +221,7 @@ class Gem::RequestSet::GemDependencyAPI return unless (groups & @without_groups).empty? - unless source_set then - raise ArgumentError, - "duplicate source (default) for gem #{name}" if - @gem_sources.include? name - - @gem_sources[name] = :default - end + pin_gem_source name, :default unless source_set gem_requires name, options @@ -246,9 +240,7 @@ class Gem::RequestSet::GemDependencyAPI return unless repository = options.delete(:git) - raise ArgumentError, - "duplicate source git: #{repository} for gem #{name}" if - @gem_sources.include? name + pin_gem_source name, :git, repository reference = nil reference ||= options.delete :ref @@ -260,8 +252,6 @@ class Gem::RequestSet::GemDependencyAPI @git_set.add_git_gem name, repository, reference, submodules - @gem_sources[name] = repository - true end @@ -310,14 +300,10 @@ class Gem::RequestSet::GemDependencyAPI def gem_path name, options # :nodoc: return unless directory = options.delete(:path) - raise ArgumentError, - "duplicate source path: #{directory} for gem #{name}" if - @gem_sources.include? name + pin_gem_source name, :path, directory @vendor_set.add_vendor_gem name, directory - @gem_sources[name] = directory - true end @@ -430,6 +416,28 @@ class Gem::RequestSet::GemDependencyAPI end ## + # Pins the gem +name+ to the given +source+. Adding a gem with the same + # name from a different +source+ will raise an exception. + + def pin_gem_source name, type = :default, source = nil + source_description = + case type + when :default then '(default)' + when :path then "path: #{source}" + when :git then "git: #{source}" + else '(unknown)' + end + + raise ArgumentError, + "duplicate source #{source_description} for gem #{name}" if + @gem_sources.fetch(name, source) != source + + @gem_sources[name] = source + end + + private :pin_gem_source + + ## # :category: Gem Dependencies DSL # # Block form for restricting gems to a particular platform. diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb index d70b09f7a2..81bc4d620d 100644 --- a/lib/rubygems/request_set/lockfile.rb +++ b/lib/rubygems/request_set/lockfile.rb @@ -1,3 +1,5 @@ +require 'strscan' + ## # Parses a gem.deps.rb.lock file and constructs a LockSet containing the # dependencies found inside. If the lock file is missing no LockSet is @@ -29,11 +31,11 @@ class Gem::RequestSet::Lockfile # Raises a ParseError with the given +message+ which was encountered at a # +line+ and +column+ while parsing. - def initialize message, line, column, path + def initialize message, column, line, path @line = line @column = column @path = path - super "#{message} (at #{line}:#{column})" + super "#{message} (at line #{line} column #{column})" end end @@ -62,30 +64,31 @@ class Gem::RequestSet::Lockfile def add_DEPENDENCIES out # :nodoc: out << "DEPENDENCIES" - @set.dependencies.sort.map do |dependency| - source = @requests.find do |req| - req.name == dependency.name and - req.spec.class == Gem::Resolver::VendorSpecification - end - - source_dep = '!' if source + @requests.sort_by { |r| r.name }.each do |request| + spec = request.spec - requirement = dependency.requirement + if [Gem::Resolver::VendorSpecification, + Gem::Resolver::GitSpecification].include? spec.class then + out << " #{request.name}!" + else + requirement = request.request.dependency.requirement - out << " #{dependency.name}#{source_dep}#{requirement.for_lockfile}" + out << " #{request.name}#{requirement.for_lockfile}" + end end out << nil end def add_GEM out # :nodoc: - out << "GEM" + return if @spec_groups.empty? source_groups = @spec_groups.values.flatten.group_by do |request| request.spec.source.uri end - source_groups.map do |group, requests| + source_groups.sort_by { |group,| group.to_s }.map do |group, requests| + out << "GEM" out << " remote: #{group}" out << " specs:" @@ -100,6 +103,33 @@ class Gem::RequestSet::Lockfile out << " #{dependency.name}#{requirement.for_lockfile}" end end + out << nil + end + end + + def add_GIT out + return unless git_requests = + @spec_groups.delete(Gem::Resolver::GitSpecification) + + by_repository_revision = git_requests.group_by do |request| + source = request.spec.source + [source.repository, source.rev_parse] + end + + out << "GIT" + by_repository_revision.each do |(repository, revision), requests| + out << " remote: #{repository}" + out << " revision: #{revision}" + out << " specs:" + + requests.sort_by { |request| request.name }.each do |request| + out << " #{request.name} (#{request.version})" + + dependencies = request.spec.dependencies.sort_by { |dep| dep.name } + dependencies.each do |dep| + out << " #{dep.name}#{dep.requirement.for_lockfile}" + end + end end out << nil @@ -148,27 +178,28 @@ class Gem::RequestSet::Lockfile ## # Gets the next token for a Lockfile - def get expected_type = nil, expected_value = nil # :nodoc: + def get expected_types = nil, expected_value = nil # :nodoc: @current_token = @tokens.shift - type, value, line, column = @current_token + type, value, column, line = @current_token - if expected_type and expected_type != type then + if expected_types and not Array(expected_types).include? type then unget message = "unexpected token [#{type.inspect}, #{value.inspect}], " + - "expected #{expected_type.inspect}" + "expected #{expected_types.inspect}" - raise ParseError.new message, line, column, "#{@gem_deps_file}.lock" + raise ParseError.new message, column, line, "#{@gem_deps_file}.lock" end if expected_value and expected_value != value then unget message = "unexpected token [#{type.inspect}, #{value.inspect}], " + - "expected [#{expected_type.inspect}, #{expected_value.inspect}]" + "expected [#{expected_types.inspect}, " + + "#{expected_value.inspect}]" - raise ParseError.new message, line, column, "#{@gem_deps_file}.lock" + raise ParseError.new message, column, line, "#{@gem_deps_file}.lock" end @current_token @@ -187,6 +218,8 @@ class Gem::RequestSet::Lockfile case data when 'DEPENDENCIES' then parse_DEPENDENCIES + when 'GIT' then + parse_GIT when 'GEM' then parse_GEM when 'PLATFORMS' then @@ -195,7 +228,7 @@ class Gem::RequestSet::Lockfile type, = get until @tokens.empty? or peek.first == :section end else - raise "BUG: unhandled token #{type} (#{data.inspect}) at #{line}:#{column}" + raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}" end end end @@ -204,7 +237,37 @@ class Gem::RequestSet::Lockfile while not @tokens.empty? and :text == peek.first do _, name, = get :text - @set.gem name + requirements = [] + + case peek[0] + when :bang then + get :bang + + git_spec = @set.sets.select { |set| + Gem::Resolver::GitSet === set + }.map { |set| + set.specs[name] + }.first + + requirements << git_spec.version + when :l_paren then + get :l_paren + + loop do + _, op, = get :requirement + _, version, = get :text + + requirements << "#{op} #{version}" + + break unless peek[0] == :comma + + get :comma + end + + get :r_paren + end + + @set.gem name, *requirements skip :newline end @@ -223,20 +286,76 @@ class Gem::RequestSet::Lockfile skip :newline set = Gem::Resolver::LockSet.new source + last_spec = nil while not @tokens.empty? and :text == peek.first do - _, name, = get :text + _, name, column, = get :text case peek[0] - when :newline then # ignore + when :newline then + last_spec.add_dependency Gem::Dependency.new name if column == 6 when :l_paren then get :l_paren - _, version, = get :text + type, data, = get [:text, :requirement] + + if type == :text and column == 4 then + last_spec = set.add name, data, Gem::Platform::RUBY + else + dependency = parse_dependency name, data + + last_spec.add_dependency dependency + end get :r_paren + else + raise "BUG: unknown token #{peek}" + end - set.add name, version, Gem::Platform::RUBY + skip :newline + end + + @set.sets << set + end + + def parse_GIT # :nodoc: + get :entry, 'remote' + _, repository, = get :text + + skip :newline + + get :entry, 'revision' + _, revision, = get :text + + skip :newline + + get :entry, 'specs' + + skip :newline + + set = Gem::Resolver::GitSet.new + last_spec = nil + + while not @tokens.empty? and :text == peek.first do + _, name, column, = get :text + + case peek[0] + when :newline then + last_spec.add_dependency Gem::Dependency.new name if column == 6 + when :l_paren then + get :l_paren + + type, data, = get [:text, :requirement] + + if type == :text and column == 4 then + last_spec = set.add_git_spec name, data, repository, revision, true + else + dependency = parse_dependency name, data + + last_spec.spec.dependencies << dependency + end + + get :r_paren else raise "BUG: unknown token #{peek}" end @@ -258,10 +377,32 @@ class Gem::RequestSet::Lockfile end ## + # Parses the requirements following the dependency +name+ and the +op+ for + # the first token of the requirements and returns a Gem::Dependency object. + + def parse_dependency name, op # :nodoc: + return Gem::Dependency.new name unless peek[0] == :text + + _, version, = get :text + + requirements = ["#{op} #{version}"] + + while peek[0] == :comma do + get :comma + _, op, = get :requirement + _, version, = get :text + + requirements << "#{op} #{version}" + end + + Gem::Dependency.new name, requirements + end + + ## # Peeks at the next token for Lockfile def peek # :nodoc: - @tokens.first + @tokens.first || :EOF end def skip type # :nodoc: @@ -284,6 +425,8 @@ class Gem::RequestSet::Lockfile add_PATH out + add_GIT out + add_GEM out add_PLATFORMS out @@ -321,14 +464,13 @@ class Gem::RequestSet::Lockfile until s.eos? do pos = s.pos - # leading whitespace is for the user's convenience - next if s.scan(/ +/) + pos = s.pos if leading_whitespace = s.scan(/ +/) if s.scan(/[<|=>]{7}/) then message = "your #{lock_file} contains merge conflict markers" - line, column = token_pos pos + column, line = token_pos pos - raise ParseError.new message, line, column, lock_file + raise ParseError.new message, column, line, lock_file end @tokens << @@ -339,7 +481,13 @@ class Gem::RequestSet::Lockfile @line += 1 token when s.scan(/[A-Z]+/) then - [:section, s.matched, *token_pos(pos)] + if leading_whitespace then + text = s.matched + text += s.scan(/[^\s)]*/).to_s # in case of no match + [:text, text, *token_pos(pos)] + else + [:section, s.matched, *token_pos(pos)] + end when s.scan(/([a-z]+):\s/) then s.pos -= 1 # rewind for possible newline [:entry, s[1], *token_pos(pos)] @@ -347,7 +495,13 @@ class Gem::RequestSet::Lockfile [:l_paren, nil, *token_pos(pos)] when s.scan(/\)/) then [:r_paren, nil, *token_pos(pos)] - when s.scan(/[^\s)]*/) then + when s.scan(/<=|>=|=|~>|<|>|!=/) then + [:requirement, s.matched, *token_pos(pos)] + when s.scan(/,/) then + [:comma, nil, *token_pos(pos)] + when s.scan(/!/) then + [:bang, nil, *token_pos(pos)] + when s.scan(/[^\s),!]*/) then [:text, s.matched, *token_pos(pos)] else raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}" diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb index 2b112a8022..ece9d00f38 100644 --- a/lib/rubygems/requirement.rb +++ b/lib/rubygems/requirement.rb @@ -133,7 +133,15 @@ class Gem::Requirement # Formats this requirement for use in a Gem::RequestSet::Lockfile. def for_lockfile # :nodoc: - " (#{to_s})" unless [DefaultRequirement] == @requirements + return if [DefaultRequirement] == @requirements + + list = requirements.sort_by { |_, version| + version + }.map { |op, version| + "#{op} #{version}" + }.uniq + + " (#{list.join ', '})" end ## @@ -147,6 +155,14 @@ class Gem::Requirement end end + ## + # true if the requirement is for only an exact version + + def exact? + return false unless @requirements.size == 1 + @requirements[0][0] == "=" + end + def as_list # :nodoc: requirements.map { |op, version| "#{op} #{version}" }.sort end diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb index 8f11acc197..ad9373cb86 100644 --- a/lib/rubygems/resolver.rb +++ b/lib/rubygems/resolver.rb @@ -36,6 +36,8 @@ class Gem::Resolver attr_reader :missing + attr_reader :stats + ## # When a missing dependency, don't stop. Just go on and record what was # missing. @@ -93,6 +95,7 @@ class Gem::Resolver @development = false @missing = [] @soft_missing = false + @stats = Gem::Resolver::Stats.new end def explain stage, *data # :nodoc: @@ -132,10 +135,13 @@ class Gem::Resolver s.dependencies.reverse_each do |d| next if d.type == :development and not @development reqs.add Gem::Resolver::DependencyRequest.new(d, act) + @stats.requirement! end @set.prefetch reqs + @stats.record_requirements reqs + reqs end @@ -151,8 +157,11 @@ class Gem::Resolver request = Gem::Resolver::DependencyRequest.new n, nil needed.add request + @stats.requirement! end + @stats.record_requirements needed + res = resolve_for needed, nil raise Gem::DependencyResolutionError, res if @@ -268,6 +277,8 @@ class Gem::Resolver states = [] while !needed.empty? + @stats.iteration! + dep = needed.remove explain :try, [dep, dep.requester ? dep.requester.request : :toplevel] explain_list :next5, needed.next5 @@ -279,12 +290,33 @@ class Gem::Resolver next if dep.matches_spec? existing conflict = handle_conflict dep, existing - explain :conflict, conflict.explain - state = find_conflict_state conflict, states + return conflict unless dep.requester + + explain :conflict, dep, :existing, existing.full_name + + depreq = dep.requester.request + + state = nil + until states.empty? + x = states.pop + + i = existing.request.requester + explain :consider, x.spec.full_name, [depreq.name, dep.name, i ? i.name : :top] + + if x.spec.name == depreq.name or + x.spec.name == dep.name or + (i && (i.name == x.spec.name)) + explain :found, x.spec.full_name + state = x + break + end + end return conflict unless state + @stats.backtracking! + needed, specs = resolve_for_conflict needed, specs, state states << state unless state.possibles.empty? @@ -346,6 +378,8 @@ class Gem::Resolver # what makes conflict resolution possible. states << State.new(needed.dup, specs, dep, spec, possible, []) + @stats.record_depth states + explain :states, states.map { |s| s.dep } needed = requests spec, act, needed @@ -404,6 +438,7 @@ require 'rubygems/resolver/activation_request' require 'rubygems/resolver/conflict' require 'rubygems/resolver/dependency_request' require 'rubygems/resolver/requirement_list' +require 'rubygems/resolver/stats' require 'rubygems/resolver/set' require 'rubygems/resolver/api_set' @@ -423,5 +458,6 @@ require 'rubygems/resolver/git_specification' require 'rubygems/resolver/index_specification' require 'rubygems/resolver/installed_specification' require 'rubygems/resolver/local_specification' +require 'rubygems/resolver/lock_specification' require 'rubygems/resolver/vendor_specification' diff --git a/lib/rubygems/resolver/git_set.rb b/lib/rubygems/resolver/git_set.rb index ed809c124f..1a2b230b80 100644 --- a/lib/rubygems/resolver/git_set.rb +++ b/lib/rubygems/resolver/git_set.rb @@ -46,6 +46,32 @@ class Gem::Resolver::GitSet < Gem::Resolver::Set end ## + # Adds and returns a GitSpecification with the given +name+ and +version+ + # which came from a +repository+ at the given +reference+. If +submodules+ + # is true they are checked out along with the repository. + # + # This fills in the prefetch information as enough information about the gem + # is present in the arguments. + + def add_git_spec name, version, repository, reference, submodules # :nodoc: + add_git_gem name, repository, reference, submodules + + source = Gem::Source::Git.new name, repository, reference + source.root_dir = @root_dir + + spec = Gem::Specification.new do |s| + s.name = name + s.version = version + end + + git_spec = Gem::Resolver::GitSpecification.new self, spec, source + + @specs[spec.name] = git_spec + + git_spec + end + + ## # Finds all git gems matching +req+ def find_all req diff --git a/lib/rubygems/resolver/lock_set.rb b/lib/rubygems/resolver/lock_set.rb index ef5395597d..cdb41b22bf 100644 --- a/lib/rubygems/resolver/lock_set.rb +++ b/lib/rubygems/resolver/lock_set.rb @@ -24,10 +24,12 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set version = Gem::Version.new version spec = - Gem::Resolver::IndexSpecification.new self, name, version, @source, - platform + Gem::Resolver::LockSpecification.new self, name, version, @source, + platform @specs << spec + + spec end ## diff --git a/lib/rubygems/resolver/lock_specification.rb b/lib/rubygems/resolver/lock_specification.rb new file mode 100644 index 0000000000..4bc21b9402 --- /dev/null +++ b/lib/rubygems/resolver/lock_specification.rb @@ -0,0 +1,58 @@ +## +# The LockSpecification comes from a lockfile (Gem::RequestSet::Lockfile). +# +# A LockSpecification's dependency information is pre-filled from the +# lockfile. + +class Gem::Resolver::LockSpecification < Gem::Resolver::Specification + + def initialize set, name, version, source, platform + super() + + @name = name + @platform = platform + @set = set + @source = source + @version = version + + @dependencies = [] + @spec = nil + end + + ## + # This is a null install as a locked specification is considered installed. + # +options+ are ignored. + + def install options + destination = options[:install_dir] || Gem.dir + + if File.exist? File.join(destination, 'specifications', spec.spec_name) then + yield nil + return + end + + super + end + + ## + # Adds +dependency+ from the lockfile to this specification + + def add_dependency dependency # :nodoc: + @dependencies << dependency + end + + ## + # A specification constructed from the lockfile is returned + + def spec + @spec ||= Gem::Specification.new do |s| + s.name = @name + s.version = @version + s.platform = @platform + + s.dependencies.concat @dependencies + end + end + +end + diff --git a/lib/rubygems/resolver/requirement_list.rb b/lib/rubygems/resolver/requirement_list.rb index fe1d77afc3..a6bfaab307 100644 --- a/lib/rubygems/resolver/requirement_list.rb +++ b/lib/rubygems/resolver/requirement_list.rb @@ -13,10 +13,12 @@ class Gem::Resolver::RequirementList # Creates a new RequirementList. def initialize + @exact = [] @list = [] end def initialize_copy other # :nodoc: + @exact = @exact.dup @list = @list.dup end @@ -24,7 +26,11 @@ class Gem::Resolver::RequirementList # Adds Resolver::DependencyRequest +req+ to this requirements list. def add(req) - @list.push req + if req.requirement.exact? + @exact.push req + else + @list.push req + end req end @@ -34,22 +40,34 @@ class Gem::Resolver::RequirementList def each # :nodoc: return enum_for __method__ unless block_given? + @exact.each do |requirement| + yield requirement + end + @list.each do |requirement| yield requirement end end ## + # How many elements are in the list + + def size + @exact.size + @list.size + end + + ## # Is the list empty? def empty? - @list.empty? + @exact.empty? && @list.empty? end ## # Remove the oldest DependencyRequest from the list. def remove + return @exact.shift unless @exact.empty? @list.shift end @@ -57,6 +75,7 @@ class Gem::Resolver::RequirementList # Returns the oldest five entries from the list. def next5 - @list[0,5] + x = @exact[0,5] + x + @list[0,5 - x.size] end end diff --git a/lib/rubygems/resolver/stats.rb b/lib/rubygems/resolver/stats.rb new file mode 100644 index 0000000000..c31e5be962 --- /dev/null +++ b/lib/rubygems/resolver/stats.rb @@ -0,0 +1,44 @@ +class Gem::Resolver::Stats + def initialize + @max_depth = 0 + @max_requirements = 0 + @requirements = 0 + @backtracking = 0 + @iterations = 0 + end + + def record_depth(stack) + if stack.size > @max_depth + @max_depth = stack.size + end + end + + def record_requirements(reqs) + if reqs.size > @max_requirements + @max_requirements = reqs.size + end + end + + def requirement! + @requirements += 1 + end + + def backtracking! + @backtracking += 1 + end + + def iteration! + @iterations += 1 + end + + PATTERN = "%20s: %d\n" + + def display + $stdout.puts "=== Resolver Statistics ===" + $stdout.printf PATTERN, "Max Depth", @max_depth + $stdout.printf PATTERN, "Total Requirements", @requirements + $stdout.printf PATTERN, "Max Requirements", @max_requirements + $stdout.printf PATTERN, "Backtracking #", @backtracking + $stdout.printf PATTERN, "Iteration #", @iterations + end +end diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index 9553db18c6..7f34e43528 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -202,7 +202,10 @@ class Gem::Source q.group 2, '[Remote:', ']' do q.breakable q.text @uri.to_s + if api = api_uri + q.breakable + q.text 'API URI: ' q.text api.to_s end end diff --git a/lib/rubygems/source/git.rb b/lib/rubygems/source/git.rb index e8b03165c1..74cbab9562 100644 --- a/lib/rubygems/source/git.rb +++ b/lib/rubygems/source/git.rb @@ -147,6 +147,16 @@ class Gem::Source::Git < Gem::Source File.join base_dir, 'gems', "#{@name}-#{dir_shortref}" end + def pretty_print q # :nodoc: + q.group 2, '[Git: ', ']' do + q.breakable + q.text @repository + + q.breakable + q.text @reference + end + end + ## # The directory where the git gem's repository will be cached. diff --git a/lib/rubygems/source/lock.rb b/lib/rubygems/source/lock.rb index d8a46d8d10..2ba7702bda 100644 --- a/lib/rubygems/source/lock.rb +++ b/lib/rubygems/source/lock.rb @@ -40,5 +40,9 @@ class Gem::Source::Lock < Gem::Source @wrapped.fetch_spec name_tuple end + def uri # :nodoc: + @wrapped.uri + end + end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index f3967aba8b..314682f13b 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -85,6 +85,10 @@ class Gem::TestCase < MiniTest::Unit::TestCase attr_accessor :fetcher # :nodoc: + attr_accessor :gem_repo # :nodoc: + + attr_accessor :uri # :nodoc: + def assert_activate expected, *specs specs.each do |spec| case spec @@ -1196,8 +1200,8 @@ Also, a list: # end # end - def spec_fetcher - Gem::TestCase::SpecFetcherSetup.declare self do |spec_fetcher_setup| + def spec_fetcher repository = @gem_repo + Gem::TestCase::SpecFetcherSetup.declare self, repository do |spec_fetcher_setup| yield spec_fetcher_setup if block_given? end end diff --git a/lib/rubygems/test_utilities.rb b/lib/rubygems/test_utilities.rb index ee5ef01203..3deb71fa46 100644 --- a/lib/rubygems/test_utilities.rb +++ b/lib/rubygems/test_utilities.rb @@ -199,16 +199,17 @@ class Gem::TestCase::SpecFetcherSetup # Executes a SpecFetcher setup block. Yields an instance then creates the # gems and specifications defined in the instance. - def self.declare test - setup = new test + def self.declare test, repository + setup = new test, repository yield setup setup.execute end - def initialize test # :nodoc: - @test = test + def initialize test, repository # :nodoc: + @test = test + @repository = repository @gems = {} @installed = [] @@ -298,12 +299,22 @@ class Gem::TestCase::SpecFetcherSetup require 'socket' require 'rubygems/remote_fetcher' - @test.fetcher = Gem::FakeFetcher.new - Gem::RemoteFetcher.fetcher = @test.fetcher + unless @test.fetcher then + @test.fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @test.fetcher + end Gem::Specification.reset - @test.util_setup_spec_fetcher(*@gems.keys) + begin + gem_repo, @test.gem_repo = @test.gem_repo, @repository + @test.uri = URI @repository + + @test.util_setup_spec_fetcher(*@gems.keys) + ensure + @test.gem_repo = gem_repo + @test.uri = URI gem_repo + end # This works around util_setup_spec_fetcher adding all created gems to the # installed set. @@ -313,7 +324,7 @@ class Gem::TestCase::SpecFetcherSetup @gems.each do |spec, gem| next unless gem - @test.fetcher.data["http://gems.example.com/gems/#{spec.file_name}"] = + @test.fetcher.data["#{@repository}gems/#{spec.file_name}"] = Gem.read_binary(gem) FileUtils.cp gem, spec.cache_file |