solve 3.1.1 → 4.0.4

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.
@@ -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: []