molinillo 0.6.2 → 0.7.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 +5 -5
- data/ARCHITECTURE.md +3 -3
- data/CHANGELOG.md +78 -0
- data/README.md +1 -2
- data/lib/molinillo.rb +5 -6
- data/lib/molinillo/dependency_graph.rb +36 -3
- data/lib/molinillo/dependency_graph/add_edge_no_circular.rb +1 -1
- data/lib/molinillo/dependency_graph/add_vertex.rb +1 -1
- data/lib/molinillo/dependency_graph/delete_edge.rb +1 -1
- data/lib/molinillo/dependency_graph/detach_vertex_named.rb +1 -1
- data/lib/molinillo/dependency_graph/log.rb +6 -6
- data/lib/molinillo/dependency_graph/set_payload.rb +1 -1
- data/lib/molinillo/dependency_graph/tag.rb +3 -3
- data/lib/molinillo/dependency_graph/vertex.rb +42 -10
- data/lib/molinillo/errors.rb +9 -4
- data/lib/molinillo/gem_metadata.rb +1 -1
- data/lib/molinillo/resolution.rb +49 -47
- data/lib/molinillo/resolver.rb +2 -2
- metadata +8 -11
- data/lib/molinillo/compatibility.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e6828b175f84c2dae7fadfaf7c614a3a6198089a11f0e2c20defc697b1108e2b
|
4
|
+
data.tar.gz: b4e8a71693257b7726be5c21fee26571197b0cd69b1445bb51107aad984b0e89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67df28dfe97c6a0b66d96df61e543fa917de1bd63e2ffa169d8499f62940722a72629b37fe1c7a8db4408d7dfbfc8d718ceac09956a5160c875d74db23ab15cf
|
7
|
+
data.tar.gz: d750b24f9a1dd5a4a2a846f00c1ef0f6e05fdff166266a9427c9918254ff991c8bc0fb7fae861ec172ac0a305942981d0c991932a282522e2bb0eb7c981a1b13
|
data/ARCHITECTURE.md
CHANGED
@@ -33,7 +33,7 @@ This stack-based approach is used because backtracking (also known as *unwinding
|
|
33
33
|
13. If there is an existing, `activated` vertex for the dependency, `attempt_to_filter_existing_spec`
|
34
34
|
- This filters the contents of the existing vertex's `PossibilitySet` by the current state's `requirement`
|
35
35
|
- If any possibilities remain within the `PossibilitySet`, it updates the activated vertex's payload with the new, filtered state and pushes a new `DependencyState`
|
36
|
-
- If no possibilities remain within the `PossibilitySet` after filtering, or if the current state's `PossibilitySet` had a different set of sub-
|
36
|
+
- If no possibilities remain within the `PossibilitySet` after filtering, or if the current state's `PossibilitySet` had a different set of sub-dependency requirements to the existing vertex's `PossibilitySet`, `create_conflict` and `unwind_for_conflict`, back to the last `DependencyState` that has a chance to not generate a conflict. Go to #6
|
37
37
|
15. Terminate with the topmost state's dependency graph when there are no more requirements left
|
38
38
|
16. For each vertex with a payload of allowable versions for this resolution (i.e., a `PossibilitySet`), pick a single specific version.
|
39
39
|
|
@@ -52,7 +52,7 @@ the previous unwinds that have determined our current state.
|
|
52
52
|
1. First, consider the current conflict as follows:
|
53
53
|
- Find the earliest (lowest index) set of requirements which combine to cause
|
54
54
|
the conflict. Any non-binding requirements can be ignored, as removing them
|
55
|
-
would not resolve the current
|
55
|
+
would not resolve the current conflict
|
56
56
|
- For each binding requirement, find all the alternative possibilities that
|
57
57
|
would relax the requirement:
|
58
58
|
- the requirement's DependencyState might have alternative possibilities
|
@@ -79,7 +79,7 @@ different, smaller unwind was chosen instead):
|
|
79
79
|
error as resolution is not possible.
|
80
80
|
3b. Filter the state that we're unwinding to, in order to remove any
|
81
81
|
possibilities we know will result in a conflict. Consider all possible unwinds
|
82
|
-
to the chosen state (there may be several,
|
82
|
+
to the chosen state (there may be several, amassed from previous unused
|
83
83
|
unwinds for different conflicts) when doing this filtering - only
|
84
84
|
possibilities that will certainly result in *all* of those conflicts can be
|
85
85
|
filtered out as having no chance of resolution
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,83 @@
|
|
1
1
|
# Molinillo Changelog
|
2
2
|
|
3
|
+
## 0.7.0 (2020-10-21)
|
4
|
+
|
5
|
+
##### Breaking
|
6
|
+
|
7
|
+
* Support for Ruby 1.8.7 and 1.9.3 has been dropped, the minimum supported
|
8
|
+
Ruby version is now 2.0.
|
9
|
+
[Samuel Giddins](https://github.com/segiddins)
|
10
|
+
|
11
|
+
##### Enhancements
|
12
|
+
|
13
|
+
* Circular dependency errors include the full (shortest) path between the
|
14
|
+
circularly-dependent vertices.
|
15
|
+
[Samuel Giddins](https://github.com/segiddins)
|
16
|
+
|
17
|
+
##### Bug Fixes
|
18
|
+
|
19
|
+
* None.
|
20
|
+
|
21
|
+
|
22
|
+
## 0.6.6 (2018-08-07)
|
23
|
+
|
24
|
+
##### Enhancements
|
25
|
+
|
26
|
+
* Improve performance of `Vertex#path_to?`.
|
27
|
+
[Samuel Giddins](https://github.com/segiddins)
|
28
|
+
|
29
|
+
* Allow customization of string used to say that a version conflict has occurred
|
30
|
+
for a particular name by passing in the `:incompatible_version_message_for_conflict`
|
31
|
+
key when constructing a version conflict message with trees.
|
32
|
+
[Samuel Giddins](https://github.com/segiddins)
|
33
|
+
|
34
|
+
##### Bug Fixes
|
35
|
+
|
36
|
+
* None.
|
37
|
+
|
38
|
+
|
39
|
+
## 0.6.5 (2018-03-22)
|
40
|
+
|
41
|
+
##### Enhancements
|
42
|
+
|
43
|
+
* Improve performance of recursive vertex methods.
|
44
|
+
[Samuel Giddins](https://github.com/segiddins)
|
45
|
+
|
46
|
+
##### Bug Fixes
|
47
|
+
|
48
|
+
* None.
|
49
|
+
|
50
|
+
|
51
|
+
## 0.6.4 (2017-10-29)
|
52
|
+
|
53
|
+
##### Enhancements
|
54
|
+
|
55
|
+
* Reduce memory usage during resolution by making the `Vertex#requirements`
|
56
|
+
array unique.
|
57
|
+
[Grey Baker](https://github.com/greysteil)
|
58
|
+
[Jan Krutisch](https://github.com/halfbyte)
|
59
|
+
|
60
|
+
##### Bug Fixes
|
61
|
+
|
62
|
+
* None.
|
63
|
+
|
64
|
+
|
65
|
+
## 0.6.3 (2017-09-06)
|
66
|
+
|
67
|
+
##### Enhancements
|
68
|
+
|
69
|
+
* None.
|
70
|
+
|
71
|
+
##### Bug Fixes
|
72
|
+
|
73
|
+
* Handle the case where an unwind occurs to a requirement that directly caused
|
74
|
+
the current conflict but could also have been unwound to directly from
|
75
|
+
previous conflicts. In this case, filtering must not remove any possibilities
|
76
|
+
that could have avoided the previous conflicts (even if they would not avoid
|
77
|
+
the current one).
|
78
|
+
[Grey Baker](https://github.com/greysteil)
|
79
|
+
|
80
|
+
|
3
81
|
## 0.6.2 (2017-08-25)
|
4
82
|
|
5
83
|
##### Enhancements
|
data/README.md
CHANGED
@@ -28,8 +28,7 @@ $ gem install molinillo
|
|
28
28
|
|
29
29
|
## Usage
|
30
30
|
|
31
|
-
See the [ARCHITECTURE](ARCHITECTURE.md) file for an overview and look at the test suite for example usage.
|
32
|
-
forthcoming.
|
31
|
+
See the [ARCHITECTURE](ARCHITECTURE.md) file for an overview and look at the test suite for example usage.
|
33
32
|
|
34
33
|
## Contributing
|
35
34
|
|
data/lib/molinillo.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require 'molinillo/modules/specification_provider'
|
3
|
+
require_relative 'molinillo/gem_metadata'
|
4
|
+
require_relative 'molinillo/errors'
|
5
|
+
require_relative 'molinillo/resolver'
|
6
|
+
require_relative 'molinillo/modules/ui'
|
7
|
+
require_relative 'molinillo/modules/specification_provider'
|
9
8
|
|
10
9
|
# Molinillo is a generic dependency resolution algorithm.
|
11
10
|
module Molinillo
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require 'set'
|
4
4
|
require 'tsort'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
require_relative 'dependency_graph/log'
|
7
|
+
require_relative 'dependency_graph/vertex'
|
8
8
|
|
9
9
|
module Molinillo
|
10
10
|
# A directed acyclic graph that is tuned to hold named dependencies
|
@@ -124,6 +124,7 @@ module Molinillo
|
|
124
124
|
dot.join("\n")
|
125
125
|
end
|
126
126
|
|
127
|
+
# @param [DependencyGraph] other
|
127
128
|
# @return [Boolean] whether the two dependency graphs are equal, determined
|
128
129
|
# by a recursive traversal of each {#root_vertices} and its
|
129
130
|
# {Vertex#successors}
|
@@ -190,7 +191,7 @@ module Molinillo
|
|
190
191
|
# @return [Edge] the added edge
|
191
192
|
def add_edge(origin, destination, requirement)
|
192
193
|
if destination.path_to?(origin)
|
193
|
-
raise CircularDependencyError.new(
|
194
|
+
raise CircularDependencyError.new(path(destination, origin))
|
194
195
|
end
|
195
196
|
add_edge_no_circular(origin, destination, requirement)
|
196
197
|
end
|
@@ -219,5 +220,37 @@ module Molinillo
|
|
219
220
|
def add_edge_no_circular(origin, destination, requirement)
|
220
221
|
log.add_edge_no_circular(self, origin.name, destination.name, requirement)
|
221
222
|
end
|
223
|
+
|
224
|
+
# Returns the path between two vertices
|
225
|
+
# @raise [ArgumentError] if there is no path between the vertices
|
226
|
+
# @param [Vertex] from
|
227
|
+
# @param [Vertex] to
|
228
|
+
# @return [Array<Vertex>] the shortest path from `from` to `to`
|
229
|
+
def path(from, to)
|
230
|
+
distances = Hash.new(vertices.size + 1)
|
231
|
+
distances[from.name] = 0
|
232
|
+
predecessors = {}
|
233
|
+
each do |vertex|
|
234
|
+
vertex.successors.each do |successor|
|
235
|
+
if distances[successor.name] > distances[vertex.name] + 1
|
236
|
+
distances[successor.name] = distances[vertex.name] + 1
|
237
|
+
predecessors[successor] = vertex
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
path = [to]
|
243
|
+
while before = predecessors[to]
|
244
|
+
path << before
|
245
|
+
to = before
|
246
|
+
break if to == from
|
247
|
+
end
|
248
|
+
|
249
|
+
unless path.last.equal?(from)
|
250
|
+
raise ArgumentError, "There is no path from #{from.name} to #{to.name}"
|
251
|
+
end
|
252
|
+
|
253
|
+
path.reverse
|
254
|
+
end
|
222
255
|
end
|
223
256
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
require_relative 'add_edge_no_circular'
|
4
|
+
require_relative 'add_vertex'
|
5
|
+
require_relative 'delete_edge'
|
6
|
+
require_relative 'detach_vertex_named'
|
7
|
+
require_relative 'set_payload'
|
8
|
+
require_relative 'tag'
|
9
9
|
|
10
10
|
module Molinillo
|
11
11
|
class DependencyGraph
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'action'
|
4
4
|
module Molinillo
|
5
5
|
class DependencyGraph
|
6
6
|
# @!visibility private
|
@@ -14,11 +14,11 @@ module Molinillo
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# (see Action#up)
|
17
|
-
def up(
|
17
|
+
def up(graph)
|
18
18
|
end
|
19
19
|
|
20
20
|
# (see Action#down)
|
21
|
-
def down(
|
21
|
+
def down(graph)
|
22
22
|
end
|
23
23
|
|
24
24
|
# @!group Tag
|
@@ -33,7 +33,7 @@ module Molinillo
|
|
33
33
|
# @return [Array<Object>] all of the requirements that required
|
34
34
|
# this vertex
|
35
35
|
def requirements
|
36
|
-
incoming_edges.map(&:requirement) + explicit_requirements
|
36
|
+
(incoming_edges.map(&:requirement) + explicit_requirements).uniq
|
37
37
|
end
|
38
38
|
|
39
39
|
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
|
@@ -50,14 +50,25 @@ module Molinillo
|
|
50
50
|
incoming_edges.map(&:origin)
|
51
51
|
end
|
52
52
|
|
53
|
-
# @return [
|
53
|
+
# @return [Set<Vertex>] the vertices of {#graph} where `self` is a
|
54
54
|
# {#descendent?}
|
55
55
|
def recursive_predecessors
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
_recursive_predecessors
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Set<Vertex>] vertices the set to add the predecessors to
|
60
|
+
# @return [Set<Vertex>] the vertices of {#graph} where `self` is a
|
61
|
+
# {#descendent?}
|
62
|
+
def _recursive_predecessors(vertices = Set.new)
|
63
|
+
incoming_edges.each do |edge|
|
64
|
+
vertex = edge.origin
|
65
|
+
next unless vertices.add?(vertex)
|
66
|
+
vertex._recursive_predecessors(vertices)
|
67
|
+
end
|
68
|
+
|
59
69
|
vertices
|
60
70
|
end
|
71
|
+
protected :_recursive_predecessors
|
61
72
|
|
62
73
|
# @return [Array<Vertex>] the vertices of {#graph} that have an edge with
|
63
74
|
# `self` as their {Edge#origin}
|
@@ -65,14 +76,25 @@ module Molinillo
|
|
65
76
|
outgoing_edges.map(&:destination)
|
66
77
|
end
|
67
78
|
|
68
|
-
# @return [
|
79
|
+
# @return [Set<Vertex>] the vertices of {#graph} where `self` is an
|
69
80
|
# {#ancestor?}
|
70
81
|
def recursive_successors
|
71
|
-
|
72
|
-
|
73
|
-
|
82
|
+
_recursive_successors
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param [Set<Vertex>] vertices the set to add the successors to
|
86
|
+
# @return [Set<Vertex>] the vertices of {#graph} where `self` is an
|
87
|
+
# {#ancestor?}
|
88
|
+
def _recursive_successors(vertices = Set.new)
|
89
|
+
outgoing_edges.each do |edge|
|
90
|
+
vertex = edge.destination
|
91
|
+
next unless vertices.add?(vertex)
|
92
|
+
vertex._recursive_successors(vertices)
|
93
|
+
end
|
94
|
+
|
74
95
|
vertices
|
75
96
|
end
|
97
|
+
protected :_recursive_successors
|
76
98
|
|
77
99
|
# @return [String] a string suitable for debugging
|
78
100
|
def inspect
|
@@ -108,11 +130,21 @@ module Molinillo
|
|
108
130
|
# dependency graph?
|
109
131
|
# @return true iff there is a path following edges within this {#graph}
|
110
132
|
def path_to?(other)
|
111
|
-
|
133
|
+
_path_to?(other)
|
112
134
|
end
|
113
135
|
|
114
136
|
alias descendent? path_to?
|
115
137
|
|
138
|
+
# @param [Vertex] other the vertex to check if there's a path to
|
139
|
+
# @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
|
140
|
+
# @return [Boolean] whether there is a path to `other` from `self`
|
141
|
+
def _path_to?(other, visited = Set.new)
|
142
|
+
return false unless visited.add?(self)
|
143
|
+
return true if equal?(other)
|
144
|
+
successors.any? { |v| v._path_to?(other, visited) }
|
145
|
+
end
|
146
|
+
protected :_path_to?
|
147
|
+
|
116
148
|
# Is there a path from `other` to `self` following edges in the
|
117
149
|
# dependency graph?
|
118
150
|
# @return true iff there is a path following edges within this {#graph}
|
data/lib/molinillo/errors.rb
CHANGED
@@ -18,7 +18,7 @@ module Molinillo
|
|
18
18
|
# @param [Array<Object>] required_by @see {#required_by}
|
19
19
|
def initialize(dependency, required_by = [])
|
20
20
|
@dependency = dependency
|
21
|
-
@required_by = required_by
|
21
|
+
@required_by = required_by.uniq
|
22
22
|
super()
|
23
23
|
end
|
24
24
|
|
@@ -65,7 +65,7 @@ module Molinillo
|
|
65
65
|
# @param [SpecificationProvider] specification_provider see {#specification_provider}
|
66
66
|
def initialize(conflicts, specification_provider)
|
67
67
|
pairs = []
|
68
|
-
|
68
|
+
conflicts.values.flat_map(&:requirements).each do |conflicting|
|
69
69
|
conflicting.each do |source, conflict_requirements|
|
70
70
|
conflict_requirements.each do |c|
|
71
71
|
pairs << [c, source]
|
@@ -80,7 +80,7 @@ module Molinillo
|
|
80
80
|
@specification_provider = specification_provider
|
81
81
|
end
|
82
82
|
|
83
|
-
|
83
|
+
require_relative 'delegates/specification_provider'
|
84
84
|
include Delegates::SpecificationProvider
|
85
85
|
|
86
86
|
# @return [String] An error message that includes requirement trees,
|
@@ -101,9 +101,14 @@ module Molinillo
|
|
101
101
|
printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
|
102
102
|
additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
|
103
103
|
version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
|
104
|
+
incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
|
105
|
+
proc do |name, _conflict|
|
106
|
+
%(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
|
107
|
+
end
|
108
|
+
end
|
104
109
|
|
105
110
|
conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
|
106
|
-
o <<
|
111
|
+
o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
|
107
112
|
if conflict.locked_requirement
|
108
113
|
o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
|
109
114
|
o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
|
data/lib/molinillo/resolution.rb
CHANGED
@@ -207,7 +207,7 @@ module Molinillo
|
|
207
207
|
def start_resolution
|
208
208
|
@started_at = Time.now
|
209
209
|
|
210
|
-
|
210
|
+
push_initial_state
|
211
211
|
|
212
212
|
debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
|
213
213
|
resolver_ui.before_resolution
|
@@ -218,7 +218,7 @@ module Molinillo
|
|
218
218
|
next unless vertex.payload
|
219
219
|
|
220
220
|
latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
|
221
|
-
vertex.requirements.
|
221
|
+
vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
|
222
222
|
end
|
223
223
|
|
224
224
|
activated.set_payload(vertex.name, latest_version)
|
@@ -238,11 +238,11 @@ module Molinillo
|
|
238
238
|
debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
|
239
239
|
end
|
240
240
|
|
241
|
-
|
242
|
-
|
241
|
+
require_relative 'state'
|
242
|
+
require_relative 'modules/specification_provider'
|
243
243
|
|
244
|
-
|
245
|
-
|
244
|
+
require_relative 'delegates/resolution_state'
|
245
|
+
require_relative 'delegates/specification_provider'
|
246
246
|
|
247
247
|
include Molinillo::Delegates::ResolutionState
|
248
248
|
include Molinillo::Delegates::SpecificationProvider
|
@@ -273,10 +273,10 @@ module Molinillo
|
|
273
273
|
states.last
|
274
274
|
end
|
275
275
|
|
276
|
-
# Creates the initial state for the resolution, based upon the
|
276
|
+
# Creates and pushes the initial state for the resolution, based upon the
|
277
277
|
# {#requested} dependencies
|
278
|
-
# @return [
|
279
|
-
def
|
278
|
+
# @return [void]
|
279
|
+
def push_initial_state
|
280
280
|
graph = DependencyGraph.new.tap do |dg|
|
281
281
|
original_requested.each do |requested|
|
282
282
|
vertex = dg.add_vertex(name_for(requested), nil, true)
|
@@ -285,18 +285,7 @@ module Molinillo
|
|
285
285
|
dg.tag(:initial_state)
|
286
286
|
end
|
287
287
|
|
288
|
-
|
289
|
-
initial_requirement = requirements.shift
|
290
|
-
DependencyState.new(
|
291
|
-
initial_requirement && name_for(initial_requirement),
|
292
|
-
requirements,
|
293
|
-
graph,
|
294
|
-
initial_requirement,
|
295
|
-
possibilities_for_requirement(initial_requirement, graph),
|
296
|
-
0,
|
297
|
-
{},
|
298
|
-
[]
|
299
|
-
)
|
288
|
+
push_state_for_requirements(original_requested, true, graph)
|
300
289
|
end
|
301
290
|
|
302
291
|
# Unwinds the states stack because a conflict has been encountered
|
@@ -361,7 +350,7 @@ module Molinillo
|
|
361
350
|
current_detail
|
362
351
|
end
|
363
352
|
|
364
|
-
# @param [Array<Object>] array of requirements that combine to create a conflict
|
353
|
+
# @param [Array<Object>] binding_requirements array of requirements that combine to create a conflict
|
365
354
|
# @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
|
366
355
|
# of resolving the passed requirements
|
367
356
|
def unwind_options_for_requirements(binding_requirements)
|
@@ -429,7 +418,7 @@ module Molinillo
|
|
429
418
|
end
|
430
419
|
|
431
420
|
# @param [DependencyState] state
|
432
|
-
# @param [Array] array of requirements
|
421
|
+
# @param [Array] binding_requirements array of requirements
|
433
422
|
# @return [Boolean] whether or not the given state has any possibilities
|
434
423
|
# that could satisfy the given requirements
|
435
424
|
def conflict_fixing_possibilities?(state, binding_requirements)
|
@@ -444,7 +433,8 @@ module Molinillo
|
|
444
433
|
|
445
434
|
# Filter's a state's possibilities to remove any that would not fix the
|
446
435
|
# conflict we've just rewound from
|
447
|
-
# @param [UnwindDetails] details of the conflict just
|
436
|
+
# @param [UnwindDetails] unwind_details details of the conflict just
|
437
|
+
# unwound from
|
448
438
|
# @return [void]
|
449
439
|
def filter_possibilities_after_unwind(unwind_details)
|
450
440
|
return unless state && !state.possibilities.empty?
|
@@ -458,14 +448,18 @@ module Molinillo
|
|
458
448
|
|
459
449
|
# Filter's a state's possibilities to remove any that would not satisfy
|
460
450
|
# the requirements in the conflict we've just rewound from
|
461
|
-
# @param [UnwindDetails] details of the conflict just unwound from
|
451
|
+
# @param [UnwindDetails] unwind_details details of the conflict just unwound from
|
462
452
|
# @return [void]
|
463
453
|
def filter_possibilities_for_primary_unwind(unwind_details)
|
464
|
-
|
454
|
+
unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
|
455
|
+
unwinds_to_state << unwind_details
|
456
|
+
unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
|
465
457
|
|
466
458
|
state.possibilities.reject! do |possibility_set|
|
467
459
|
possibility_set.possibilities.none? do |poss|
|
468
|
-
|
460
|
+
unwind_requirement_sets.any? do |requirements|
|
461
|
+
possibility_satisfies_requirements?(poss, requirements)
|
462
|
+
end
|
469
463
|
end
|
470
464
|
end
|
471
465
|
end
|
@@ -487,7 +481,7 @@ module Molinillo
|
|
487
481
|
|
488
482
|
# Filter's a state's possibilities to remove any that would (eventually)
|
489
483
|
# create a requirement in the conflict we've just rewound from
|
490
|
-
# @param [UnwindDetails] details of the conflict just unwound from
|
484
|
+
# @param [UnwindDetails] unwind_details details of the conflict just unwound from
|
491
485
|
# @return [void]
|
492
486
|
def filter_possibilities_for_parent_unwind(unwind_details)
|
493
487
|
unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
|
@@ -496,7 +490,7 @@ module Molinillo
|
|
496
490
|
primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
|
497
491
|
parent_unwinds = unwinds_to_state.uniq - primary_unwinds
|
498
492
|
|
499
|
-
allowed_possibility_sets =
|
493
|
+
allowed_possibility_sets = primary_unwinds.flat_map do |unwind|
|
500
494
|
states[unwind.state_index].possibilities.select do |possibility_set|
|
501
495
|
possibility_set.possibilities.any? do |poss|
|
502
496
|
possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
|
@@ -504,7 +498,7 @@ module Molinillo
|
|
504
498
|
end
|
505
499
|
end
|
506
500
|
|
507
|
-
requirements_to_avoid =
|
501
|
+
requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid)
|
508
502
|
|
509
503
|
state.possibilities.reject! do |possibility_set|
|
510
504
|
!allowed_possibility_sets.include?(possibility_set) &&
|
@@ -520,12 +514,12 @@ module Molinillo
|
|
520
514
|
|
521
515
|
possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
|
522
516
|
|
523
|
-
# When there
|
524
|
-
# (the one causing the circular) won
|
525
|
-
# (which won
|
526
|
-
# because it
|
527
|
-
# We need to make sure we have that requirement in the conflict
|
528
|
-
# otherwise we won
|
517
|
+
# When there's a `CircularDependency` error the conflicting requirement
|
518
|
+
# (the one causing the circular) won't be `conflict.requirement`
|
519
|
+
# (which won't be for the right state, because we won't have created it,
|
520
|
+
# because it's circular).
|
521
|
+
# We need to make sure we have that requirement in the conflict's list,
|
522
|
+
# otherwise we won't be able to unwind properly, so we just return all
|
529
523
|
# the requirements for the conflict.
|
530
524
|
return possible_binding_requirements if conflict.underlying_error
|
531
525
|
|
@@ -554,8 +548,8 @@ module Molinillo
|
|
554
548
|
end
|
555
549
|
|
556
550
|
# @param [Object] requirement we wish to check
|
557
|
-
# @param [Array] array of requirements
|
558
|
-
# @param [Array] array of possibilities the requirements will be used to filter
|
551
|
+
# @param [Array] possible_binding_requirements array of requirements
|
552
|
+
# @param [Array] possibilities array of possibilities the requirements will be used to filter
|
559
553
|
# @return [Boolean] whether or not the given requirement is required to filter
|
560
554
|
# out all elements of the array of possibilities.
|
561
555
|
def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
|
@@ -564,6 +558,7 @@ module Molinillo
|
|
564
558
|
end
|
565
559
|
end
|
566
560
|
|
561
|
+
# @param [Object] requirement
|
567
562
|
# @return [Object] the requirement that led to `requirement` being added
|
568
563
|
# to the list of requirements.
|
569
564
|
def parent_of(requirement)
|
@@ -573,6 +568,7 @@ module Molinillo
|
|
573
568
|
parent_state.requirement
|
574
569
|
end
|
575
570
|
|
571
|
+
# @param [String] name
|
576
572
|
# @return [Object] the requirement that led to a version of a possibility
|
577
573
|
# with the given name being activated.
|
578
574
|
def requirement_for_existing_name(name)
|
@@ -581,6 +577,7 @@ module Molinillo
|
|
581
577
|
states.find { |s| s.name == name }.requirement
|
582
578
|
end
|
583
579
|
|
580
|
+
# @param [Object] requirement
|
584
581
|
# @return [ResolutionState] the state whose `requirement` is the given
|
585
582
|
# `requirement`.
|
586
583
|
def find_state_for(requirement)
|
@@ -588,6 +585,7 @@ module Molinillo
|
|
588
585
|
states.find { |i| requirement == i.requirement }
|
589
586
|
end
|
590
587
|
|
588
|
+
# @param [Object] underlying_error
|
591
589
|
# @return [Conflict] a {Conflict} that reflects the failure to activate
|
592
590
|
# the {#possibility} in conjunction with the current {#state}
|
593
591
|
def create_conflict(underlying_error = nil)
|
@@ -624,6 +622,7 @@ module Molinillo
|
|
624
622
|
vertex.requirements.map { |r| requirement_tree_for(r) }
|
625
623
|
end
|
626
624
|
|
625
|
+
# @param [Object] requirement
|
627
626
|
# @return [Array<Object>] the list of requirements that led to
|
628
627
|
# `requirement` being required.
|
629
628
|
def requirement_tree_for(requirement)
|
@@ -669,9 +668,8 @@ module Molinillo
|
|
669
668
|
attempt_to_filter_existing_spec(existing_vertex)
|
670
669
|
else
|
671
670
|
latest = possibility.latest_version
|
672
|
-
|
673
|
-
|
674
|
-
!requirement_satisfied_by?(requirement, activated, possibility)
|
671
|
+
possibility.possibilities.select! do |possibility|
|
672
|
+
requirement_satisfied_by?(requirement, activated, possibility)
|
675
673
|
end
|
676
674
|
if possibility.latest_version.nil?
|
677
675
|
# ensure there's a possibility for better error messages
|
@@ -701,7 +699,7 @@ module Molinillo
|
|
701
699
|
|
702
700
|
# Generates a filtered version of the existing vertex's `PossibilitySet` using the
|
703
701
|
# current state's `requirement`
|
704
|
-
# @param [Object] existing vertex
|
702
|
+
# @param [Object] vertex existing vertex
|
705
703
|
# @return [PossibilitySet] filtered possibility set
|
706
704
|
def filtered_possibility_set(vertex)
|
707
705
|
PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
|
@@ -726,7 +724,7 @@ module Molinillo
|
|
726
724
|
end
|
727
725
|
|
728
726
|
# Requires the dependencies that the recently activated spec has
|
729
|
-
# @param [Object]
|
727
|
+
# @param [Object] possibility_set the PossibilitySet that has just been
|
730
728
|
# activated
|
731
729
|
# @return [void]
|
732
730
|
def require_nested_dependencies_for(possibility_set)
|
@@ -745,6 +743,8 @@ module Molinillo
|
|
745
743
|
# Pushes a new {DependencyState} that encapsulates both existing and new
|
746
744
|
# requirements
|
747
745
|
# @param [Array] new_requirements
|
746
|
+
# @param [Boolean] requires_sort
|
747
|
+
# @param [Object] new_activated
|
748
748
|
# @return [void]
|
749
749
|
def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
|
750
750
|
new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
|
@@ -763,7 +763,8 @@ module Molinillo
|
|
763
763
|
|
764
764
|
# Checks a proposed requirement with any existing locked requirement
|
765
765
|
# before generating an array of possibilities for it.
|
766
|
-
# @param [Object] the proposed requirement
|
766
|
+
# @param [Object] requirement the proposed requirement
|
767
|
+
# @param [Object] activated
|
767
768
|
# @return [Array] possibilities
|
768
769
|
def possibilities_for_requirement(requirement, activated = self.activated)
|
769
770
|
return [] unless requirement
|
@@ -774,7 +775,8 @@ module Molinillo
|
|
774
775
|
group_possibilities(search_for(requirement))
|
775
776
|
end
|
776
777
|
|
777
|
-
# @param [Object] the proposed requirement
|
778
|
+
# @param [Object] requirement the proposed requirement
|
779
|
+
# @param [Object] activated
|
778
780
|
# @return [Array] possibility set containing only the locked requirement, if any
|
779
781
|
def locked_requirement_possibility_set(requirement, activated = self.activated)
|
780
782
|
all_possibilities = search_for(requirement)
|
@@ -793,8 +795,8 @@ module Molinillo
|
|
793
795
|
# Build an array of PossibilitySets, with each element representing a group of
|
794
796
|
# dependency versions that all have the same sub-dependency version constraints
|
795
797
|
# and are contiguous.
|
796
|
-
# @param [Array] an array of possibilities
|
797
|
-
# @return [Array] an array of possibility sets
|
798
|
+
# @param [Array] possibilities an array of possibilities
|
799
|
+
# @return [Array<PossibilitySet>] an array of possibility sets
|
798
800
|
def group_possibilities(possibilities)
|
799
801
|
possibility_sets = []
|
800
802
|
current_possibility_set = nil
|
data/lib/molinillo/resolver.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'dependency_graph'
|
4
4
|
|
5
5
|
module Molinillo
|
6
6
|
# This class encapsulates a dependency resolver.
|
@@ -9,7 +9,7 @@ module Molinillo
|
|
9
9
|
#
|
10
10
|
#
|
11
11
|
class Resolver
|
12
|
-
|
12
|
+
require_relative 'resolution'
|
13
13
|
|
14
14
|
# @return [SpecificationProvider] the specification provider used
|
15
15
|
# in the resolution process
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: molinillo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel E. Giddins
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
41
|
+
description:
|
42
42
|
email:
|
43
43
|
- segiddins@segiddins.me
|
44
44
|
executables: []
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- LICENSE
|
51
51
|
- README.md
|
52
52
|
- lib/molinillo.rb
|
53
|
-
- lib/molinillo/compatibility.rb
|
54
53
|
- lib/molinillo/delegates/resolution_state.rb
|
55
54
|
- lib/molinillo/delegates/specification_provider.rb
|
56
55
|
- lib/molinillo/dependency_graph.rb
|
@@ -74,7 +73,7 @@ homepage: https://github.com/CocoaPods/Molinillo
|
|
74
73
|
licenses:
|
75
74
|
- MIT
|
76
75
|
metadata: {}
|
77
|
-
post_install_message:
|
76
|
+
post_install_message:
|
78
77
|
rdoc_options: []
|
79
78
|
require_paths:
|
80
79
|
- lib
|
@@ -82,17 +81,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
81
|
requirements:
|
83
82
|
- - ">="
|
84
83
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
84
|
+
version: 2.0.0
|
86
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
86
|
requirements:
|
88
87
|
- - ">="
|
89
88
|
- !ruby/object:Gem::Version
|
90
89
|
version: '0'
|
91
90
|
requirements: []
|
92
|
-
|
93
|
-
|
94
|
-
signing_key:
|
91
|
+
rubygems_version: 3.1.3
|
92
|
+
signing_key:
|
95
93
|
specification_version: 4
|
96
94
|
summary: Provides support for dependency resolution
|
97
95
|
test_files: []
|
98
|
-
has_rdoc:
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Molinillo
|
4
|
-
# Hacks needed for old Ruby versions.
|
5
|
-
module Compatibility
|
6
|
-
module_function
|
7
|
-
|
8
|
-
if [].respond_to?(:flat_map)
|
9
|
-
# Flat map
|
10
|
-
# @param [Enumerable] enum an enumerable object
|
11
|
-
# @block the block to flat-map with
|
12
|
-
# @return The enum, flat-mapped
|
13
|
-
def flat_map(enum, &blk)
|
14
|
-
enum.flat_map(&blk)
|
15
|
-
end
|
16
|
-
else
|
17
|
-
# Flat map
|
18
|
-
# @param [Enumerable] enum an enumerable object
|
19
|
-
# @block the block to flat-map with
|
20
|
-
# @return The enum, flat-mapped
|
21
|
-
def flat_map(enum, &blk)
|
22
|
-
enum.map(&blk).flatten(1)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|