summaryrefslogtreecommitdiff
path: root/lib/rubygems/dependency_resolver.rb
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-19 00:34:13 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-19 00:34:13 +0000
commita7fa4d5d9aab150ad4b0c3f3217fe444df69f527 (patch)
tree88ab96d22f7228b556337aa7c34042d4fd279394 /lib/rubygems/dependency_resolver.rb
parente7ec3dad907f2c77f17faddb40a98b2ef4523222 (diff)
* 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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43714 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems/dependency_resolver.rb')
-rw-r--r--lib/rubygems/dependency_resolver.rb364
1 files changed, 0 insertions, 364 deletions
diff --git a/lib/rubygems/dependency_resolver.rb b/lib/rubygems/dependency_resolver.rb
deleted file mode 100644
index 35fbe925ad..0000000000
--- a/lib/rubygems/dependency_resolver.rb
+++ /dev/null
@@ -1,364 +0,0 @@
-require 'rubygems'
-require 'rubygems/dependency'
-require 'rubygems/exceptions'
-require 'rubygems/util/list'
-
-require 'uri'
-require 'net/http'
-
-##
-# Given a set of Gem::Dependency objects as +needed+ and a way to query the
-# set of available specs via +set+, calculates a set of ActivationRequest
-# objects which indicate all the specs that should be activated to meet the
-# all the requirements.
-
-class Gem::DependencyResolver
-
- ##
- # Contains all the conflicts encountered while doing resolution
-
- attr_reader :conflicts
-
- attr_accessor :development
-
- attr_reader :missing
-
- ##
- # When a missing dependency, don't stop. Just go on and record what was
- # missing.
-
- attr_accessor :soft_missing
-
- def self.compose_sets *sets
- sets.compact!
-
- case sets.length
- when 0 then
- raise ArgumentError, 'one set in the composition must be non-nil'
- when 1 then
- sets.first
- else
- Gem::DependencyResolver::ComposedSet.new(*sets)
- end
- end
-
- ##
- # Provide a DependencyResolver that queries only against the already
- # installed gems.
-
- def self.for_current_gems needed
- new needed, Gem::DependencyResolver::CurrentSet.new
- end
-
- ##
- # Create DependencyResolver object which will resolve the tree starting
- # with +needed+ Dependency objects.
- #
- # +set+ is an object that provides where to look for specifications to
- # satisfy the Dependencies. This defaults to IndexSet, which will query
- # rubygems.org.
-
- def initialize needed, set = nil
- @set = set || Gem::DependencyResolver::IndexSet.new
- @needed = needed
-
- @conflicts = []
- @development = false
- @missing = []
- @soft_missing = false
- end
-
- ##
- # Creates an ActivationRequest for the given +dep+ and the last +possible+
- # specification.
- #
- # Returns the Specification and the ActivationRequest
-
- def activation_request dep, possible # :nodoc:
- spec = possible.pop
-
- activation_request =
- Gem::DependencyResolver::ActivationRequest.new spec, dep, possible
-
- return spec, activation_request
- end
-
- def requests s, act, reqs=nil
- s.dependencies.reverse_each do |d|
- next if d.type == :development and not @development
- reqs = Gem::List.new Gem::DependencyResolver::DependencyRequest.new(d, act), reqs
- end
-
- @set.prefetch reqs
-
- reqs
- end
-
- ##
- # Proceed with resolution! Returns an array of ActivationRequest objects.
-
- def resolve
- @conflicts = []
-
- needed = nil
-
- @needed.reverse_each do |n|
- request = Gem::DependencyResolver::DependencyRequest.new n, nil
-
- needed = Gem::List.new request, needed
- end
-
- res = resolve_for needed, nil
-
- raise Gem::DependencyResolutionError, res if
- res.kind_of? Gem::DependencyResolver::DependencyConflict
-
- res.to_a
- end
-
- ##
- # Finds the State in +states+ that matches the +conflict+ so that we can try
- # other possible sets.
- #
- # If no good candidate is found, the first state is tried.
-
- def find_conflict_state conflict, states # :nodoc:
- rejected = []
-
- until states.empty? do
- state = states.pop
-
- if conflict.for_spec? state.spec
- state.conflicts << [state.spec, conflict]
- return state
- end
-
- rejected << state
- end
-
- return rejected.shift
- ensure
- rejected = rejected.concat states
- states.replace rejected
- end
-
- ##
- # Extracts the specifications that may be able to fulfill +dependency+ and
- # returns those that match the local platform and all those that match.
-
- def find_possible dependency # :nodoc:
- all = @set.find_all dependency
- matching_platform = select_local_platforms all
-
- return matching_platform, all
- end
-
- def handle_conflict(dep, existing)
- # There is a conflict! We return the conflict object which will be seen by
- # the caller and be handled at the right level.
-
- # If the existing activation indicates that there are other possibles for
- # it, then issue the conflict on the dependency for the activation itself.
- # 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
- else
- depreq = existing.request.requester.request
- conflict =
- Gem::DependencyResolver::DependencyConflict.new depreq, existing, dep
- end
-
- @conflicts << conflict unless @conflicts.include? conflict
-
- return conflict
- end
-
- # Contains the state for attempting activation of a set of possible specs.
- # +needed+ is a Gem::List of DependencyRequest objects that, well, need
- # to be satisfied.
- # +specs+ is the List of ActivationRequest that are being tested.
- # +dep+ is the DependencyRequest that was used to generate this state.
- # +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
- # activate the state.
- #
- State = Struct.new(:needed, :specs, :dep, :spec, :possibles, :conflicts) do
- def summary # :nodoc:
- nd = needed.map { |s| s.to_s }.sort if nd
-
- if specs then
- ss = specs.map { |s| s.full_name }.sort
- ss.unshift ss.length
- end
-
- d = dep.to_s
- d << " from #{dep.requester.full_name}" if dep.requester
-
- ps = possibles.map { |p| p.full_name }.sort
- ps.unshift ps.length
-
- cs = conflicts.map do |(s, c)|
- [s.full_name, c.conflicting_dependencies.map { |cd| cd.to_s }]
- end
-
- { :needed => nd, :specs => ss, :dep => d, :spec => spec.full_name,
- :possibles => ps, :conflicts => cs }
- end
- end
-
- ##
- # The meat of the algorithm. Given +needed+ DependencyRequest objects and
- # +specs+ being a list to ActivationRequest, calculate a new list of
- # ActivationRequest objects.
-
- def resolve_for needed, specs
- # The State objects that are used to attempt the activation tree.
- states = []
-
- while needed
- dep = needed.value
- needed = needed.tail
-
- # If there is already a spec activated for the requested name...
- if specs && existing = specs.find { |s| dep.name == s.name }
- # then we're done since this new dep matches the existing spec.
- next if dep.matches_spec? existing
-
- conflict = handle_conflict dep, existing
-
- state = find_conflict_state conflict, states
-
- return conflict unless state
-
- needed, specs = resolve_for_conflict needed, specs, state
-
- states << state unless state.possibles.empty?
-
- next
- end
-
- matching, all = find_possible dep
-
- case matching.size
- when 0
- resolve_for_zero dep, all
- when 1
- needed, specs =
- resolve_for_single needed, specs, dep, matching
- else
- needed, specs =
- resolve_for_multiple needed, specs, states, dep, matching
- end
- end
-
- specs
- end
-
- ##
- # Rewinds +needed+ and +specs+ to a previous state in +state+ for a conflict
- # between +dep+ and +existing+.
-
- def resolve_for_conflict needed, specs, state # :nodoc:
- # We exhausted the possibles so it's definitely not going to work out,
- # bail out.
- raise Gem::ImpossibleDependenciesError.new state.dep, state.conflicts if
- state.possibles.empty?
-
- # Retry resolution with this spec and add it's dependencies
- spec, act = activation_request state.dep, state.possibles
-
- needed = requests spec, act, state.needed
- specs = Gem::List.prepend state.specs, act
-
- return needed, specs
- end
-
- ##
- # There are multiple +possible+ specifications for this +dep+. Updates
- # +needed+, +specs+ and +states+ for further resolution of the +possible+
- # choices.
-
- def resolve_for_multiple needed, specs, states, dep, possible # :nodoc:
- # Sort them so that we try the highest versions first.
- possible = possible.sort_by do |s|
- [s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
- end
-
- spec, act = activation_request dep, possible
-
- # 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, [])
-
- needed = requests spec, act, needed
- specs = Gem::List.prepend specs, act
-
- return needed, specs
- end
-
- ##
- # Add the spec from the +possible+ list to +specs+ and process the spec's
- # dependencies by adding them to +needed+.
-
- def resolve_for_single needed, specs, dep, possible # :nodoc:
- spec, act = activation_request dep, possible
-
- specs = Gem::List.prepend specs, act
-
- # Put the deps for at the beginning of needed
- # rather than the end to match the depth first
- # searching done by the multiple case code below.
- #
- # This keeps the error messages consistent.
- needed = requests spec, act, needed
-
- return needed, specs
- end
-
- ##
- # When there are no possible specifications for +dep+ our work is done.
-
- def resolve_for_zero dep, platform_mismatch # :nodoc:
- @missing << dep
-
- unless @soft_missing
- raise Gem::UnsatisfiableDependencyError.new(dep, platform_mismatch)
- end
- end
-
- ##
- # Returns the gems in +specs+ that match the local platform.
-
- def select_local_platforms specs # :nodoc:
- specs.select do |spec|
- Gem::Platform.installable? spec
- end
- end
-
-end
-
-require 'rubygems/dependency_resolver/activation_request'
-require 'rubygems/dependency_resolver/dependency_conflict'
-require 'rubygems/dependency_resolver/dependency_request'
-
-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'
-
-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'
-