molinillo 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|