solve 3.1.1 → 4.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -67,7 +67,7 @@ module Solve
67
67
  return false unless other.is_a?(Graph)
68
68
  return false unless artifacts.size == other.artifacts.size
69
69
 
70
- self_artifacts = self.artifacts
70
+ self_artifacts = artifacts
71
71
  other_artifacts = other.artifacts
72
72
 
73
73
  self_dependencies = self_artifacts.inject([]) do |list, artifact|
@@ -79,8 +79,8 @@ module Solve
79
79
  end.flatten
80
80
 
81
81
  self_dependencies.size == other_dependencies.size &&
82
- self_artifacts.all? { |artifact| other_artifacts.include?(artifact) } &&
83
- self_dependencies.all? { |dependency| other_dependencies.include?(dependency) }
82
+ self_artifacts.all? { |artifact| other_artifacts.include?(artifact) } &&
83
+ self_dependencies.all? { |dependency| other_dependencies.include?(dependency) }
84
84
  end
85
85
  alias_method :eql?, :==
86
86
  end
@@ -1,6 +1,7 @@
1
- require 'set'
2
- require 'molinillo'
3
- require_relative 'solver/serializer'
1
+ require "set" unless defined?(Set)
2
+ require "molinillo"
3
+ require "molinillo/modules/specification_provider"
4
+ require_relative "solver/serializer"
4
5
 
5
6
  module Solve
6
7
  class RubySolver
@@ -10,11 +11,11 @@ module Solve
10
11
  #
11
12
  # @return [Integer]
12
13
  def timeout
13
- seconds = 30 unless seconds = ENV["SOLVE_TIMEOUT"]
14
+ seconds = 30 unless ( seconds = ENV["SOLVE_TIMEOUT"] )
14
15
  seconds.to_i * 1_000
15
16
  end
16
17
 
17
- # For optinal solver engines, this attempts to load depenencies. The
18
+ # For optional solver engines, this attempts to load depenencies. The
18
19
  # RubySolver is a non-optional component, so this is a no-op
19
20
  def activate
20
21
  true
@@ -45,7 +46,7 @@ module Solve
45
46
  @timeout_ms = self.class.timeout
46
47
 
47
48
  @ui = options[:ui] # could be nil, but that's okay
48
- @dependency_source = options[:dependency_source] || 'user-specified dependency'
49
+ @dependency_source = options[:dependency_source] || "user-specified dependency"
49
50
 
50
51
  @molinillo_graph = Molinillo::DependencyGraph.new
51
52
  @resolver = Molinillo::Resolver.new(self, self)
@@ -74,10 +75,10 @@ module Solve
74
75
 
75
76
  solved_graph = resolve_with_error_wrapping
76
77
 
77
- solution = solved_graph.map(&:payload)
78
+ solution = solved_graph.map(&:payload)
78
79
 
79
80
  unsorted_solution = solution.inject({}) do |stringified_soln, artifact|
80
- stringified_soln[artifact.name] = artifact.version.to_s if artifact
81
+ stringified_soln[artifact.name] = artifact.version.to_s
81
82
  stringified_soln
82
83
  end
83
84
 
@@ -106,13 +107,13 @@ module Solve
106
107
  # Callback required by Molinillo, called when the solve starts
107
108
  # @return nil
108
109
  def before_resolution
109
- @ui.say('Starting dependency resolution') if @ui
110
+ @ui.say("Starting dependency resolution") if @ui
110
111
  end
111
112
 
112
113
  # Callback required by Molinillo, called when the solve is complete.
113
114
  # @return nil
114
115
  def after_resolution
115
- @ui.say('Finished dependency resolution') if @ui
116
+ @ui.say("Finished dependency resolution") if @ui
116
117
  end
117
118
 
118
119
  # Callback required by Molinillo, called when resolving every progress_rate
@@ -123,32 +124,22 @@ module Solve
123
124
 
124
125
  # Callback required by Molinillo, gives debug information about the solution
125
126
  # @return nil
126
- def debug(current_resolver_depth)
127
+ def debug(current_resolver_depth = 0)
127
128
  # debug info will be returned if you call yield here, but it seems to be
128
129
  # broken in current Molinillo
129
130
  @ui.say(yield) if @ui
130
131
  end
131
132
 
