class Librarian::Resolver::Implementation
Attributes
cyclic[RW]
resolver[RW]
spec[RW]
Public Class Methods
new(resolver, spec, options = { })
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 36 def initialize(resolver, spec, options = { }) unrecognized_options = options.keys - [:cyclic] unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}" self.resolver = resolver self.spec = spec self.cyclic = !!options[:cyclic] @level = 0 end
Public Instance Methods
resolve(manifests)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 46 def resolve(manifests) manifests = index_by(manifests, &:name) if manifests.kind_of?(Array) queue = spec.dependencies + sourced_dependencies_for_manifests(manifests) state = State.new(manifests.dup, [], queue) do_resolve(state) end
Private Instance Methods
check_manifest(state, manifest)
click to toggle source
When using this method, you are required to check the return value. Returns true
if the manifest satisfies all of the dependencies. Returns false
if there was a dependency that the manifest does not satisfy.
# File lib/librarian/resolver/implementation.rb, line 109 def check_manifest(state, manifest) violation = lambda{|d| d.name == manifest.name && !d.satisfied_by?(manifest)} if q = state.dependencies.find(&violation) || state.queue.find(&violation) debug_conflict manifest, q return false end true end
check_manifest_for_cycles(state, manifest)
click to toggle source
When using this method, you are required to check the return value. Returns true
if the manifest does not introduce a cycle. Returns false
if the manifest introduces a cycle.
# File lib/librarian/resolver/implementation.rb, line 121 def check_manifest_for_cycles(state, manifest) manifests = state.manifests.merge(manifest.name => manifest) known = manifests.keys graph = Hash[manifests.map{|n, m| [n, m.dependencies.map(&:name) & known]}] if Algorithms::AdjacencyListDirectedGraph.cyclic?(graph) debug_cycle manifest return false end true end
debug() { || ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 235 def debug environment.logger.debug { ' ' * @level + yield } end
debug_conflict(dependency, conflict)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 208 def debug_conflict(dependency, conflict) debug { "Conflict between #{dependency} and #{conflict}" } end
debug_cycle(manifest)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 212 def debug_cycle(manifest) debug { "Cycle with #{manifest}" } end
debug_schedule(dependency)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 204 def debug_schedule(dependency) debug { "Scheduling #{dependency}" } end
default_source()
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 132 def default_source @default_source ||= MultiSource.new(spec.sources) end
dependency_source_map()
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 136 def dependency_source_map @dependency_source_map ||= Hash[spec.dependencies.map{|d| [d.name, d.source]}] end
do_resolve(state)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 55 def do_resolve(state) stack = [state] while !stack.empty? do state = stack.pop shift_resolved_enqueued_dependencies(state) or return state.queue.empty? and return state.manifests state.dependencies << state.queue.shift dependency = state.dependencies.last resolving_dependency_map_find_manifests(dependency) do |manifest| check_manifest(state, manifest) or next manifest.exclude_dependencies!(spec.exclusions).each do |d| debug { "Excluding dependency #{d.name} from #{manifest.name}" } end check_manifest_for_cycles(state, manifest) or next unless cyclic m = state.manifests.merge(dependency.name => manifest) a = sourced_dependencies_for_manifest(manifest) s = State.new(m, state.dependencies.dup, state.queue + a) stack.push(s) end end end
environment()
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 239 def environment resolver.environment end
find_inconsistency(state, dependency)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 81 def find_inconsistency(state, dependency) m = state.manifests[dependency.name] dependency.satisfied_by?(m) or return m if m violation = lambda{|d| !dependency.consistent_with?(d)} state.dependencies.find(&violation) || state.queue.find(&violation) end
index_by(enum)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 224 def index_by(enum) Hash[enum.map{|obj| [yield(obj), obj]}] end
map_find(enum) { |obj| ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 216 def map_find(enum) enum.each do |obj| res = yield(obj) res.nil? or return res end nil end
resolving_dependency_map_find_manifests(dependency) { |manifest| ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 157 def resolving_dependency_map_find_manifests(dependency) scope_resolving_dependency dependency do map_find(dependency.manifests) do |manifest| scope_checking_manifest dependency, manifest do yield manifest end end end end
scope() { || ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 228 def scope @level += 1 yield ensure @level -= 1 end
scope_checking_manifest(dependency, manifest) { || ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 190 def scope_checking_manifest(dependency, manifest) debug { "Checking #{manifest}" } resolution = nil scope do resolution = yield if resolution debug { "Resolved #{dependency} at #{manifest}" } else debug { "Backtracking from #{manifest}" } end end resolution end
scope_checking_manifests() { || ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 183 def scope_checking_manifests debug { "Checking manifests" } scope do yield end end
scope_resolving_dependency(dependency) { || ... }
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 167 def scope_resolving_dependency(dependency) debug { "Resolving #{dependency}" } resolution = nil scope do scope_checking_manifests do resolution = yield end if resolution debug { "Resolved #{dependency}" } else debug { "Failed to resolve #{dependency}" } end end resolution end
shift_resolved_enqueued_dependencies(state)
click to toggle source
When using this method, you are required to check the return value. Returns true
if the resolved enqueued dependencies at the front of the queue could all be moved to the resolved dependencies list. Returns false
if there was an inconsistency when trying to move one or more of them. This modifies queue
and dependencies
.
# File lib/librarian/resolver/implementation.rb, line 94 def shift_resolved_enqueued_dependencies(state) while (d = state.queue.first) && state.manifests[d.name] if q = find_inconsistency(state, d) debug_conflict d, q return false end state.dependencies << state.queue.shift end true end
sourced_dependencies_for_manifest(manifest)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 148 def sourced_dependencies_for_manifest(manifest) manifest.dependencies.map{|d| sourced_dependency_for(d)} end
sourced_dependencies_for_manifests(manifests)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 152 def sourced_dependencies_for_manifests(manifests) manifests = manifests.values if manifests.kind_of?(Hash) manifests.map{|m| sourced_dependencies_for_manifest(m)}.flatten(1) end
sourced_dependency_for(dependency)
click to toggle source
# File lib/librarian/resolver/implementation.rb, line 141 def sourced_dependency_for(dependency) return dependency if dependency.source source = dependency_source_map[dependency.name] || default_source dependency.class.new(dependency.name, dependency.requirement, source) end