Class: Inspec::Resolver
- Inherits:
-
Object
- Object
- Inspec::Resolver
- Includes:
- Molinillo::UI
- Defined in:
- lib/inspec/dependencies.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#allow_missing?(_dependency) ⇒ Boolean
Returns whether this dependency, which has no possible matching specifications, can safely be ignored.
-
#dependencies_for(specification) ⇒ Array<Object>
Returns the dependencies of ‘specification`.
-
#initialize(vendor_index, opts = {}) ⇒ Resolver
constructor
A new instance of Resolver.
-
#name_for(dependency) ⇒ String
Returns the name for the given ‘dependency`.
-
#name_for_explicit_dependency_source ⇒ String
The name of the source of explicit dependencies, i.e.
-
#name_for_locking_dependency_source ⇒ String
The name of the source of ‘locked’ dependencies, i.e.
-
#output ⇒ IO
The IO object that should be used to print output.
- #print(what = '') ⇒ Object (also: #puts)
-
#requirement_satisfied_by?(requirement, _activated, spec) ⇒ Boolean
Determines whether the given ‘requirement` is satisfied by the given `spec`, in the context of the current `activated` dependency graph.
-
#resolve(requirements) ⇒ Array(String)
Resolve requirements.
-
#search_for(dep) ⇒ Array<Object>
Search for the specifications that match the given dependency.
-
#sort_dependencies(dependencies, activated, conflicts) ⇒ Array<Object>
Sort dependencies so that the ones that are easiest to resolve are first.
- #uncached_search_for(dep) ⇒ Object
Constructor Details
#initialize(vendor_index, opts = {}) ⇒ Resolver
Returns a new instance of Resolver.
21 22 23 24 25 26 27 28 |
# File 'lib/inspec/dependencies.rb', line 21 def initialize(vendor_index, opts = {}) @logger = opts[:logger] || Logger.new(nil) @debug_mode = false # TODO: hardcoded for now, grab from options @vendor_index = vendor_index @resolver = Molinillo::Resolver.new(self, self) @search_cache = {} end |
Class Method Details
.resolve(requirements, vendor_index, cwd, opts = {}) ⇒ Object
12 13 14 15 16 17 18 19 |
# File 'lib/inspec/dependencies.rb', line 12 def self.resolve(requirements, vendor_index, cwd, opts = {}) reqs = requirements.map do |req| Requirement.(req, cwd: cwd) || fail("Cannot initialize dependency: #{req}") end new(vendor_index, opts).resolve(reqs) end |
Instance Method Details
#allow_missing?(_dependency) ⇒ Boolean
Returns whether this dependency, which has no possible matching specifications, can safely be ignored.
160 161 162 163 |
# File 'lib/inspec/dependencies.rb', line 160 def allow_missing?(_dependency) # TODO false end |
#dependencies_for(specification) ⇒ Array<Object>
This method should be ‘pure’, i.e. the return value should depend only on the ‘specification` parameter.
Returns the dependencies of ‘specification`.
89 90 91 |
# File 'lib/inspec/dependencies.rb', line 89 def dependencies_for(specification) specification.profile..dependencies end |
#name_for(dependency) ⇒ String
This method should be ‘pure’, i.e. the return value should depend only on the ‘dependency` parameter.
Returns the name for the given ‘dependency`.
112 113 114 115 116 117 |
# File 'lib/inspec/dependencies.rb', line 112 def name_for(dependency) unless dependency.is_a?(Inspec::Requirement) fail 'Internal error: Dependency resolver requires an Inspec::Requirement object for #name_for(dependency)' end dependency.name end |
#name_for_explicit_dependency_source ⇒ String
Returns the name of the source of explicit dependencies, i.e. those passed to #resolve directly.
121 122 123 |
# File 'lib/inspec/dependencies.rb', line 121 def name_for_explicit_dependency_source 'inspec.yml' end |
#name_for_locking_dependency_source ⇒ String
Returns the name of the source of ‘locked’ dependencies, i.e. those passed to #resolve directly as the ‘base`.
127 128 129 |
# File 'lib/inspec/dependencies.rb', line 127 def name_for_locking_dependency_source 'inspec.lock' end |
#output ⇒ IO
The IO object that should be used to print output. ‘STDOUT`, by default.
173 174 175 |
# File 'lib/inspec/dependencies.rb', line 173 def output self end |
#print(what = '') ⇒ Object Also known as: puts
177 178 179 |
# File 'lib/inspec/dependencies.rb', line 177 def print(what = '') @logger.info(what) end |
#requirement_satisfied_by?(requirement, _activated, spec) ⇒ Boolean
Determines whether the given ‘requirement` is satisfied by the given `spec`, in the context of the current `activated` dependency graph.
102 103 104 |
# File 'lib/inspec/dependencies.rb', line 102 def requirement_satisfied_by?(requirement, _activated, spec) requirement.matches_spec?(spec) || spec.is_a?(Inspec::Profile) end |
#resolve(requirements) ⇒ Array(String)
Resolve requirements.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/inspec/dependencies.rb', line 34 def resolve(requirements) requirements.each(&:pull) @base_dep_graph = Molinillo::DependencyGraph.new @dep_graph = @resolver.resolve(requirements, @base_dep_graph) arr = @dep_graph.map(&:payload) Hash[arr.map { |e| [e.name, e] }] rescue Molinillo::VersionConflict => e raise VersionConflict.new(e.conflicts.keys.uniq, e.) rescue Molinillo::CircularDependencyError => e names = e.dependencies.sort_by(&:name).map { |d| "profile '#{d.name}'" } raise CyclicDependencyError, 'Your profile has requirements that depend on each other, creating '\ "an infinite loop. Please remove #{names.count > 1 ? 'either ' : ''} "\ "#{names.join(' or ')} and try again." end |
#search_for(dep) ⇒ Array<Object>
This method should be ‘pure’, i.e. the return value should depend only on the ‘dependency` parameter.
Search for the specifications that match the given dependency. The specifications in the returned array will be considered in reverse order, so the latest version ought to be last.
62 63 64 65 66 67 |
# File 'lib/inspec/dependencies.rb', line 62 def search_for(dep) unless dep.is_a?(Inspec::Requirement) fail 'Internal error: Dependency resolver requires an Inspec::Requirement object for #search_for(dependency)' end @search_cache[dep] ||= uncached_search_for(dep) end |
#sort_dependencies(dependencies, activated, conflicts) ⇒ Array<Object>
Sort dependencies so that the ones that are easiest to resolve are first. Easiest to resolve is (usually) defined by:
1) Is this dependency already activated?
2) How relaxed are the requirements?
3) Are there any conflicts for this dependency?
4) How many possibilities are there to satisfy this dependency?
143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/inspec/dependencies.rb', line 143 def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) [ activated.vertex_named(name).payload ? 0 : 1, # amount_constrained(dependency), # TODO conflicts[name] ? 0 : 1, # activated.vertex_named(name).payload ? 0 : search_for(dependency).count, # TODO ] end end |
#uncached_search_for(dep) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/inspec/dependencies.rb', line 69 def uncached_search_for(dep) # pre-cached and specified dependencies return [dep] unless dep.profile.nil? results = @vendor_index.find(dep) return [] unless results.any? # TODO: load dep from vendor index # vertex = @dep_graph.vertex_named(dep.name) # locked_requirement = vertex.payload.requirement if vertex fail NotImplementedError, "load dependency #{dep} from vendor index" end |