132
- # Callback required by Molinillo
133
- # @return [String] the dependency's name
134
- def name_for(dependency)
135
- dependency.name
136
- end
137
-
138
- # Callback required by Molinillo
139
- # @return [Array<Solve::Dependency>] the dependencies sorted by preference.
140
- def sort_dependencies(dependencies, activated, conflicts)
141
- dependencies.sort_by do |dependency|
142
- name = name_for(dependency)
143
- [
144
- activated.vertex_named(name).payload ? 0 : 1,
145
- conflicts[name] ? 0 : 1,
146
- activated.vertex_named(name).payload ? 0 : graph.versions(dependency.name).count,
147
- ]
148
- end
149
- end
133
+ include Molinillo::SpecificationProvider
150
134
 
151
135
  # Callback required by Molinillo
136
+ # Search for the specifications that match the given dependency.
137
+ # The specifications in the returned array will be considered in reverse
138
+ # order, so the latest version ought to be last.
139
+ # @note This method should be 'pure', i.e. the return value should depend
140
+ # only on the `dependency` parameter.
141
+ #
142
+ # @param [Object] dependency
152
143
  # @return [Array<Solve::Artifact>] the artifacts that match the dependency.
153
144
  def search_for(dependency)
154
145
  # This array gets mutated by Molinillo; it's okay because sort returns a
@@ -157,29 +148,103 @@ module Solve
157
148
  end
158
149
 
159
150
  # Callback required by Molinillo
160
- # @return [Boolean]
151
+ # Returns the dependencies of `specification`.
152
+ # @note This method should be 'pure', i.e. the return value should depend
153
+ # only on the `specification` parameter.
154
+ #
155
+ # @param [Object] specification
156
+ # @return [Array<Solve::Dependency>] the dependencies of the given artifact
157
+ def dependencies_for(specification)
158
+ specification.dependencies
159
+ end
160
+
161
+ # Callback required by Molinillo
162
+ # Determines whether the given `requirement` is satisfied by the given
163
+ # `spec`, in the context of the current `activated` dependency graph.
164
+ #
165
+ # @param [Object] requirement
166
+ # @param [DependencyGraph] activated the current dependency graph in the
167
+ # resolution process.
168
+ # @param [Object] spec
169
+ # @return [Boolean] whether `requirement` is satisfied by `spec` in the
170
+ # context of the current `activated` dependency graph.
161
171
  def requirement_satisfied_by?(requirement, activated, spec)
162
- requirement.constraint.satisfies?(spec.version)
172
+ version = spec.version
173
+ return false unless requirement.constraint.satisfies?(version)
174
+
175
+ shared_possibility_versions = possibility_versions(requirement, activated)
176
+ return false if !shared_possibility_versions.empty? && !shared_possibility_versions.include?(version)
177
+
178
+ true
163
179
  end
164
180
 
181
+ # Searches the current dependency graph to find previously activated
182
+ # requirements for the current artifact.
183
+ #
184
+ # @param [Object] requirement
185
+ # @param [DependencyGraph] activated the current dependency graph in the
186
+ # resolution process.
187
+ # @return [Array<Semverse::Version> the list of currently activated versions
188
+ # of this requirement
189
+ def possibility_versions(requirement, activated)
190
+ activated.vertices.values.flat_map do |vertex|
191
+
192
+ next unless vertex.payload
193
+
194
+ next unless vertex.name == requirement.name
195
+
196
+ if vertex.payload.respond_to?(:possibilities)
197
+ vertex.payload.possibilities.map(&:version)
198
+ else
199
+ vertex.payload.version
200
+ end
201
+ end.compact
202
+ end
203
+ private :possibility_versions
204
+
165
205
  # Callback required by Molinillo
166
- # @return [Array<Solve::Dependency>] the dependencies of the given artifact
167
- def dependencies_for(specification)
168
- specification.dependencies
206
+ # Returns the name for the given `dependency`.
207
+ # @note This method should be 'pure', i.e. the return value should depend
208
+ # only on the `dependency` parameter.
209
+ #
210
+ # @param [Object] dependency
211
+ # @return [String] the name for the given `dependency`.
212
+ def name_for(dependency)
213
+ dependency.name
169
214
  end
170
215
 
216
+ # Callback required by Molinillo
171
217
  # @return [String] the name of the source of explicit dependencies, i.e.
