Class: Bundler::Molinillo::Resolver::Resolution
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb |
Overview
A specific resolution from a given ::Bundler::Molinillo::Resolver
Class Method Summary
-
.new(specification_provider, resolver_ui, requested, base) ⇒ Resolution
constructor
Initializes a new resolution.
Instance Attribute Summary
- #base ⇒ DependencyGraph readonly
- #original_requested ⇒ Array readonly
- #resolver_ui ⇒ UI readonly
- #specification_provider ⇒ SpecificationProvider readonly
- #iteration_rate ⇒ Integer rw private
- #started_at ⇒ Time rw private
- #states ⇒ Array<ResolutionState> rw private
Instance Method Summary
-
#resolve ⇒ DependencyGraph
Resolves the #original_requested dependencies into a full dependency.
-
#activate_new_spec ⇒ void
private
Add the current #possibility to the dependency graph of the current #state
-
#attempt_to_activate ⇒ void
private
Attempts to activate the current #possibility
-
#attempt_to_filter_existing_spec(vertex) ⇒ void
private
Attempts to update the existing vertex’s
PossibilitySet
with a filtered version. - #binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) ⇒ Boolean private
- #binding_requirements_for_conflict(conflict) ⇒ Array private
- #build_details_for_unwind ⇒ UnwindDetails private
- #conflict_fixing_possibilities?(state, binding_requirements) ⇒ Boolean private
- #create_conflict(underlying_error = nil) ⇒ Conflict private
-
#debug(depth = 0, &block) ⇒ void
private
Calls the #resolver_ui‘s UI#debug method.
-
#end_resolution ⇒ void
private
Ends the resolution process.
-
#filter_possibilities_after_unwind(unwind_details) ⇒ void
private
Filter’s a state’s possibilities to remove any that would not fix the conflict we’ve just rewound from.
-
#filter_possibilities_for_parent_unwind(unwind_details) ⇒ void
private
Filter’s a state’s possibilities to remove any that would (eventually) create a requirement in the conflict we’ve just rewound from.
-
#filter_possibilities_for_primary_unwind(unwind_details) ⇒ void
private
Filter’s a state’s possibilities to remove any that would not satisfy the requirements in the conflict we’ve just rewound from.
-
#filtered_possibility_set(vertex) ⇒ PossibilitySet
private
Generates a filtered version of the existing vertex’s
PossibilitySet
using the current state’srequirement
- #find_state_for(requirement) ⇒ ResolutionState private
-
#group_possibilities(possibilities) ⇒ Array<PossibilitySet>
private
Build an array of PossibilitySets, with each element representing a group of dependency versions that all have the same sub-dependency version constraints and are contiguous.
-
#handle_missing_or_push_dependency_state(state) ⇒ void
private
Pushes a new
::Bundler::Molinillo::DependencyState
. -
#indicate_progress ⇒ void
private
Indicates progress roughly once every second.
- #locked_requirement_named(requirement_name) ⇒ Object private
- #locked_requirement_possibility_set(requirement, activated = self.activated) ⇒ Array private
- #parent_of(requirement) ⇒ Object private
-
#possibilities_for_requirement(requirement, activated = self.activated) ⇒ Array
private
Checks a proposed requirement with any existing locked requirement before generating an array of possibilities for it.
- #possibility ⇒ Object private
- #possibility_satisfies_requirements?(possibility, requirements) ⇒ Boolean private
-
#process_topmost_state ⇒ void
private
Processes the topmost available
RequirementState
on the stack. -
#push_initial_state ⇒ void
private
Creates and pushes the initial state for the resolution, based upon the
#requested
dependencies. -
#push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) ⇒ void
private
Pushes a new
::Bundler::Molinillo::DependencyState
that encapsulates both existing and new requirements. -
#raise_error_unless_state(conflicts) ⇒ void
private
Raises a
::Bundler::Molinillo::VersionConflict
error, or any underlying error, if there is no current state. -
#require_nested_dependencies_for(possibility_set) ⇒ void
private
Requires the dependencies that the recently activated spec has.
- #requirement_for_existing_name(name) ⇒ Object private
- #requirement_tree_for(requirement) ⇒ Array<Object> private
- #requirement_trees ⇒ Array<Array<Object>> private
- #resolve_activated_specs private
-
#start_resolution ⇒ void
private
Sets up the resolution process.
- #state ⇒ RequirementState private
-
#unwind_for_conflict ⇒ void
private
Unwinds the states stack because a conflict has been encountered.
- #unwind_options_for_requirements(binding_requirements) ⇒ Array<UnwindDetails> private
::Bundler::Molinillo::Delegates::SpecificationProvider
- Included
#allow_missing? | Returns whether this dependency, which has no possible matching specifications, can safely be ignored. |
#dependencies_equal? | Determines whether two arrays of dependencies are equal, and thus can be grouped. |
#dependencies_for | Returns the dependencies of |
#name_for | Returns the name for the given |
#name_for_explicit_dependency_source, #name_for_locking_dependency_source, | |
#requirement_satisfied_by? | Determines whether the given |
#search_for | Search for the specifications that match the given dependency. |
#sort_dependencies | Sort dependencies so that the ones that are easiest to resolve are first. |
#with_no_such_dependency_error_handling | Ensures any raised |
::Bundler::Molinillo::Delegates::ResolutionState
- Included
#activated | A state that a |
#conflicts | A state that a |
#depth | A state that a |
#name | A state that a |
#possibilities | A state that a |
#requirement | A state that a |
#requirements | A state that a |
#unused_unwind_options | A state that a |
Constructor Details
.new(specification_provider, resolver_ui, requested, base) ⇒ Resolution
Initializes a new resolution.
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 152
def initialize(specification_provider, resolver_ui, requested, base) @specification_provider = specification_provider @resolver_ui = resolver_ui @original_requested = requested @base = base @states = [] @iteration_counter = 0 @parents_of = Hash.new { |h, k| h[k] = [] } end
Instance Attribute Details
#base ⇒ DependencyGraph (readonly)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 141
attr_reader :base
#iteration_rate ⇒ Integer
(rw, private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 192
attr_accessor :iteration_rate
#original_requested ⇒ Array
(readonly)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 144
attr_reader :original_requested
#resolver_ui ⇒ UI (readonly)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 137
attr_reader :resolver_ui
#specification_provider ⇒ SpecificationProvider (readonly)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 133
attr_reader :specification_provider
#started_at ⇒ Time
(rw, private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 196
attr_accessor :started_at
#states ⇒ Array
<ResolutionState> (rw, private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 200
attr_accessor :states
Instance Method Details
#activate_new_spec ⇒ void
(private)
This method returns an undefined value.
Add the current #possibility to the dependency graph of the current #state
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 723
def activate_new_spec conflicts.delete(name) debug(depth) { "Activated #{name} at #{possibility}" } activated.set_payload(name, possibility) require_nested_dependencies_for(possibility) end
#attempt_to_activate ⇒ void
(private)
This method returns an undefined value.
Attempts to activate the current #possibility
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 667
def attempt_to_activate debug(depth) { 'Attempting to activate ' + possibility.to_s } existing_vertex = activated.vertex_named(name) if existing_vertex.payload debug(depth) { "Found existing spec (#{existing_vertex.payload})" } attempt_to_filter_existing_spec(existing_vertex) else latest = possibility.latest_version possibility.possibilities.select! do |possibility| requirement_satisfied_by?(requirement, activated, possibility) end if possibility.latest_version.nil? # ensure there's a possibility for better error messages possibility.possibilities << latest if latest create_conflict unwind_for_conflict else activate_new_spec end end end
#attempt_to_filter_existing_spec(vertex) ⇒ void
(private)
This method returns an undefined value.
Attempts to update the existing vertex’s Resolution::PossibilitySet
with a filtered version
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 691
def attempt_to_filter_existing_spec(vertex) filtered_set = filtered_possibility_set(vertex) if !filtered_set.possibilities.empty? activated.set_payload(name, filtered_set) new_requirements = requirements.dup push_state_for_requirements(new_requirements, false) else create_conflict debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" } unwind_for_conflict end end
#binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) ⇒ Boolean
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 559
def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) possibilities.any? do |poss| possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement]) end end
#binding_requirements_for_conflict(conflict) ⇒ Array
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 516
def binding_requirements_for_conflict(conflict) return [conflict.requirement] if conflict.possibility.nil? possible_binding_requirements = conflict.requirements.values.flatten(1).uniq # When there's a `CircularDependency` error the conflicting requirement # (the one causing the circular) won't be `conflict.requirement` # (which won't be for the right state, because we won't have created it, # because it's circular). # We need to make sure we have that requirement in the conflict's list, # otherwise we won't be able to unwind properly, so we just return all # the requirements for the conflict. return possible_binding_requirements if conflict. possibilities = search_for(conflict.requirement) # If all the requirements together don't filter out all possibilities, # then the only two requirements we need to consider are the initial one # (where the dependency's version was first chosen) and the last if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities) return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact end # Loop through the possible binding requirements, removing each one # that doesn't bind. Use a `reverse_each` as we want the earliest set of # binding requirements, and don't use `reject!` as we wish to refine the # array *on each iteration*. binding_requirements = possible_binding_requirements.dup possible_binding_requirements.reverse_each do |req| next if req == conflict.requirement unless binding_requirement_in_set?(req, binding_requirements, possibilities) binding_requirements -= [req] end end binding_requirements end
#build_details_for_unwind ⇒ UnwindDetails (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 321
def build_details_for_unwind # Get the possible unwinds for the current conflict current_conflict = conflicts[name] binding_requirements = binding_requirements_for_conflict(current_conflict) unwind_details = (binding_requirements) last_detail_for_current_unwind = unwind_details.sort.last current_detail = last_detail_for_current_unwind # Look for past conflicts that could be unwound to affect the # requirement tree for the current conflict all_reqs = last_detail_for_current_unwind.all_requirements all_reqs_size = all_reqs.size relevant_unused_unwinds = .select do |alternative| diff_reqs = all_reqs - alternative.requirements_unwound_to_instead next if diff_reqs.size == all_reqs_size # Find the highest index unwind whilst looping through current_detail = alternative if alternative > current_detail alternative end # Add the current unwind options to the `unused_unwind_options` array. # The "used" option will be filtered out during `unwind_for_conflict`. state. += unwind_details.reject { |detail| detail.state_index == -1 } # Update the requirements_unwound_to_instead on any relevant unused unwinds relevant_unused_unwinds.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end unwind_details.each do |d| (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! end current_detail end
#conflict_fixing_possibilities?(state, binding_requirements) ⇒ Boolean
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 428
def conflict_fixing_possibilities?(state, binding_requirements) return false unless state state.possibilities.any? do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, binding_requirements) end end end
#create_conflict(underlying_error = nil) ⇒ Conflict (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 595
def create_conflict( = nil) vertex = activated.vertex_named(name) locked_requirement = locked_requirement_named(name) requirements = {} unless vertex.explicit_requirements.empty? requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements end requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement vertex.incoming_edges.each do |edge| (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement) end activated_by_name = {} activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload } conflicts[name] = Conflict.new( requirement, requirements, vertex.payload && vertex.payload.latest_version, possibility, locked_requirement, requirement_trees, activated_by_name, ) end
#debug(depth = 0, &block) ⇒ void
(private)
This method returns an undefined value.
Calls the #resolver_ui‘s UI#debug method
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 661
def debug(depth = 0, &block) resolver_ui.debug(depth, &block) end
#end_resolution ⇒ void
(private)
This method returns an undefined value.
Ends the resolution process
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 231
def end_resolution resolver_ui.after_resolution debug do "Finished resolution (#{@iteration_counter} steps) " \ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})" end debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state end
#filter_possibilities_after_unwind(unwind_details) ⇒ void
(private)
This method returns an undefined value.
Filter’s a state’s possibilities to remove any that would not fix the conflict we’ve just rewound from
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 443
def filter_possibilities_after_unwind(unwind_details) return unless state && !state.possibilities.empty? if unwind_details.unwinding_to_primary_requirement? filter_possibilities_for_primary_unwind(unwind_details) else filter_possibilities_for_parent_unwind(unwind_details) end end
#filter_possibilities_for_parent_unwind(unwind_details) ⇒ void
(private)
This method returns an undefined value.
Filter’s a state’s possibilities to remove any that would (eventually) create a requirement in the conflict we’ve just rewound from
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 490
def filter_possibilities_for_parent_unwind(unwind_details) unwinds_to_state = .select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq parent_unwinds = unwinds_to_state.uniq - primary_unwinds allowed_possibility_sets = primary_unwinds.flat_map do |unwind| states[unwind.state_index].possibilities.select do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, unwind.conflicting_requirements) end end end requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid) state.possibilities.reject! do |possibility_set| !allowed_possibility_sets.include?(possibility_set) && (requirements_to_avoid - possibility_set.dependencies).empty? end end
#filter_possibilities_for_primary_unwind(unwind_details) ⇒ void
(private)
This method returns an undefined value.
Filter’s a state’s possibilities to remove any that would not satisfy the requirements in the conflict we’ve just rewound from
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 457
def filter_possibilities_for_primary_unwind(unwind_details) unwinds_to_state = .select { |uw| uw.state_index == unwind_details.state_index } unwinds_to_state << unwind_details unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements) state.possibilities.reject! do |possibility_set| possibility_set.possibilities.none? do |poss| unwind_requirement_sets.any? do |requirements| possibility_satisfies_requirements?(poss, requirements) end end end end
#filtered_possibility_set(vertex) ⇒ PossibilitySet (private)
Generates a filtered version of the existing vertex’s Resolution::PossibilitySet
using the current state’s requirement
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 708
def filtered_possibility_set(vertex) PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) end
#find_state_for(requirement) ⇒ ResolutionState (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 587
def find_state_for(requirement) return nil unless requirement states.find { |i| requirement == i.requirement } end
#group_possibilities(possibilities) ⇒ Array
<PossibilitySet> (private)
Build an array of PossibilitySets, with each element representing a group of dependency versions that all have the same sub-dependency version constraints and are contiguous.
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 804
def group_possibilities(possibilities) possibility_sets = [] current_possibility_set = nil possibilities.reverse_each do |possibility| dependencies = dependencies_for(possibility) if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies) current_possibility_set.possibilities.unshift(possibility) else possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) current_possibility_set = possibility_sets.first end end possibility_sets end
#handle_missing_or_push_dependency_state(state) ⇒ void
(private)
This method returns an undefined value.
Pushes a new ::Bundler::Molinillo::DependencyState
. If the #specification_provider says to SpecificationProvider#allow_missing? that particular requirement, and there are no possibilities for that requirement, then #state is not pushed, and the vertex in #activated
is removed, and we continue resolving the remaining requirements.
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 829
def handle_missing_or_push_dependency_state(state) if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement) state.activated.detach_vertex_named(state.name) push_state_for_requirements(state.requirements.dup, false, state.activated) else states.push(state).tap { activated.tag(state) } end end
#indicate_progress ⇒ void
(private)
This method returns an undefined value.
Indicates progress roughly once every second
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 643
def indicate_progress @iteration_counter += 1 @progress_rate ||= resolver_ui.progress_rate if iteration_rate.nil? if Time.now - started_at >= @progress_rate self.iteration_rate = @iteration_counter end end if iteration_rate && (@iteration_counter % iteration_rate) == 0 resolver_ui.indicate_progress end end
#locked_requirement_named(requirement_name) ⇒ Object
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 715
def locked_requirement_named(requirement_name) vertex = base.vertex_named(requirement_name) vertex && vertex.payload end
#locked_requirement_possibility_set(requirement, activated = self.activated) ⇒ Array
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 785
def locked_requirement_possibility_set(requirement, activated = self.activated) all_possibilities = search_for(requirement) locked_requirement = locked_requirement_named(name_for(requirement)) # Longwinded way to build a possibilities array with either the locked # requirement or nothing in it. Required, since the API for # locked_requirement isn't guaranteed. locked_possibilities = all_possibilities.select do |possibility| requirement_satisfied_by?(locked_requirement, activated, possibility) end group_possibilities(locked_possibilities) end
#parent_of(requirement) ⇒ Object
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 568
def parent_of(requirement) return unless requirement return unless index = @parents_of[requirement].last return unless parent_state = @states[index] parent_state.requirement end
#possibilities_for_requirement(requirement, activated = self.activated) ⇒ Array
(private)
Checks a proposed requirement with any existing locked requirement before generating an array of possibilities for it.
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 773
def possibilities_for_requirement(requirement, activated = self.activated) return [] unless requirement if locked_requirement_named(name_for(requirement)) return locked_requirement_possibility_set(requirement, activated) end group_possibilities(search_for(requirement)) end
#possibility ⇒ Object
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 266
def possibility possibilities.last end
#possibility_satisfies_requirements?(possibility, requirements) ⇒ Boolean
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 475
def possibility_satisfies_requirements?(possibility, requirements) name = name_for(possibility) activated.tag(:swap) activated.set_payload(name, possibility) if activated.vertex_named(name) satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } activated.rewind_to(:swap) satisfied end
#process_topmost_state ⇒ void
(private)
This method returns an undefined value.
Processes the topmost available RequirementState
on the stack
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 252
def process_topmost_state if possibility attempt_to_activate else create_conflict unwind_for_conflict end rescue CircularDependencyError => create_conflict( ) unwind_for_conflict end
#push_initial_state ⇒ void
(private)
This method returns an undefined value.
Creates and pushes the initial state for the resolution, based upon the #requested
dependencies
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 279
def push_initial_state graph = DependencyGraph.new.tap do |dg| original_requested.each do |requested| vertex = dg.add_vertex(name_for(requested), nil, true) vertex.explicit_requirements << requested end dg.tag(:initial_state) end push_state_for_requirements(original_requested, true, graph) end
#push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) ⇒ void
(private)
This method returns an undefined value.
Pushes a new ::Bundler::Molinillo::DependencyState
that encapsulates both existing and new requirements
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 753
def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort new_requirement = nil loop do new_requirement = new_requirements.shift break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement } end new_name = new_requirement ? name_for(new_requirement) : ''.freeze possibilities = possibilities_for_requirement(new_requirement) handle_missing_or_push_dependency_state DependencyState.new( new_name, new_requirements, new_activated, new_requirement, possibilities, depth, conflicts.dup, .dup ) end
#raise_error_unless_state(conflicts) ⇒ void
(private)
This method returns an undefined value.
Raises a ::Bundler::Molinillo::VersionConflict
error, or any underlying error, if there is no current state
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 313
def raise_error_unless_state(conflicts) return if state error = conflicts.values.map(&: ).compact.first raise error || VersionConflict.new(conflicts, specification_provider) end
#require_nested_dependencies_for(possibility_set) ⇒ void
(private)
This method returns an undefined value.
Requires the dependencies that the recently activated spec has
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 734
def require_nested_dependencies_for(possibility_set) nested_dependencies = dependencies_for(possibility_set.latest_version) debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each do |d| activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d) parent_index = states.size - 1 parents = @parents_of[d] parents << parent_index if parents.empty? end push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?) end
#requirement_for_existing_name(name) ⇒ Object
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 578
def requirement_for_existing_name(name) return nil unless vertex = activated.vertex_named(name) return nil unless vertex.payload states.find { |s| s.name == name }.requirement end
#requirement_tree_for(requirement) ⇒ Array
<Object
> (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 632
def requirement_tree_for(requirement) tree = [] while requirement tree.unshift(requirement) requirement = parent_of(requirement) end tree end
#requirement_trees ⇒ Array
<Array
<Object
>> (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 624
def requirement_trees vertex = activated.vertex_named(name) vertex.requirements.map { |r| requirement_tree_for(r) } end
#resolve ⇒ DependencyGraph
Resolves the #original_requested dependencies into a full dependency
graph
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 167
def resolve start_resolution while state break if !state.requirement && state.requirements.empty? indicate_progress if state.respond_to?(:pop_possibility_state) # DependencyState debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" } state.pop_possibility_state.tap do |s| if s states.push(s) activated.tag(s) end end end process_topmost_state end resolve_activated_specs ensure end_resolution end
#resolve_activated_specs (private)
[ GitHub ]# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 216
def resolve_activated_specs activated.vertices.each do |_, vertex| next unless vertex.payload latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } end activated.set_payload(vertex.name, latest_version) end activated.freeze end
#start_resolution ⇒ void
(private)
This method returns an undefined value.
Sets up the resolution process
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 207
def start_resolution @started_at = Time.now push_initial_state debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } resolver_ui.before_resolution end
#state ⇒ RequirementState
(private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 272
def state states.last end
#unwind_for_conflict ⇒ void
(private)
This method returns an undefined value.
Unwinds the states stack because a conflict has been encountered
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 293
def unwind_for_conflict details_for_unwind = build_details_for_unwind = debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" } conflicts.tap do |c| sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1) raise_error_unless_state(c) activated.rewind_to(sliced_states.first || :initial_state) if sliced_states state.conflicts = c state. = filter_possibilities_after_unwind(details_for_unwind) index = states.size - 1 @parents_of.each { |_, a| a.reject! { |i| i >= index } } state. .reject! { |uw| uw.state_index >= index } end end
#unwind_options_for_requirements(binding_requirements) ⇒ Array
<UnwindDetails> (private)
# File 'lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb', line 360
def (binding_requirements) unwind_details = [] trees = [] binding_requirements.reverse_each do |r| partial_tree = [r] trees << partial_tree unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, []) # If this requirement has alternative possibilities, check if any would # satisfy the other requirements that created this conflict requirement_state = find_state_for(r) if conflict_fixing_possibilities?(requirement_state, binding_requirements) unwind_details << UnwindDetails.new( states.index(requirement_state), r, partial_tree, binding_requirements, trees, [] ) end # Next, look at the parent of this requirement, and check if the requirement # could have been avoided if an alternative PossibilitySet had been chosen parent_r = parent_of(r) next if parent_r.nil? partial_tree.unshift(parent_r) requirement_state = find_state_for(parent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) } unwind_details << UnwindDetails.new( states.index(requirement_state), parent_r, partial_tree, binding_requirements, trees, [] ) end # Finally, look at the grandparent and up of this requirement, looking # for any possibilities that wouldn't create their parent requirement grandparent_r = parent_of(parent_r) until grandparent_r.nil? partial_tree.unshift(grandparent_r) requirement_state = find_state_for(grandparent_r) if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) } unwind_details << UnwindDetails.new( states.index(requirement_state), grandparent_r, partial_tree, binding_requirements, trees, [] ) end parent_r = grandparent_r grandparent_r = parent_of(parent_r) end end unwind_details end