molinillo 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c0e6948c750e17cfaf091e5cd1f94ac58e4bffe
4
- data.tar.gz: 64427be3edf97f492aef46c7c6eb69f1e262e25e
3
+ metadata.gz: 59b5cd0ec4345cc73a54775616b40161fb2af5a4
4
+ data.tar.gz: d38ad81fd35dcb0cc20a05005f5945c51c22b041
5
5
  SHA512:
6
- metadata.gz: 2e11fb6bebe0f6797d7c855cfe92aef39054a7d82cccb9e6b78b080bb69bdb9455aa4e8b13fc613a4acd3c430fb3a6faf96ae5d63663404f377a95bbc417136e
7
- data.tar.gz: e4d395af07f86d361e5fa47c13e098f3ee77f4f878311a93c9a64bcbc87d1775837233f2096ccc84196a2b13c68586852097ad1e866e9814e09212a8d82c5dda
6
+ metadata.gz: 7ef9ce46b630677f9ad68fe2861be96bce9a90e66e12e065f75387ed01cf50c6200e8bb79128abec09a4a56f5fd11ab5f47d1e7eb3754549c6f2fd7cd3c4ca3e
7
+ data.tar.gz: 731564965a432a6b80a74ccc312936e43c1b3ad11f8be2f322eee01e8ce3d831c91979139b079436b20bd072d52640420356c9a6db095f4582d5a514bd25485d
@@ -1,14 +1,36 @@
1
1
  require 'set'
2
+ require 'tsort'
2
3
 
3
4
  module Molinillo
4
5
  # A directed acyclic graph that is tuned to hold named dependencies
5
6
  class DependencyGraph
6
7
  include Enumerable
7
8
 
9
+ # Enumerates through the vertices of the graph.
10
+ # @return [Array<Vertex>] The graph's vertices.
8
11
  def each
9
12
  vertices.values.each { |v| yield v }
10
13
  end
11
14
 
15
+ include TSort
16
+
17
+ alias_method :tsort_each_node, :each
18
+
19
+ def tsort_each_child(vertex, &block)
20
+ vertex.successors.each(&block)
21
+ end
22
+
23
+ # Topologically sorts the given vertices.
24
+ # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
25
+ # all belong to the same graph.
26
+ # @return [Array<Vertex>] The sorted vertices.
27
+ def self.tsort(vertices)
28
+ TSort.tsort(
29
+ lambda { |b| vertices.each(&b) },
30
+ lambda { |v, &b| (v.successors & vertices).each(&b) }
31
+ )
32
+ end
33
+
12
34
  # A directed edge of a {DependencyGraph}
13
35
  # @attr [Vertex] origin The origin of the directed edge
14
36
  # @attr [Vertex] destination The destination of the directed edge
@@ -162,7 +184,7 @@ module Molinillo
162
184
  # @return [Array<Object>] all of the requirements that required
163
185
  # this vertex
164
186
  def requirements
165
- incoming_edges.flat_map(&:requirements) + explicit_requirements
187
+ incoming_edges.map(&:requirements).flatten + explicit_requirements
166
188
  end
167
189
 
168
190
  # @return [Array<Edge>] the edges of {#graph} that have `self` as their
@@ -1,3 +1,3 @@
1
1
  module Molinillo
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -40,7 +40,6 @@ module Molinillo
40
40
  end
41
41
 
42
42
  # Conveys debug information to the user.
43
- # By default, prints to `STDERR` instead of {#output}.
44
43
  #
45
44
  # @param [Integer] depth the current depth of the resolution process.
46
45
  # @return [void]
@@ -48,7 +47,7 @@ module Molinillo
48
47
  if debug?
49
48
  debug_info = yield
50
49
  debug_info = debug_info.inspect unless debug_info.is_a?(String)
51
- STDERR.puts debug_info.split("\n").map { |s| ' ' * depth + s }
50
+ output.puts debug_info.split("\n").map { |s| ' ' * depth + s }
52
51
  end
53
52
  end
54
53
 
@@ -9,11 +9,16 @@ module Molinillo
9
9
  # the {#possibility}
10
10
  # @attr [Object] possibility the spec that was unable to be activated due