172
218
  # those passed to {Resolver#resolve} directly.
173
219
  def name_for_explicit_dependency_source
174
220
  @dependency_source
175
221
  end
176
222
 
177
- # @return [String] the name of the source of 'locked' dependencies, i.e.
178
- # those passed to {Resolver#resolve} directly as the `base`
179
- def name_for_locking_dependency_source
180
- 'Lockfile'
223
+ # Callback required by Molinillo
224
+ # Sort dependencies so that the ones that are easiest to resolve are first.
225
+ # Easiest to resolve is (usually) defined by:
226
+ # 1) Is this dependency already activated?
227
+ # 2) How relaxed are the requirements?
228
+ # 3) Are there any conflicts for this dependency?
229
+ # 4) How many possibilities are there to satisfy this dependency?
230
+ #
231
+ # @param [Array<Object>] dependencies
232
+ # @param [DependencyGraph] activated the current dependency graph in the
233
+ # resolution process.
234
+ # @param [{String => Array<Conflict>}] conflicts
235
+ # @return [Array<Solve::Dependency>] the dependencies sorted by preference.
236
+ def sort_dependencies(dependencies, activated, conflicts)
237
+ dependencies.sort_by do |dependency|
238
+ name = name_for(dependency)
239
+ [
240
+ activated.vertex_named(name).payload ? 0 : 1,
241
+ conflicts[name] ? 0 : 1,
242
+ search_for(dependency).count,
243
+ ]
244
+ end
181
245
  end
182
246
 
247
+ # Callback required by Molinillo
183
248
  # Returns whether this dependency, which has no possible matching
184
249
  # specifications, can safely be ignored.
185
250
  #
@@ -191,35 +256,35 @@ module Solve
191
256
 
192
257
  private
193
258
 
194
- def resolve_with_error_wrapping
195
- @resolver.resolve(demands, @molinillo_graph)
196
- rescue Molinillo::VersionConflict, Molinillo::CircularDependencyError => e
197
- raise Solve::Errors::NoSolutionError.new(e.message)
198
- end
259
+ def resolve_with_error_wrapping
260
+ @resolver.resolve(demands, @molinillo_graph)
261
+ rescue Molinillo::VersionConflict, Molinillo::CircularDependencyError => e
262
+ raise Solve::Errors::NoSolutionError.new(e.message)
263
+ end
199
264
 
200
- def build_sorted_solution(unsorted_solution)
201
- nodes = Hash.new
202
- unsorted_solution.each do |name, version|
203
- nodes[name] = @graph.artifact(name, version).dependencies.map(&:name)
204
- end
265
+ def build_sorted_solution(unsorted_solution)
266
+ nodes = {}
267
+ unsorted_solution.each do |name, version|
268
+ nodes[name] = @graph.artifact(name, version).dependencies.map(&:name)
269
+ end
205
270
 
206
- # Modified from http://ruby-doc.org/stdlib-1.9.3/libdoc/tsort/rdoc/TSort.html
207
- class << nodes
208
- include TSort
209
- alias tsort_each_node each_key
210
- def tsort_each_child(node, &block)
211
- fetch(node).each(&block)
212
- end
213
- end
214
- begin
215
- sorted_names = nodes.tsort
216
- rescue TSort::Cyclic => e
217
- raise Solve::Errors::UnsortableSolutionError.new(e, unsorted_solution)
271
+ # Modified from http://ruby-doc.org/stdlib-1.9.3/libdoc/tsort/rdoc/TSort.html
272
+ class << nodes
273
+ include TSort
274
+ alias tsort_each_node each_key
275
+ def tsort_each_child(node, &block)
276
+ fetch(node).each(&block)
218
277
  end
278
+ end
279
+ begin
280
+ sorted_names = nodes.tsort
281
+ rescue TSort::Cyclic => e
282
+ raise Solve::Errors::UnsortableSolutionError.new(e, unsorted_solution)
283
+ end
219
284
 
220
- sorted_names.map do |artifact|
221
- [artifact, unsorted_solution[artifact]]
222
- end
285
+ sorted_names.map do |artifact|
286
+ [artifact, unsorted_solution[artifact]]
223
287
  end
288
+ end
224
289
  end
225
290
  end
