molinillo 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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