molinillo 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/molinillo/dependency_graph.rb +82 -71
- data/lib/molinillo/gem_metadata.rb +1 -1
- data/lib/molinillo/resolution.rb +8 -8
- data/spec/dependency_graph_spec.rb +7 -8
- data/spec/resolver_spec.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f860bde0bd4aed39aadb78bce1dd854bedf9d34e
|
4
|
+
data.tar.gz: eaebd8e7e9070425f2c4c80b65fc562ff8fe210a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ede3f0f7aecfdf3aab7be57f3bf23f2c23e2fe440aa8c470bcfd5bdd212941aa4ad52dd5a958886448c64fd515af63ce9342dd343912d8f8213cfbc5ff6ddbf
|
7
|
+
data.tar.gz: 82b5e19bb50aa3db372c838fca16a8b61628ca7bd9cfd9aa525d9cd7af4218768bf48e21b9801232959993cd258207e4deeb4356fd6b575d781af9ba2ebd7065
|
@@ -34,40 +34,34 @@ module Molinillo
|
|
34
34
|
# A directed edge of a {DependencyGraph}
|
35
35
|
# @attr [Vertex] origin The origin of the directed edge
|
36
36
|
# @attr [Vertex] destination The destination of the directed edge
|
37
|
-
# @attr [
|
38
|
-
Edge = Struct.new(:origin, :destination, :
|
37
|
+
# @attr [Object] requirement The requirement the directed edge represents
|
38
|
+
Edge = Struct.new(:origin, :destination, :requirement)
|
39
39
|
|
40
|
-
# @return [{String => Vertex}] vertices that have no {Vertex#predecessors},
|
41
|
-
# keyed by by {Vertex#name}
|
42
|
-
attr_reader :root_vertices
|
43
40
|
# @return [{String => Vertex}] the vertices of the dependency graph, keyed
|
44
41
|
# by {Vertex#name}
|
45
42
|
attr_reader :vertices
|
46
|
-
# @return [Set<Edge>] the edges of the dependency graph
|
47
|
-
attr_reader :edges
|
48
43
|
|
49
44
|
def initialize
|
50
45
|
@vertices = {}
|
51
|
-
@edges = Set.new
|
52
|
-
@root_vertices = {}
|
53
46
|
end
|
54
47
|
|
55
48
|
# Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
|
56
|
-
#
|
49
|
+
# are properly copied.
|
57
50
|
def initialize_copy(other)
|
58
51
|
super
|
59
|
-
@vertices =
|
60
|
-
|
61
|
-
|
52
|
+
@vertices = {}
|
53
|
+
traverse = lambda do |new_v, old_v|
|
54
|
+
return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
|
55
|
+
old_v.outgoing_edges.each do |edge|
|
56
|
+
destination = add_vertex(edge.destination.name, edge.destination.payload)
|
57
|
+
add_edge_no_circular(new_v, destination, edge.requirement)
|
58
|
+
traverse.call(destination, edge.destination)
|
62
59
|
end
|
63
60
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
vertex_named(edge.destination.name),
|
69
|
-
edge.requirements.dup
|
70
|
-
)
|
61
|
+
other.vertices.each do |name, vertex|
|
62
|
+
new_vertex = add_vertex(name, vertex.payload, vertex.root?)
|
63
|
+
new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
|
64
|
+
traverse.call(new_vertex, vertex)
|
71
65
|
end
|
72
66
|
end
|
73
67
|
|
@@ -80,7 +74,12 @@ module Molinillo
|
|
80
74
|
# by a recursive traversal of each {#root_vertices} and its
|
81
75
|
# {Vertex#successors}
|
82
76
|
def ==(other)
|
83
|
-
|
77
|
+
return false unless other
|
78
|
+
vertices.each do |name, vertex|
|
79
|
+
other_vertex = other.vertex_named(name)
|
80
|
+
return false unless other_vertex
|
81
|
+
return false unless other_vertex.successors.map(&:name).to_set == vertex.successors.map(&:name).to_set
|
82
|
+
end
|
84
83
|
end
|
85
84
|
|
86
85
|
# @param [String] name
|
@@ -89,15 +88,13 @@ module Molinillo
|
|
89
88
|
# @param [Object] requirement the requirement that is requiring the child
|
90
89
|
# @return [void]
|
91
90
|
def add_child_vertex(name, payload, parent_names, requirement)
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
vertex.payload ||= payload
|
100
|
-
parent_nodes.each do |parent_node|
|
91
|
+
vertex = add_vertex(name, payload)
|
92
|
+
parent_names.each do |parent_name|
|
93
|
+
unless parent_name
|
94
|
+
vertex.root = true
|
95
|
+
next
|
96
|
+
end
|
97
|
+
parent_node = vertex_named(parent_name)
|
101
98
|
add_edge(parent_node, vertex, requirement)
|
102
99
|
end
|
103
100
|
vertex
|
@@ -106,16 +103,11 @@ module Molinillo
|
|
106
103
|
# @param [String] name
|
107
104
|
# @param [Object] payload
|
108
105
|
# @return [Vertex] the vertex that was added to `self`
|
109
|
-
def add_vertex(name, payload)
|
110
|
-
vertex = vertices[name] ||= Vertex.new(
|
111
|
-
vertex.
|
112
|
-
|
113
|
-
|
114
|
-
# @param [String] name
|
115
|
-
# @param [Object] payload
|
116
|
-
# @return [Vertex] the vertex that was added to `self`
|
117
|
-
def add_root_vertex(name, payload)
|
118
|
-
add_vertex(name, payload).tap { |v| root_vertices[name] = v }
|
106
|
+
def add_vertex(name, payload, root = false)
|
107
|
+
vertex = vertices[name] ||= Vertex.new(name, payload)
|
108
|
+
vertex.payload ||= payload
|
109
|
+
vertex.root ||= root
|
110
|
+
vertex
|
119
111
|
end
|
120
112
|
|
121
113
|
# Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
|
@@ -123,12 +115,12 @@ module Molinillo
|
|
123
115
|
# @param [String] name
|
124
116
|
# @return [void]
|
125
117
|
def detach_vertex_named(name)
|
126
|
-
vertex =
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
118
|
+
return unless vertex = vertices.delete(name)
|
119
|
+
vertex.outgoing_edges.each do |e|
|
120
|
+
v = e.destination
|
121
|
+
v.incoming_edges.delete(e)
|
122
|
+
detach_vertex_named(v.name) unless v.root? || v.predecessors.any?
|
123
|
+
end
|
132
124
|
end
|
133
125
|
|
134
126
|
# @param [String] name
|
@@ -140,7 +132,8 @@ module Molinillo
|
|
140
132
|
# @param [String] name
|
141
133
|
# @return [Vertex,nil] the root vertex with the given name
|
142
134
|
def root_vertex_named(name)
|
143
|
-
|
135
|
+
vertex = vertex_named(name)
|
136
|
+
vertex if vertex && vertex.root?
|
144
137
|
end
|
145
138
|
|
146
139
|
# Adds a new {Edge} to the dependency graph
|
@@ -149,18 +142,24 @@ module Molinillo
|
|
149
142
|
# @param [Object] requirement the requirement that this edge represents
|
150
143
|
# @return [Edge] the added edge
|
151
144
|
def add_edge(origin, destination, requirement)
|
152
|
-
if
|
145
|
+
if destination.path_to?(origin)
|
153
146
|
raise CircularDependencyError.new([origin, destination])
|
154
147
|
end
|
155
|
-
|
148
|
+
add_edge_no_circular(origin, destination, requirement)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def add_edge_no_circular(origin, destination, requirement)
|
154
|
+
edge = Edge.new(origin, destination, requirement)
|
155
|
+
origin.outgoing_edges << edge
|
156
|
+
destination.incoming_edges << edge
|
157
|
+
edge
|
156
158
|
end
|
157
159
|
|
158
160
|
# A vertex in a {DependencyGraph} that encapsulates a {#name} and a
|
159
161
|
# {#payload}
|
160
162
|
class Vertex
|
161
|
-
# @return [DependencyGraph] the graph this vertex is a node of
|
162
|
-
attr_accessor :graph
|
163
|
-
|
164
163
|
# @return [String] the name of the vertex
|
165
164
|
attr_accessor :name
|
166
165
|
|
@@ -171,50 +170,62 @@ module Molinillo
|
|
171
170
|
# this vertex
|
172
171
|
attr_reader :explicit_requirements
|
173
172
|
|
174
|
-
# @
|
173
|
+
# @return [Boolean] whether the vertex is considered a root vertex
|
174
|
+
attr_accessor :root
|
175
|
+
alias_method :root?, :root
|
176
|
+
|
175
177
|
# @param [String] name see {#name}
|
176
178
|
# @param [Object] payload see {#payload}
|
177
|
-
def initialize(
|
178
|
-
@graph = graph
|
179
|
+
def initialize(name, payload)
|
179
180
|
@name = name
|
180
181
|
@payload = payload
|
181
182
|
@explicit_requirements = []
|
183
|
+
@outgoing_edges = []
|
184
|
+
@incoming_edges = []
|
182
185
|
end
|
183
186
|
|
184
187
|
# @return [Array<Object>] all of the requirements that required
|
185
188
|
# this vertex
|
186
189
|
def requirements
|
187
|
-
incoming_edges.map(&:
|
190
|
+
incoming_edges.map(&:requirement) + explicit_requirements
|
188
191
|
end
|
189
192
|
|
190
193
|
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
|
191
194
|
# {Edge#origin}
|
192
|
-
|
193
|
-
graph.edges.select { |e| e.origin.shallow_eql?(self) }
|
194
|
-
end
|
195
|
+
attr_accessor :outgoing_edges
|
195
196
|
|
196
197
|
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
|
197
198
|
# {Edge#destination}
|
198
|
-
|
199
|
-
graph.edges.select { |e| e.destination.shallow_eql?(self) }
|
200
|
-
end
|
199
|
+
attr_accessor :incoming_edges
|
201
200
|
|
202
|
-
# @return [
|
201
|
+
# @return [Array<Vertex>] the vertices of {#graph} that have an edge with
|
203
202
|
# `self` as their {Edge#destination}
|
204
203
|
def predecessors
|
205
|
-
incoming_edges.map(&:origin)
|
204
|
+
incoming_edges.map(&:origin)
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [Array<Vertex>] the vertices of {#graph} where `self` is a
|
208
|
+
# {#descendent?}
|
209
|
+
def recursive_predecessors
|
210
|
+
vertices = predecessors
|
211
|
+
vertices += vertices.map(&:recursive_predecessors).flatten(1)
|
212
|
+
vertices.uniq!
|
213
|
+
vertices
|
206
214
|
end
|
207
215
|
|
208
|
-
# @return [
|
216
|
+
# @return [Array<Vertex>] the vertices of {#graph} that have an edge with
|
209
217
|
# `self` as their {Edge#origin}
|
210
218
|
def successors
|
211
|
-
outgoing_edges.map(&:destination)
|
219
|
+
outgoing_edges.map(&:destination)
|
212
220
|
end
|
213
221
|
|
214
|
-
# @return [
|
222
|
+
# @return [Array<Vertex>] the vertices of {#graph} where `self` is an
|
215
223
|
# {#ancestor?}
|
216
224
|
def recursive_successors
|
217
|
-
|
225
|
+
vertices = successors
|
226
|
+
vertices += vertices.map(&:recursive_successors).flatten(1)
|
227
|
+
vertices.uniq!
|
228
|
+
vertices
|
218
229
|
end
|
219
230
|
|
220
231
|
# @return [String] a string suitable for debugging
|
@@ -226,7 +237,7 @@ module Molinillo
|
|
226
237
|
# by a recursive traversal of each {Vertex#successors}
|
227
238
|
def ==(other)
|
228
239
|
shallow_eql?(other) &&
|
229
|
-
successors == other.successors
|
240
|
+
successors.to_set == other.successors.to_set
|
230
241
|
end
|
231
242
|
|
232
243
|
# @return [Boolean] whether the two vertices are equal, determined
|
@@ -248,7 +259,7 @@ module Molinillo
|
|
248
259
|
# dependency graph?
|
249
260
|
# @return true iff there is a path following edges within this {#graph}
|
250
261
|
def path_to?(other)
|
251
|
-
|
262
|
+
equal?(other) || successors.any? { |v| v.path_to?(other) }
|
252
263
|
end
|
253
264
|
|
254
265
|
alias_method :descendent?, :path_to?
|
@@ -257,7 +268,7 @@ module Molinillo
|
|
257
268
|
# dependency graph?
|
258
269
|
# @return true iff there is a path following edges within this {#graph}
|
259
270
|
def ancestor?(other)
|
260
|
-
|
271
|
+
other.path_to?(self)
|
261
272
|
end
|
262
273
|
|
263
274
|
alias_method :is_reachable_from?, :ancestor?
|
data/lib/molinillo/resolution.rb
CHANGED
@@ -166,7 +166,7 @@ module Molinillo
|
|
166
166
|
# @return [DependencyState] the initial state for the resolution
|
167
167
|
def initial_state
|
168
168
|
graph = DependencyGraph.new.tap do |dg|
|
169
|
-
original_requested.each { |r| dg.
|
169
|
+
original_requested.each { |r| dg.add_vertex(name_for(r), nil, true).tap { |v| v.explicit_requirements << r } }
|
170
170
|
end
|
171
171
|
|
172
172
|
requirements = sort_dependencies(original_requested, graph, {})
|
@@ -252,7 +252,7 @@ module Molinillo
|
|
252
252
|
name_for_explicit_dependency_source => vertex.explicit_requirements,
|
253
253
|
name_for_locking_dependency_source => Array(locked_requirement_named(name)),
|
254
254
|
}
|
255
|
-
vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(
|
255
|
+
vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(edge.requirement) }
|
256
256
|
conflicts[name] = Conflict.new(
|
257
257
|
requirement,
|
258
258
|
Hash[requirements.select { |_, r| !r.empty? }],
|
@@ -326,7 +326,7 @@ module Molinillo
|
|
326
326
|
existing_spec = existing_node.payload
|
327
327
|
if requirement_satisfied_by?(requirement, activated, existing_spec)
|
328
328
|
new_requirements = requirements.dup
|
329
|
-
push_state_for_requirements(new_requirements)
|
329
|
+
push_state_for_requirements(new_requirements, false)
|
330
330
|
else
|
331
331
|
return if attempt_to_swap_possibility
|
332
332
|
create_conflict
|
@@ -393,17 +393,17 @@ module Molinillo
|
|
393
393
|
def require_nested_dependencies_for(activated_spec)
|
394
394
|
nested_dependencies = dependencies_for(activated_spec)
|
395
395
|
debug(depth) { "Requiring nested dependencies (#{nested_dependencies.map(&:to_s).join(', ')})" }
|
396
|
-
nested_dependencies.each { |d|
|
396
|
+
nested_dependencies.each { |d| activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d) }
|
397
397
|
|
398
|
-
push_state_for_requirements(requirements + nested_dependencies)
|
398
|
+
push_state_for_requirements(requirements + nested_dependencies, nested_dependencies.size > 0)
|
399
399
|
end
|
400
400
|
|
401
401
|
# Pushes a new {DependencyState} that encapsulates both existing and new
|
402
402
|
# requirements
|
403
403
|
# @param [Array] new_requirements
|
404
404
|
# @return [void]
|
405
|
-
def push_state_for_requirements(new_requirements, new_activated = activated.dup)
|
406
|
-
new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts)
|
405
|
+
def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated.dup)
|
406
|
+
new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
|
407
407
|
new_requirement = new_requirements.shift
|
408
408
|
new_name = new_requirement ? name_for(new_requirement) : ''
|
409
409
|
possibilities = new_requirement ? search_for(new_requirement) : []
|
@@ -424,7 +424,7 @@ module Molinillo
|
|
424
424
|
def handle_missing_or_push_dependency_state(state)
|
425
425
|
if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
|
426
426
|
state.activated.detach_vertex_named(state.name)
|
427
|
-
push_state_for_requirements(state.requirements, state.activated)
|
427
|
+
push_state_for_requirements(state.requirements.dup, false, state.activated)
|
428
428
|
else
|
429
429
|
states.push state
|
430
430
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
require 'set'
|
3
2
|
|
4
3
|
module Molinillo
|
5
4
|
describe DependencyGraph do
|
6
5
|
describe 'in general' do
|
7
6
|
before do
|
8
7
|
@graph = DependencyGraph.new
|
9
|
-
@root = @graph.
|
10
|
-
@root2 = @graph.
|
8
|
+
@root = @graph.add_vertex('Root', 'Root', true)
|
9
|
+
@root2 = @graph.add_vertex('Root2', 'Root2', true)
|
11
10
|
@child = @graph.add_child_vertex('Child', 'Child', %w(Root), 'Child')
|
12
11
|
end
|
13
12
|
|
@@ -40,7 +39,7 @@ module Molinillo
|
|
40
39
|
end
|
41
40
|
|
42
41
|
it 'detaches a root vertex without successors' do
|
43
|
-
root = @graph.
|
42
|
+
root = @graph.add_vertex('root', 'root', true)
|
44
43
|
@graph.detach_vertex_named(root.name)
|
45
44
|
@graph.vertex_named(root.name).
|
46
45
|
should.equal nil
|
@@ -49,7 +48,7 @@ module Molinillo
|
|
49
48
|
end
|
50
49
|
|
51
50
|
it 'detaches a root vertex with successors' do
|
52
|
-
root = @graph.
|
51
|
+
root = @graph.add_vertex('root', 'root', true)
|
53
52
|
child = @graph.add_child_vertex('child', 'child', %w(root), 'child')
|
54
53
|
@graph.detach_vertex_named(root.name)
|
55
54
|
@graph.vertex_named(root.name).
|
@@ -61,8 +60,8 @@ module Molinillo
|
|
61
60
|
end
|
62
61
|
|
63
62
|
it 'detaches a root vertex with successors with other parents' do
|
64
|
-
root = @graph.
|
65
|
-
root2 = @graph.
|
63
|
+
root = @graph.add_vertex('root', 'root', true)
|
64
|
+
root2 = @graph.add_vertex('root2', 'root2', true)
|
66
65
|
child = @graph.add_child_vertex('child', 'child', %w(root root2), 'child')
|
67
66
|
@graph.detach_vertex_named(root.name)
|
68
67
|
@graph.vertex_named(root.name).
|
@@ -70,7 +69,7 @@ module Molinillo
|
|
70
69
|
@graph.vertex_named(child.name).
|
71
70
|
should.equal child
|
72
71
|
child.predecessors.
|
73
|
-
should.equal
|
72
|
+
should.equal [root2]
|
74
73
|
@graph.vertices.count.
|
75
74
|
should.equal 2
|
76
75
|
end
|
data/spec/resolver_spec.rb
CHANGED
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: molinillo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel E. Giddins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.5'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description:
|
@@ -74,12 +74,12 @@ require_paths:
|
|
74
74
|
- lib
|
75
75
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- -
|
77
|
+
- - '>='
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: '0'
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
|
-
- -
|
82
|
+
- - '>='
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|