@@ -1,5 +1,5 @@
1
- require 'json'
2
- require 'solve/graph'
1
+ require "json" unless defined?(JSON)
2
+ require_relative "../graph"
3
3
 
4
4
  module Solve
5
5
 
@@ -58,71 +58,71 @@ module Solve
58
58
 
59
59
  private
60
60
 
61
- def format_graph(graph)
62
- artifacts = graph.artifacts.inject([]) do |list, artifact|
63
- list << format_artifact(artifact)
64
- end
65
- { "graph" => artifacts }
61
+ def format_graph(graph)
62
+ artifacts = graph.artifacts.inject([]) do |list, artifact|
63
+ list << format_artifact(artifact)
66
64
  end
65
+ { "graph" => artifacts }
66
+ end
67
67
 
68
- def format_artifact(artifact)
69
- dependencies = artifact.dependencies.inject([]) do |list, dependency|
70
- list << format_dependency(dependency)
71
- end
72
-
73
- {
74
- "name" => artifact.name,
75
- "version" => artifact.version.to_s,
76
- "dependencies" => dependencies
77
- }
68
+ def format_artifact(artifact)
69
+ dependencies = artifact.dependencies.inject([]) do |list, dependency|
70
+ list << format_dependency(dependency)
78
71
  end
79
72
 
80
- def format_dependency(dependency)
81
- {
82
- "name" => dependency.name,
83
- "constraint" => dependency.constraint.to_s
84
- }
85
- end
73
+ {
74
+ "name" => artifact.name,
75
+ "version" => artifact.version.to_s,
76
+ "dependencies" => dependencies,
77
+ }
78
+ end
86
79
 
87
- def format_demands(demands)
88
- demands_list = demands.inject([]) do |list, demand|
89
- list << format_demand(demand)
90
- end
91
- { "demands" => demands_list }
92
- end
80
+ def format_dependency(dependency)
81
+ {
82
+ "name" => dependency.name,
83
+ "constraint" => dependency.constraint.to_s,
84
+ }
85
+ end
93
86
 
94
- def format_demand(demand)
95
- {
96
- "name" => demand[0],
97
- "constraint" => demand[1]
98
- }
87
+ def format_demands(demands)
88
+ demands_list = demands.inject([]) do |list, demand|
89
+ list << format_demand(demand)
99
90
  end
91
+ { "demands" => demands_list }
92
+ end
100
93
 
101
- def load_graph(artifacts_list)
102
- graph = Solve::Graph.new
103
- artifacts_list.each do |artifact_spec|
104
- load_artifact(graph, artifact_spec)
105
- end
106
- graph
107
- end
94
+ def format_demand(demand)
95
+ {
96
+ "name" => demand[0],
97
+ "constraint" => demand[1],
98
+ }
99
+ end
108
100
 
109
- def load_artifact(graph, artifact_spec)
110
- artifact = graph.artifact(artifact_spec["name"], artifact_spec["version"])
111
- artifact_spec["dependencies"].each do |dependency_spec|
112
- load_dependency(artifact, dependency_spec)
113
- end
114
- artifact
101
+ def load_graph(artifacts_list)
102
+ graph = Solve::Graph.new
103
+ artifacts_list.each do |artifact_spec|
104
+ load_artifact(graph, artifact_spec)
115
105
  end
106
+ graph
107
+ end
116
108
 
117
- def load_dependency(artifact, dependency_spec)
118
- artifact.depends(dependency_spec["name"], dependency_spec["constraint"])
109
+ def load_artifact(graph, artifact_spec)
110
+ artifact = graph.artifact(artifact_spec["name"], artifact_spec["version"])
111
+ artifact_spec["dependencies"].each do |dependency_spec|
112
+ load_dependency(artifact, dependency_spec)
119
113
  end
114
+ artifact
115
+ end
120
116
 
121
- def load_demands(demand_specs)
122
- demand_specs.inject([]) do |list, demand_spec|
123
- list << [demand_spec["name"], demand_spec["constraint"]]
124
- end
117
+ def load_dependency(artifact, dependency_spec)
118
+ artifact.depends(dependency_spec["name"], dependency_spec["constraint"])
119
+ end
120
+
121
+ def load_demands(demand_specs)
122
+ demand_specs.inject([]) do |list, demand_spec|
123
+ list << [demand_spec["name"], demand_spec["constraint"]]
125
124
  end