11
11
  # to a conflict
12
+ # @attr [Object] locked_requirement the relevant locking requirement.
13
+ # @attr [Array<Array<Object>>] requirement_trees the different requirement
14
+ # trees that led to every requirement for the conflicting name.
12
15
  Conflict = Struct.new(
13
16
  :requirement,
14
17
  :requirements,
15
18
  :existing,
16
- :possibility
19
+ :possibility,
20
+ :locked_requirement,
21
+ :requirement_trees
17
22
  )
18
23
 
19
24
  # @return [SpecificationProvider] the provider that knows about
@@ -176,8 +181,7 @@ module Molinillo
176
181
  def unwind_for_conflict
177
182
  debug(depth) { "Unwinding for conflict: #{requirement}" }
178
183
  conflicts.tap do |c|
179
- states.slice!(state_index_for_unwind..-1)
180
- states.pop if state
184
+ states.slice!((state_index_for_unwind + 1)..-1)
181
185
  raise VersionConflict.new(c) unless state
182
186
  state.conflicts = c
183
187
  end
@@ -186,22 +190,58 @@ module Molinillo
186
190
  # @return [Integer] The index to which the resolution should unwind in the
187
191
  # case of conflict.
188
192
  def state_index_for_unwind
189
- index = states.rindex do |state|
190
- return nil unless vertex = state.activated.vertex_named(name)
191
- state.is_a?(DependencyState) &&
192
- (
193
- !vertex.payload ||
194
- (!state.requirements.include?(requirement) && state.requirement != requirement)
195
- )
193
+ current_requirement = requirement
194
+ existing_requirement = requirement_for_existing_name(name)
195
+ until current_requirement.nil?
196
+ current_state = find_state_for(current_requirement)
197
+ return states.index(current_state) if state_any?(current_state)
198
+ current_requirement = parent_of(current_requirement)
196
199
  end
197
- index + 2
200
+
201
+ until existing_requirement.nil?
202
+ existing_state = find_state_for(existing_requirement)
203
+ return states.index(existing_state) if state_any?(existing_state)
204
+ existing_requirement = parent_of(existing_requirement)
205
+ end
206
+ -1
207
+ end
208
+
209
+ # @return [Object] the requirement that led to `requirement` being added
210
+ # to the list of requirements.
211
+ def parent_of(requirement)
212
+ return nil unless requirement
213
+ seen = false
214
+ state = states.reverse_each.find do |s|
215
+ seen ||= s.requirement == requirement
216
+ seen && s.requirement != requirement && !s.requirements.include?(requirement)
217
+ end
218
+ state && state.requirement
219
+ end
220
+
221
+ # @return [Object] the requirement that led to a version of a possibility
222
+ # with the given name being activated.
223
+ def requirement_for_existing_name(name)
224
+ return nil unless activated.vertex_named(name).payload
225
+ states.reverse_each.find { |s| !s.activated.vertex_named(name).payload }.requirement
226
+ end
227
+
228
+ # @return [ResolutionState] the state whose `requirement` is the given
229
+ # `requirement`.
230
+ def find_state_for(requirement)
231
+ return nil unless requirement
232
+ states.find { |i| requirement == i.requirement }
233
+ end
234
+
235
+ # @return [Boolean] whether or not the given state has any possibilities
236
+ # left.
237
+ def state_any?(state)
238
+ state && state.possibilities.any?
198
239
  end
199
240
 
200
241
  # @return [Conflict] a {Conflict} that reflects the failure to activate
201
242
  # the {#possibility} in conjunction with the current {#state}
202
243
  def create_conflict
203
244
  vertex = activated.vertex_named(name)
