Class: Solve::RubySolver

Inherits:
Object
  • Object
show all
Defined in:
lib/solve/ruby_solver.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(graph, demands, options = {}) ⇒ RubySolver

Returns a new instance of RubySolver.

Examples:

Basic use:

graph = Solve::Graph.new
graph.artifacts("mysql", "1.2.0")
demands = [["mysql"]]
RubySolver.new(graph, demands)

Parameters:

  • graph (Solve::Graph)
  • demands (Array<String>, Array<Array<String, String>>)


42
43
44
45
46
47
48
49
50
51
52
# File 'lib/solve/ruby_solver.rb', line 42

def initialize(graph, demands, options = {})
  @graph         = graph
  @demands_array = demands
  @timeout_ms    = self.class.timeout

  @ui = options[:ui] # could be nil, but that's okay
  @dependency_source = options[:dependency_source] || 'user-specified dependency'

  @molinillo_graph = Molinillo::DependencyGraph.new
  @resolver = Molinillo::Resolver.new(self, self)
end

Instance Attribute Details

#demands_arrayArray<String>, Array<Array<String, String>> (readonly)

Returns demands.

Examples:

Demands are Arrays of Arrays with an artifact name and optional constraint:

[['nginx', '= 1.0.0'], ['mysql']]

Returns:

  • (Array<String>, Array<Array<String, String>>)

    demands



33
34
35
# File 'lib/solve/ruby_solver.rb', line 33

def demands_array
  @demands_array
end

#graphSolve::Graph (readonly)

Graph object with references to all known artifacts and dependency constraints.

Returns:



28
29
30
# File 'lib/solve/ruby_solver.rb', line 28

def graph
  @graph
end

Class Method Details

.activateObject

For optinal solver engines, this attempts to load depenencies. The RubySolver is a non-optional component, so this is a no-op



19
20
21
# File 'lib/solve/ruby_solver.rb', line 19

def activate
  true
end

.timeoutInteger

The timeout (in seconds) to use when resolving graphs. Default is 10. This can be configured by setting the SOLVE_TIMEOUT environment variable.

Returns:

  • (Integer)


12
13
14
15
# File 'lib/solve/ruby_solver.rb', line 12

def timeout
  seconds = 30 unless seconds = ENV["SOLVE_TIMEOUT"]
  seconds.to_i * 1_000
end

Instance Method Details

#after_resolutionObject

Callback required by Molinillo, called when the solve is complete.

Returns:

  • nil



114
115
116
# File 'lib/solve/ruby_solver.rb', line 114

def after_resolution
  @ui.say('Finished dependency resolution') if @ui
end

#before_resolutionObject

Callback required by Molinillo, called when the solve starts

Returns:

  • nil



108
109
110
# File 'lib/solve/ruby_solver.rb', line 108

def before_resolution
  @ui.say('Starting dependency resolution') if @ui
end

#debug(current_resolver_depth) ⇒ Object

Callback required by Molinillo, gives debug information about the solution

Returns:

  • nil



126
127
128
129
130
# File 'lib/solve/ruby_solver.rb', line 126

def debug(current_resolver_depth)
  # debug info will be returned if you call yield here, but it seems to be
  # broken in current Molinillo
  @ui.say(yield) if @ui
end

#demandsArray<Solve::Demand>

The problem demands given as Demand model objects

Returns:



56
57
58
59
60
# File 'lib/solve/ruby_solver.rb', line 56

def demands
  demands_array.map do |name, constraint|
    Demand.new(self, name, constraint)
  end
end

#dependencies_for(specification) ⇒ Array<Solve::Dependency>

Callback required by Molinillo

Returns:



167
168
169
# File 'lib/solve/ruby_solver.rb', line 167

def dependencies_for(specification)
  specification.dependencies
end

#indicate_progressObject

Callback required by Molinillo, called when resolving every progress_rate

Returns:

  • nil



120
121
122
# File 'lib/solve/ruby_solver.rb', line 120

def indicate_progress
  nil
end

#name_for(dependency) ⇒ String

Callback required by Molinillo

Returns:

  • (String)

    the dependency’s name



134
135
136
# File 'lib/solve/ruby_solver.rb', line 134

def name_for(dependency)
  dependency.name
end

#name_for_explicit_dependency_sourceString

Returns the name of the source of explicit dependencies, i.e. those passed to Resolver#resolve directly.

Returns:

  • (String)

    the name of the source of explicit dependencies, i.e. those passed to Resolver#resolve directly.



173
174
175
# File 'lib/solve/ruby_solver.rb', line 173

def name_for_explicit_dependency_source
  @dependency_source
end

#name_for_locking_dependency_sourceString

Returns the name of the source of ‘locked’ dependencies, i.e. those passed to Resolver#resolve directly as the ‘base`.

Returns:

  • (String)

    the name of the source of ‘locked’ dependencies, i.e. those passed to Resolver#resolve directly as the ‘base`



179
180
181
# File 'lib/solve/ruby_solver.rb', line 179

def name_for_locking_dependency_source
  'Lockfile'
end

#progress_rateInteger

Callback required by Molinillo, called when the solve starts

Returns:

  • (Integer)


102
103
104
# File 'lib/solve/ruby_solver.rb', line 102

def progress_rate
  1
end

#requirement_satisfied_by?(requirement, activated, spec) ⇒ Boolean

Callback required by Molinillo

Returns:

  • (Boolean)


161
162
163
# File 'lib/solve/ruby_solver.rb', line 161

def requirement_satisfied_by?(requirement, activated, spec)
  requirement.constraint.satisfies?(spec.version)
end

#resolve(options = {}) ⇒ Hash, List

Returns a hash like { “Artifact Name” => “Version”,… } unless the :sorted option is true, then it returns a list like [[“Artifact Name”, “Version],…]

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :sorted (Boolean)

    return the solution as a sorted list instead of a Hash

Returns:

  • (Hash, List)

    Returns a hash like { “Artifact Name” => “Version”,… } unless the :sorted option is true, then it returns a list like [[“Artifact Name”, “Version],…]

Raises:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/solve/ruby_solver.rb', line 72

def resolve(options = {})
  @ui = options[:ui] if options[:ui]

  solved_graph = resolve_with_error_wrapping

  solution =  solved_graph.map(&:payload)

  unsorted_solution = solution.inject({}) do |stringified_soln, artifact|
    stringified_soln[artifact.name] = artifact.version.to_s
    stringified_soln
  end

  if options[:sorted]
    build_sorted_solution(unsorted_solution)
  else
    unsorted_solution
  end
end

#search_for(dependency) ⇒ Array<Solve::Artifact>

Callback required by Molinillo

Returns:



153
154
155
156
157
# File 'lib/solve/ruby_solver.rb', line 153

def search_for(dependency)
  # This array gets mutated by Molinillo; it's okay because sort returns a
  # new array.
  graph.versions(dependency.name, dependency.constraint).sort
end

#sort_dependencies(dependencies, activated, conflicts) ⇒ Array<Solve::Dependency>

Callback required by Molinillo

Returns:



140
141
142
143
144
145
146
147
148
149
# File 'lib/solve/ruby_solver.rb', line 140

def sort_dependencies(dependencies, activated, conflicts)
  dependencies.sort_by do |dependency|
    name = name_for(dependency)
    [
      activated.vertex_named(name).payload ? 0 : 1,
      conflicts[name] ? 0 : 1,
      activated.vertex_named(name).payload ? 0 : graph.versions(dependency.name).count,
    ]
  end
end