diff options
Diffstat (limited to 'ruby_2_2/lib/rubygems/resolver.rb')
-rw-r--r-- | ruby_2_2/lib/rubygems/resolver.rb | 485 |
1 files changed, 0 insertions, 485 deletions
diff --git a/ruby_2_2/lib/rubygems/resolver.rb b/ruby_2_2/lib/rubygems/resolver.rb deleted file mode 100644 index ef17d682ac..0000000000 --- a/ruby_2_2/lib/rubygems/resolver.rb +++ /dev/null @@ -1,485 +0,0 @@ -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::Resolver - - ## - # If the DEBUG_RESOLVER environment variable is set then debugging mode is - # enabled for the resolver. This will display information about the state - # of the resolver while a set of dependencies is being resolved. - - DEBUG_RESOLVER = !ENV['DEBUG_RESOLVER'].nil? - - require 'pp' if DEBUG_RESOLVER - - ## - # Contains all the conflicts encountered while doing resolution - - attr_reader :conflicts - - ## - # Set to true if all development dependencies should be considered. - - attr_accessor :development - - ## - # Set to true if immediate development dependencies should be considered. - - attr_accessor :development_shallow - - ## - # When true, no dependencies are looked up for requested gems. - - attr_accessor :ignore_dependencies - - ## - # List of dependencies that could not be found in the configured sources. - - attr_reader :missing - - attr_reader :stats - - ## - # Hash of gems to skip resolution. Keyed by gem name, with arrays of - # gem specifications as values. - - attr_accessor :skip_gems - - ## - # When a missing dependency, don't stop. Just go on and record what was - # missing. - - attr_accessor :soft_missing - - ## - # Combines +sets+ into a ComposedSet that allows specification lookup in a - # uniform manner. If one of the +sets+ is itself a ComposedSet its sets are - # flattened into the result ComposedSet. - - def self.compose_sets *sets - sets.compact! - - sets = sets.map do |set| - case set - when Gem::Resolver::BestSet then - set - when Gem::Resolver::ComposedSet then - set.sets - else - set - end - end.flatten - - case sets.length - when 0 then - raise ArgumentError, 'one set in the composition must be non-nil' - when 1 then - sets.first - else - Gem::Resolver::ComposedSet.new(*sets) - end - end - - ## - # Creates a Resolver that queries only against the already installed gems - # for the +needed+ dependencies. - - def self.for_current_gems needed - new needed, Gem::Resolver::CurrentSet.new - end - - ## - # 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 - # satisfy the Dependencies. This defaults to IndexSet, which will query - # rubygems.org. - - def initialize needed, set = nil - @set = set || Gem::Resolver::IndexSet.new - @needed = needed - - @conflicts = [] - @development = false - @development_shallow = false - @ignore_dependencies = false - @missing = [] - @skip_gems = {} - @soft_missing = false - @stats = Gem::Resolver::Stats.new - end - - def explain stage, *data # :nodoc: - return unless DEBUG_RESOLVER - - d = data.map { |x| x.pretty_inspect }.join(", ") - $stderr.printf "%10s %s\n", stage.to_s.upcase, d - end - - def explain_list stage # :nodoc: - return unless DEBUG_RESOLVER - - data = yield - $stderr.printf "%10s (%d entries)\n", stage.to_s.upcase, data.size - PP.pp data, $stderr unless data.empty? - 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 - - explain :activate, [spec.full_name, possible.size] - explain :possible, possible - - activation_request = - Gem::Resolver::ActivationRequest.new spec, dep, possible - - return spec, activation_request - end - - def requests s, act, reqs=nil # :nodoc: - return reqs if @ignore_dependencies - - s.fetch_development_dependencies if @development - - s.dependencies.reverse_each do |d| - next if d.type == :development and not @development - next if d.type == :development and @development_shallow and - act.development? - next if d.type == :development and @development_shallow and - act.parent - - reqs.add Gem::Resolver::DependencyRequest.new(d, act) - @stats.requirement! - end - - @set.prefetch reqs - - @stats.record_requirements reqs - - reqs - end - - ## - # Proceed with resolution! Returns an array of ActivationRequest objects. - - def resolve - @conflicts = [] - - needed = Gem::Resolver::RequirementList.new - - @needed.reverse_each do |n| - 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 - res.kind_of? Gem::Resolver::Conflict - - res.to_a - 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 - - if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty? - matching = all.select do |api_spec| - skip_dep_gems.any? { |s| api_spec.version == s.version } - end - - all = matching unless matching.empty? - end - - matching_platform = select_local_platforms all - - return matching_platform, all - end - - def handle_conflict(dep, existing) # :nodoc: - # 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, if there was a requester, issue it on the requester's - # request itself. - # Finally, if the existing request has no requester (toplevel) unwind to - # it anyway. - - if existing.others_possible? - conflict = - Gem::Resolver::Conflict.new dep, existing - elsif dep.requester - depreq = dep.requester.request - conflict = - Gem::Resolver::Conflict.new depreq, existing, dep - elsif existing.request.requester.nil? - conflict = - Gem::Resolver::Conflict.new dep, existing - else - raise Gem::DependencyError, "Unable to figure out how to unwind conflict" - 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, Conflict] 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 # :nodoc: - # The State objects that are used to attempt the activation tree. - states = [] - - while !needed.empty? - @stats.iteration! - - dep = needed.remove - explain :try, [dep, dep.requester ? dep.requester.request : :toplevel] - explain_list(:next5) { needed.next5 } - explain_list(:specs) { Array(specs).map { |x| x.full_name }.sort } - - # 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 - - 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? - - 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.dup - 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.dup, specs, dep, spec, possible, []) - - @stats.record_depth states - - explain :states, states.map { |s| s.dep } - - 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 - exc = Gem::UnsatisfiableDependencyError.new dep, platform_mismatch - exc.errors = @set.errors - - raise exc - 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 - -## -# TODO remove in RubyGems 3 - -Gem::DependencyResolver = Gem::Resolver # :nodoc: - -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' -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/local_specification' -require 'rubygems/resolver/lock_specification' -require 'rubygems/resolver/vendor_specification' - |