125
+ end
126
126
  end
127
127
  end
128
128
  end
@@ -1,3 +1,3 @@
1
1
  module Solve
2
- VERSION = "3.1.1"
2
+ VERSION = "4.0.4".freeze
3
3
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solve
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 4.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Winsor
8
8
  - Andrew Garson
9
9
  - Thibaud Guillaume-Gentil
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-08-01 00:00:00.000000000 Z
13
+ date: 2020-08-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: semverse
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '1.1'
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
- version: '3.0'
24
+ version: '4.0'
25
25
  type: :runtime
26
26
  prerelease: false
27
27
  version_requirements: !ruby/object:Gem::Requirement
@@ -31,21 +31,21 @@ dependencies:
31
31
  version: '1.1'
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
- version: '3.0'
34
+ version: '4.0'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: molinillo
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '0.5'
41
+ version: '0.6'
42
42
  type: :runtime
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0.5'
48
+ version: '0.6'
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: thor
51
51
  requirement: !ruby/object:Gem::Requirement
@@ -111,15 +111,7 @@ executables: []
111
111
  extensions: []
112
112
  extra_rdoc_files: []
113
113
  files:
114
- - ".gitignore"
115
- - ".travis.yml"
116
- - Gemfile
117
- - Guardfile
118
114
  - LICENSE
119
- - NoGecode.gemfile
120
- - README.md
121
- - Rakefile
122
- - Thorfile
123
115
  - lib/solve.rb
124
116
  - lib/solve/artifact.rb
125
117
  - lib/solve/constraint.rb
@@ -131,26 +123,11 @@ files:
131
123
  - lib/solve/ruby_solver.rb
132
124
  - lib/solve/solver/serializer.rb
133
125
  - lib/solve/version.rb
134
- - solve.gemspec
135
- - spec/acceptance/benchmark.rb
136
- - spec/acceptance/large_graph_no_solution.rb
137
- - spec/acceptance/opscode_ci_graph.rb
138
- - spec/acceptance/ruby_solver_solutions_spec.rb
139
- - spec/acceptance/solutions_spec.rb
140
- - spec/spec_helper.rb
141
- - spec/unit/solve/artifact_spec.rb
142
- - spec/unit/solve/demand_spec.rb
143
- - spec/unit/solve/dependency_spec.rb
144
- - spec/unit/solve/gecode_solver_spec.rb
145
- - spec/unit/solve/graph_spec.rb
146
- - spec/unit/solve/ruby_solver_spec.rb
147
- - spec/unit/solve/solver/serializer_spec.rb
148
- - spec/unit/solve_spec.rb
149
126
  homepage: https://github.com/berkshelf/solve
150
127
  licenses:
151
- - Apache 2.0
128
+ - Apache-2.0
152
129
  metadata: {}
153
- post_install_message:
130
+ post_install_message:
154
131
  rdoc_options: []
155
132
  require_paths:
156
133
  - lib
@@ -165,23 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
142
  - !ruby/object:Gem::Version
166
143
  version: '0'
167
144
  requirements: []
168
- rubyforge_project:
169
- rubygems_version: 2.6.11
170
- signing_key:
145
+ rubygems_version: 3.1.2
146
+ signing_key:
171
147
  specification_version: 4
172
148
  summary: A Ruby version constraint solver implementing Semantic Versioning 2.0.0-rc.1
173
- test_files:
174
- - spec/acceptance/benchmark.rb
175
- - spec/acceptance/large_graph_no_solution.rb
176
- - spec/acceptance/opscode_ci_graph.rb
177
- - spec/acceptance/ruby_solver_solutions_spec.rb
178
- - spec/acceptance/solutions_spec.rb
179
- - spec/spec_helper.rb
180
- - spec/unit/solve/artifact_spec.rb
181
- - spec/unit/solve/demand_spec.rb
182
- - spec/unit/solve/dependency_spec.rb
183
- - spec/unit/solve/gecode_solver_spec.rb
184
- - spec/unit/solve/graph_spec.rb
185
- - spec/unit/solve/ruby_solver_spec.rb
186
- - spec/unit/solve/solver/serializer_spec.rb
187
- - spec/unit/solve_spec.rb
149
+ test_files: []