# 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
# 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) recursive_resolve(state) end
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 102 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
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 114 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
# File lib/librarian/resolver/implementation.rb, line 228 def debug environment.logger.debug { ' ' * @level + yield } end
# File lib/librarian/resolver/implementation.rb, line 201 def debug_conflict(dependency, conflict) debug { "Conflict between #{dependency} and #{conflict}" } end
# File lib/librarian/resolver/implementation.rb, line 205 def debug_cycle(manifest) debug { "Cycle with #{manifest}" } end
# File lib/librarian/resolver/implementation.rb, line 197 def debug_schedule(dependency) debug { "Scheduling #{dependency}" } end
# File lib/librarian/resolver/implementation.rb, line 125 def default_source @default_source ||= MultiSource.new(spec.sources) end
# File lib/librarian/resolver/implementation.rb, line 129 def dependency_source_map @dependency_source_map ||= Hash[spec.dependencies.map{|d| [d.name, d.source]}] end
# File lib/librarian/resolver/implementation.rb, line 232 def environment resolver.environment end
# File lib/librarian/resolver/implementation.rb, line 74 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
# File lib/librarian/resolver/implementation.rb, line 217 def index_by(enum) Hash[enum.map{|obj| [yield(obj), obj]}] end
# File lib/librarian/resolver/implementation.rb, line 209 def map_find(enum) enum.each do |obj| res = yield(obj) res.nil? or return res end nil end
# File lib/librarian/resolver/implementation.rb, line 55 def recursive_resolve(state) 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 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) recursive_resolve(s) end end
# File lib/librarian/resolver/implementation.rb, line 150 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
# File lib/librarian/resolver/implementation.rb, line 221 def scope @level += 1 yield ensure @level -= 1 end
# File lib/librarian/resolver/implementation.rb, line 183 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
# File lib/librarian/resolver/implementation.rb, line 176 def scope_checking_manifests debug { "Checking manifests" } scope do yield end end
# File lib/librarian/resolver/implementation.rb, line 160 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
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 87 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
# File lib/librarian/resolver/implementation.rb, line 141 def sourced_dependencies_for_manifest(manifest) manifest.dependencies.map{|d| sourced_dependency_for(d)} end
# File lib/librarian/resolver/implementation.rb, line 145 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
# File lib/librarian/resolver/implementation.rb, line 134 def sourced_dependency_for(dependency) return dependency if dependency.source source = dependency_source_map[dependency.name] || default_source Dependency.new(dependency.name, dependency.requirement, source) end