204
- existing = vertex.payload
205
245
  requirements = {
206
246
  name_for_explicit_dependency_source => vertex.explicit_requirements,
207
247
  name_for_locking_dependency_source => Array(locked_requirement_named(name)),
@@ -210,11 +250,30 @@ module Molinillo
210
250
  conflicts[name] = Conflict.new(
211
251
  requirement,
212
252
  Hash[requirements.select { |_, r| !r.empty? }],
213
- existing,
214
- possibility
253
+ vertex.payload,
254
+ possibility,
255
+ locked_requirement_named(name),
256
+ requirement_trees
215
257
  )
216
258
  end
217
259
 
260
+ # @return [Array<Array<Object>>] The different requirement
261
+ # trees that led to every requirement for the current spec.
262
+ def requirement_trees
263
+ activated.vertex_named(name).requirements.map { |r| requirement_tree_for(r) }
264
+ end
265
+
266
+ # @return [Array<Object>] the list of requirements that led to
267
+ # `requirement` being required.
268
+ def requirement_tree_for(requirement)
269
+ tree = []
270
+ while requirement
271
+ tree.unshift(requirement)
272
+ requirement = parent_of(requirement)
273
+ end
274
+ tree
275
+ end
276
+
218
277
  # Indicates progress roughly once every second
219
278
  # @return [void]
220
279
  def indicate_progress
@@ -7,7 +7,7 @@ module Molinillo
7
7
  File.open(FIXTURE_INDEX_DIR + (fixture_name + '.json'), 'r') do |fixture|
8
8
  self.specs = JSON.load(fixture).reduce(Hash.new([])) do |specs_by_name, (name, versions)|
9
9
  specs_by_name.tap do |specs|
10
- specs[name] = versions.map { |s| TestSpecification.new s }.sort { |x, y| x.version <=> y.version }
10
+ specs[name] = versions.map { |s| TestSpecification.new s }.sort_by(&:version)
11
11
  end
12
12
  end
13
13
  end
@@ -24,8 +24,9 @@ module Molinillo
24
24
 
25
25
  def search_for(dependency)
26
26
  pre_release = dependency_pre_release?(dependency)
27
- specs[dependency.name].reject do |spec|
28
- pre_release ? false : spec.version.pre_release?
27
+ specs[dependency.name].select do |spec|
28
+ (pre_release ? true : !spec.version.pre_release?) &&
29
+ dependency.satisfied_by?(spec.version)
29
30
  end
30
31
  end
31
32
 
@@ -43,7 +44,7 @@ module Molinillo
43
44
  activated.vertex_named(d.name).payload ? 0 : 1,
44
45
  dependency_pre_release?(d) ? 0 : 1,
45
46
  conflicts[d.name] ? 0 : 1,
46
- specs[d.name].count,
47
+ activated.vertex_named(d.name).payload ? 0 : search_for(d).count,
47
48
  ]
48
49
  end
49
50
  end
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.1.2
4
+ version: 0.2.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: 2014-11-19 00:00:00.000000000 Z
11
+ date: 2014-12-25 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:
@@ -45,9 +45,6 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - LICENSE
49
- - README.md
50
- - lib/molinillo.rb
51
48
  - lib/molinillo/dependency_graph.rb
52
49
  - lib/molinillo/errors.rb
53
50
  - lib/molinillo/gem_metadata.rb
@@ -56,12 +53,15 @@ files:
56
53
  - lib/molinillo/resolution.rb
57
54
  - lib/molinillo/resolver.rb
58
55
  - lib/molinillo/state.rb
56
+ - lib/molinillo.rb
57
+ - README.md
58
+ - LICENSE
59
59
  - spec/dependency_graph_spec.rb
60
60
  - spec/resolver_spec.rb
61
- - spec/spec_helper.rb
62
61
  - spec/spec_helper/index.rb
63
62
  - spec/spec_helper/specification.rb
64
63
  - spec/spec_helper/ui.rb
64
+ - spec/spec_helper.rb
65
65
  - spec/state_spec.rb
66
66
  homepage: https://github.com/CocoaPods/Molinillo
67
67
  licenses:
@@ -73,17 +73,17 @@ require_paths:
73
73
  - lib
74
74
  required_ruby_version: !ruby/object:Gem::Requirement
75
75
  requirements:
76
- - - ">="
76
+ - - '>='
77
77
  - !ruby/object:Gem::Version
78
78
  version: '0'
79
79
  required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - ">="
81
+ - - '>='
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  requirements: []
85
85
  rubyforge_project:
86
- rubygems_version: 2.2.2
86
+ rubygems_version: 2.0.14
87
87
  signing_key:
88
88
  specification_version: 4
89
89
  summary: Provides support for dependency resolution