Class: Berkshelf::Resolver

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/berkshelf/resolver.rb,
lib/berkshelf/resolver/graph.rb

Defined Under Namespace

Classes: Graph

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(berksfile, demands = []) ⇒ Resolver

Returns a new instance of Resolver.

Parameters:

  • berksfile (Berksfile)
  • demands (Array<Dependency>, Dependency) (defaults to: [])

    a dependency, or array of dependencies, which must be satisfied



21
22
23
24
25
26
27
28
# File 'lib/berkshelf/resolver.rb', line 21

def initialize(berksfile, demands = [])
  @berksfile = berksfile
  @graph     = Graph.new
  @demands   = []

  Array(demands).each { |demand| add_demand(demand) }
  compute_solver_engine(berksfile)
end

Instance Attribute Details

#berksfileBerksfile (readonly)

Returns:



9
10
11
# File 'lib/berkshelf/resolver.rb', line 9

def berksfile
  @berksfile
end

#demandsArray<Dependency> (readonly)

Returns an array of dependencies that must be satisfied.

Returns:

  • (Array<Dependency>)

    an array of dependencies that must be satisfied



16
17
18
# File 'lib/berkshelf/resolver.rb', line 16

def demands
  @demands
end

#graphResolver::Graph (readonly)

Returns:



12
13
14
# File 'lib/berkshelf/resolver.rb', line 12

def graph
  @graph
end

Instance Method Details

#[](demand) ⇒ Dependency Also known as: get_demand

Retrieve the given demand from the resolver

Parameters:

  • demand (Dependency, #to_s)

    name of the dependency to return

Returns:



94
95
96
97
# File 'lib/berkshelf/resolver.rb', line 94

def [](demand)
  name = demand.respond_to?(:name) ? demand.name : demand.to_s
  demands.find { |d| d.name == name }
end

#add_demand(demand) ⇒ Array<Dependency>

Add the given dependency to the collection of demands

Parameters:

  • demand (Dependency)

    add a dependency that must be satisfied to the graph

Returns:

Raises:



38
39
40
41
42
43
44
# File 'lib/berkshelf/resolver.rb', line 38

def add_demand(demand)
  if has_demand?(demand)
    raise DuplicateDemand, "A demand named '#{demand.name}' is already present."
  end

  demands.push(demand)
end

#add_explicit_dependencies(cookbook) ⇒ Hash

Add dependencies of a locally cached cookbook which will take precedence over anything found in the universe.

Parameters:

Returns:

  • (Hash)


52
53
54
# File 'lib/berkshelf/resolver.rb', line 52

def add_explicit_dependencies(cookbook)
  graph.populate_local(cookbook)
end

#compute_solver_engine(berksfile) ⇒ Object

Look at berksfile’s solvers, and ask Solve#engine= for the right one, swallowing any exceptions if it’s preferred but not required

Parameters:



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/berkshelf/resolver.rb', line 112

def compute_solver_engine(berksfile)
  if berksfile.required_solver
    begin
      Solve.engine = berksfile.required_solver
    rescue Solve::Errors::InvalidEngine => e
      raise ArgumentError, e.message
    end
  elsif berksfile.preferred_solver
    begin
      Solve.engine = berksfile.preferred_solver
    rescue
      # We should log this, but Berkshelf.log.warn and Berkshelf.formatter.warn
      # both seem inappropriate here.
      # "  Preferred solver ':#{berksfile.preferred_solver}' unavailable"
    end
  end
  # We should log this, but Berkshelf.log.info and Berkshelf.formatter.msg
  # both seem inappropriate here.
  # "  Selected dependency solver engine ':#{Solve.engine}'"
end

#demand_arrayArray<String, String>

Note:

this is the format that Solve uses to determine a solution for the graph

An array of arrays containing the name and constraint of each demand

Returns:



61
62
63
64
65
66
# File 'lib/berkshelf/resolver.rb', line 61

def demand_array
  demands.collect do |demand|
    constraint = demand.locked_version || demand.version_constraint
    [demand.name, constraint]
  end
end

#has_demand?(demand) ⇒ Boolean

Check if the given demand has been added to the resolver

Parameters:

  • demand (Dependency, #to_s)

    the demand or the name of the demand to check for

Returns:

  • (Boolean)


104
105
106
# File 'lib/berkshelf/resolver.rb', line 104

def has_demand?(demand)
  !get_demand(demand).nil?
end

#resolveArray<Array<String, String, Dependency>>

Finds a solution for the currently added dependencies and their dependencies and returns an array of CachedCookbooks.

Returns:

Raises:

  • (NoSolutionError)

    when a solution could not be found for the given demands



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/berkshelf/resolver.rb', line 74

def resolve
  graph.populate_store
  graph.populate(berksfile.sources)

  Solve.it!(graph, demand_array, ENV["DEBUG_RESOLVER"] ? { ui: Berkshelf.ui } : {}).collect do |name, version|
    dependency = get_demand(name) || Dependency.new(berksfile, name)
    dependency.locked_version = version

    dependency
  end
rescue Solve::Errors::NoSolutionError => e
  raise NoSolutionError.new(demands, e)
end