solve 3.1.1 → 4.0.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 +4 -4
- data/.travis.yml +10 -7
- data/Gemfile +20 -17
- data/Guardfile +6 -6
- data/Rakefile +11 -1
- data/Thorfile +3 -3
- data/lib/solve.rb +9 -11
- data/lib/solve/artifact.rb +10 -10
- data/lib/solve/constraint.rb +41 -41
- data/lib/solve/demand.rb +2 -2
- data/lib/solve/dependency.rb +4 -2
- data/lib/solve/errors.rb +1 -1
- data/lib/solve/gecode_solver.rb +94 -94
- data/lib/solve/graph.rb +3 -3
- data/lib/solve/ruby_solver.rb +125 -62
- data/lib/solve/solver/serializer.rb +53 -53
- data/lib/solve/version.rb +1 -1
- data/solve.gemspec +7 -7
- data/spec/acceptance/benchmark.rb +4 -4
- data/spec/acceptance/large_graph_no_solution.rb +18727 -18727
- data/spec/acceptance/opscode_ci_graph.rb +18598 -18598
- data/spec/acceptance/ruby_solver_solutions_spec.rb +14 -15
- data/spec/acceptance/solutions_spec.rb +14 -15
- data/spec/spec_helper.rb +15 -8
- data/spec/unit/solve/artifact_spec.rb +5 -5
- data/spec/unit/solve/demand_spec.rb +2 -2
- data/spec/unit/solve/dependency_spec.rb +3 -3
- data/spec/unit/solve/gecode_solver_spec.rb +6 -7
- data/spec/unit/solve/graph_spec.rb +7 -7
- data/spec/unit/solve/ruby_solver_spec.rb +5 -6
- data/spec/unit/solve/solver/serializer_spec.rb +2 -2
- data/spec/unit/solve_spec.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af5099b9f2b7ff996d32e8082de7f3f8085bf5aa
|
4
|
+
data.tar.gz: 8b6541e4ce764b2c1db8ade3c8b1ba5a19060c47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21fc447438917b86a09f5741b0b325ba030d4f654b1831806bb987c68bbc22975c83725fa1e5845f22cd1b35a7ecbcc8dbf56d6f44ec3c09ec97113199c7263d
|
7
|
+
data.tar.gz: b8862c18f07f3fea2c0033f54848a073ab387edc1b9f489439ee2b088ff78cdb36cf7f97d98cdb66396771f6990d4ee44004a7047c081f33f17291d25b5c2a67
|
data/.travis.yml
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
sudo: true
|
2
1
|
language: ruby
|
3
|
-
cache:
|
4
|
-
|
2
|
+
cache:
|
3
|
+
- apt
|
4
|
+
- bundler
|
5
5
|
|
6
6
|
before_install:
|
7
7
|
- sudo apt-get update
|
8
8
|
- gem install bundler --no-ri --no-rdoc
|
9
9
|
|
10
|
-
install: travis_wait bundle install --without
|
10
|
+
install: travis_wait bundle install --without guard --jobs 7 --retry=3
|
11
11
|
script: "bundle exec thor spec"
|
12
12
|
# prevent PR branches from running travis twice
|
13
13
|
branches:
|
@@ -16,7 +16,10 @@ branches:
|
|
16
16
|
|
17
17
|
matrix:
|
18
18
|
include:
|
19
|
-
- rvm: 2.
|
20
|
-
- rvm: 2.
|
21
|
-
- rvm: 2.3.1
|
19
|
+
- rvm: 2.3.3
|
20
|
+
- rvm: 2.4.1
|
22
21
|
- rvm: ruby-head
|
22
|
+
- rvm: 2.4.1
|
23
|
+
env:
|
24
|
+
CHEFSTYLE: 1
|
25
|
+
script: bundle exec rake style
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
@@ -9,25 +9,28 @@ end
|
|
9
9
|
# If this group is named "development", then `bundle install --without
|
10
10
|
# development` automagically excludes development dependencies that are listed
|
11
11
|
# in the gemspec, which will skip installing rspec and then we can't run tests.
|
12
|
-
group :
|
13
|
-
gem
|
14
|
-
gem
|
15
|
-
gem
|
16
|
-
gem
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
group :development do
|
13
|
+
gem "fuubar"
|
14
|
+
gem "yard"
|
15
|
+
gem "redcarpet"
|
16
|
+
gem "chefstyle", git: "https://github.com/chef/chefstyle"
|
17
|
+
end
|
18
|
+
|
19
|
+
group :guard do
|
20
|
+
gem "guard-rspec"
|
21
|
+
gem "guard-spork"
|
22
|
+
gem "guard-yard"
|
23
|
+
gem "coolline"
|
20
24
|
|
21
|
-
require
|
25
|
+
require "rbconfig"
|
22
26
|
|
23
|
-
if RbConfig::CONFIG[
|
24
|
-
gem
|
27
|
+
if RbConfig::CONFIG["target_os"] =~ /darwin/i
|
28
|
+
gem "ruby_gntp", require: false
|
25
29
|
|
26
|
-
elsif RbConfig::CONFIG[
|
27
|
-
gem
|
30
|
+
elsif RbConfig::CONFIG["target_os"] =~ /linux/i
|
31
|
+
gem "libnotify", require: false
|
28
32
|
|
29
|
-
elsif RbConfig::CONFIG[
|
30
|
-
gem
|
33
|
+
elsif RbConfig::CONFIG["target_os"] =~ /mswin|mingw/i
|
34
|
+
gem "win32console", require: false
|
31
35
|
end
|
32
36
|
end
|
33
|
-
|
data/Guardfile
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
guard
|
2
|
-
watch(
|
3
|
-
watch(
|
1
|
+
guard "spork", rspec_port: 8991 do
|
2
|
+
watch("Gemfile")
|
3
|
+
watch("spec/spec_helper.rb") { :rspec }
|
4
4
|
end
|
5
5
|
|
6
|
-
guard
|
6
|
+
guard "yard", port: 8809, stdout: "/dev/null", stderr: "/dev/null" do
|
7
7
|
watch(%r{app/.+\.rb})
|
8
8
|
watch(%r{lib/.+\.rb})
|
9
9
|
watch(%r{ext/.+\.c})
|
10
10
|
end
|
11
11
|
|
12
|
-
guard
|
12
|
+
guard "rspec", cli: "--color --drb --drb-port 8991 --format Fuubar", all_on_start: false, all_after_pass: false, notification: false do
|
13
13
|
watch(%r{^spec/acceptance/.+_spec\.rb$})
|
14
14
|
watch(%r{^spec/unit/.+_spec\.rb$})
|
15
15
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
16
|
-
watch(
|
16
|
+
watch("spec/spec_helper.rb") { "spec" }
|
17
17
|
end
|
data/Rakefile
CHANGED
@@ -1 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "chefstyle"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
RuboCop::RakeTask.new(:style) do |task|
|
7
|
+
task.options += ["--display-cop-names", "--no-color"]
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
puts "chefstyle/rubocop is not available. gem install chefstyle to do style checking."
|
11
|
+
end
|
data/Thorfile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
4
|
+
require "bundler"
|
5
|
+
require "bundler/setup"
|
6
|
+
require "thor/rake_compat"
|
7
7
|
|
8
8
|
class Default < Thor
|
9
9
|
include Thor::RakeCompat
|
data/lib/solve.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "semverse"
|
2
2
|
|
3
3
|
module Solve
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
4
|
+
require_relative "solve/artifact"
|
5
|
+
require_relative "solve/demand"
|
6
|
+
require_relative "solve/dependency"
|
7
|
+
require_relative "solve/version"
|
8
|
+
require_relative "solve/errors"
|
9
|
+
require_relative "solve/graph"
|
10
|
+
require_relative "solve/ruby_solver"
|
11
|
+
require_relative "solve/gecode_solver"
|
12
12
|
|
13
13
|
# We have to set the default engine here, it gets set on the wrong object if
|
14
14
|
# we put this in the metaclass context below.
|
@@ -23,7 +23,6 @@ module Solve
|
|
23
23
|
# @return [Symbol]
|
24
24
|
attr_reader :engine
|
25
25
|
|
26
|
-
|
27
26
|
# Sets the solving backend engine. Solve supports 2 engines:
|
28
27
|
# * `:ruby` - Molinillo, a pure ruby solver
|
29
28
|
# * `:gecode` - dep-selector, a wrapper around the Gecode CSP solver library
|
@@ -77,4 +76,3 @@ module Solve
|
|
77
76
|
end
|
78
77
|
|
79
78
|
end
|
80
|
-
|
data/lib/solve/artifact.rb
CHANGED
@@ -74,7 +74,7 @@ module Solve
|
|
74
74
|
# .depends('ntp', '~> 1.3')
|
75
75
|
#
|
76
76
|
# @return [Solve::Artifact]
|
77
|
-
def depends(name, constraint =
|
77
|
+
def depends(name, constraint = ">= 0.0.0")
|
78
78
|
unless dependency?(name, constraint)
|
79
79
|
set_dependency(name, constraint)
|
80
80
|
end
|
@@ -91,8 +91,8 @@ module Solve
|
|
91
91
|
# @return [Boolean]
|
92
92
|
def ==(other)
|
93
93
|
other.is_a?(self.class) &&
|
94
|
-
|
95
|
-
|
94
|
+
name == other.name &&
|
95
|
+
version == other.version
|
96
96
|
end
|
97
97
|
alias_method :eql?, :==
|
98
98
|
|
@@ -100,17 +100,17 @@ module Solve
|
|
100
100
|
#
|
101
101
|
# @return [Integer]
|
102
102
|
def <=>(other)
|
103
|
-
|
103
|
+
version <=> other.version
|
104
104
|
end
|
105
105
|
|
106
106
|
private
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
def get_dependency(name, constraint)
|
109
|
+
@dependencies["#{name}-#{constraint}"]
|
110
|
+
end
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
def set_dependency(name, constraint)
|
113
|
+
@dependencies["#{name}-#{constraint}"] = Dependency.new(self, name, constraint)
|
114
|
+
end
|
115
115
|
end
|
116
116
|
end
|
data/lib/solve/constraint.rb
CHANGED
@@ -48,17 +48,17 @@ module Solve
|
|
48
48
|
end
|
49
49
|
|
50
50
|
split_version = case version.to_s
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
51
|
+
when /^(\d+)\.(\d+)\.(\d+)(-([0-9a-z\-\.]+))?(\+([0-9a-z\-\.]+))?$/i
|
52
|
+
[ $1.to_i, $2.to_i, $3.to_i, $5, $7 ]
|
53
|
+
when /^(\d+)\.(\d+)\.(\d+)?$/
|
54
|
+
[ $1.to_i, $2.to_i, $3.to_i, nil, nil ]
|
55
|
+
when /^(\d+)\.(\d+)?$/
|
56
|
+
[ $1.to_i, $2.to_i, nil, nil, nil ]
|
57
|
+
when /^(\d+)$/
|
58
|
+
[ $1.to_i, nil, nil, nil, nil ]
|
59
|
+
else
|
60
|
+
raise Errors::InvalidConstraintFormat.new(constraint)
|
61
|
+
end
|
62
62
|
|
63
63
|
[ operator, split_version ].flatten
|
64
64
|
end
|
@@ -110,18 +110,18 @@ module Solve
|
|
110
110
|
def compare_approx(constraint, target_version)
|
111
111
|
min = constraint.version
|
112
112
|
max = if constraint.patch.nil?
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
113
|
+
Semverse::Version.new([min.major + 1, 0, 0, 0])
|
114
|
+
elsif constraint.build
|
115
|
+
identifiers = constraint.version.identifiers(:build)
|
116
|
+
replace = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
|
117
|
+
Semverse::Version.new([min.major, min.minor, min.patch, min.pre_release, identifiers.fill(replace, -1).join(".")])
|
118
|
+
elsif constraint.pre_release
|
119
|
+
identifiers = constraint.version.identifiers(:pre_release)
|
120
|
+
replace = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
|
121
|
+
Semverse::Version.new([min.major, min.minor, min.patch, identifiers.fill(replace, -1).join(".")])
|
122
|
+
else
|
123
|
+
Semverse::Version.new([min.major, min.minor + 1, 0, 0])
|
124
|
+
end
|
125
125
|
min <= target_version && target_version < max
|
126
126
|
end
|
127
127
|
end
|
@@ -142,7 +142,7 @@ module Solve
|
|
142
142
|
greater_than: method(:compare_gt),
|
143
143
|
less_than_equal: method(:compare_lte),
|
144
144
|
less_than: method(:compare_lt),
|
145
|
-
equal: method(:compare_equal)
|
145
|
+
equal: method(:compare_equal),
|
146
146
|
}.freeze
|
147
147
|
|
148
148
|
REGEXP = /^(#{OPERATOR_TYPES.keys.join('|')})\s?(.+)$/
|
@@ -164,7 +164,7 @@ module Solve
|
|
164
164
|
def initialize(constraint = nil)
|
165
165
|
constraint = constraint.to_s
|
166
166
|
if constraint.nil? || constraint.empty?
|
167
|
-
constraint =
|
167
|
+
constraint = ">= 0.0.0"
|
168
168
|
end
|
169
169
|
|
170
170
|
@operator, @major, @minor, @patch, @pre_release, @build = self.class.split(constraint)
|
@@ -175,18 +175,18 @@ module Solve
|
|
175
175
|
end
|
176
176
|
|
177
177
|
@version = Semverse::Version.new([
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
178
|
+
major,
|
179
|
+
minor,
|
180
|
+
patch,
|
181
|
+
pre_release,
|
182
|
+
build,
|
183
183
|
])
|
184
184
|
end
|
185
185
|
|
186
186
|
# @return [Symbol]
|
187
187
|
def operator_type
|
188
188
|
unless type = OPERATOR_TYPES.fetch(operator)
|
189
|
-
raise
|
189
|
+
raise "unknown operator type: #{operator}"
|
190
190
|
end
|
191
191
|
|
192
192
|
type
|
@@ -201,7 +201,7 @@ module Solve
|
|
201
201
|
def satisfies?(target)
|
202
202
|
target = Semverse::Version.coerce(target)
|
203
203
|
|
204
|
-
return false if !version
|
204
|
+
return false if !(version == 0) && greedy_match?(target)
|
205
205
|
|
206
206
|
compare(target)
|
207
207
|
end
|
@@ -215,13 +215,13 @@ module Solve
|
|
215
215
|
# @return [Boolean]
|
216
216
|
def ==(other)
|
217
217
|
other.is_a?(self.class) &&
|
218
|
-
|
219
|
-
|
218
|
+
operator == other.operator &&
|
219
|
+
version == other.version
|
220
220
|
end
|
221
221
|
alias_method :eql?, :==
|
222
222
|
|
223
223
|
def inspect
|
224
|
-
"#<#{self.class
|
224
|
+
"#<#{self.class} #{self}>"
|
225
225
|
end
|
226
226
|
|
227
227
|
def to_s
|
@@ -241,15 +241,15 @@ module Solve
|
|
241
241
|
#
|
242
242
|
# @param [Semverse::Version] target_version
|
243
243
|
#
|
244
|
-
|
245
|
-
|
246
|
-
|
244
|
+
def greedy_match?(target_version)
|
245
|
+
operator_type !~ /less/ && target_version.pre_release? && !version.pre_release?
|
246
|
+
end
|
247
247
|
|
248
248
|
# @param [Semverse::Version] target
|
249
249
|
#
|
250
250
|
# @return [Boolean]
|
251
|
-
|
252
|
-
|
253
|
-
|
251
|
+
def compare(target)
|
252
|
+
COMPARE_FUNS.fetch(operator_type).call(self, target)
|
253
|
+
end
|
254
254
|
end
|
255
255
|
end
|
data/lib/solve/demand.rb
CHANGED
data/lib/solve/dependency.rb
CHANGED
@@ -27,14 +27,16 @@ module Solve
|
|
27
27
|
def to_s
|
28
28
|
"#{name} (#{constraint})"
|
29
29
|
end
|
30
|
+
alias :inspect :to_s
|
30
31
|
|
31
32
|
# @param [Object] other
|
32
33
|
#
|
33
34
|
# @return [Boolean]
|
34
35
|
def ==(other)
|
35
36
|
other.is_a?(self.class) &&
|
36
|
-
|
37
|
-
|
37
|
+
name == other.name &&
|
38
|
+
artifact == other.artifact &&
|
39
|
+
constraint == other.constraint
|
38
40
|
end
|
39
41
|
alias_method :eql?, :==
|
40
42
|
end
|
data/lib/solve/errors.rb
CHANGED
@@ -49,7 +49,7 @@ module Solve
|
|
49
49
|
s << "#{@message}\n"
|
50
50
|
s << "Missing artifacts: #{missing_artifacts.join(',')}\n" unless missing_artifacts.empty?
|
51
51
|
unless constraints_excluding_all_artifacts.empty?
|
52
|
-
|
52
|
+
pretty = constraints_excluding_all_artifacts.map { |constraint| "(#{constraint[0]} #{constraint[1]})" }.join(",")
|
53
53
|
s << "Constraints that match no available version: #{pretty}\n"
|
54
54
|
end
|
55
55
|
s << "Demand that cannot be met: #{unsatisfiable_demand}\n" if unsatisfiable_demand
|
data/lib/solve/gecode_solver.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require_relative
|
1
|
+
require "set"
|
2
|
+
require "solve/errors"
|
3
|
+
require_relative "solver/serializer"
|
4
4
|
|
5
5
|
module Solve
|
6
6
|
class GecodeSolver
|
@@ -16,7 +16,7 @@ module Solve
|
|
16
16
|
|
17
17
|
# Attemp to load the dep_selector gem which this solver engine requires.
|
18
18
|
def activate
|
19
|
-
require
|
19
|
+
require "dep_selector"
|
20
20
|
rescue LoadError => e
|
21
21
|
raise Errors::EngineNotAvailable, "dep_selector is not installed, GecodeSolver cannot be used (#{e})"
|
22
22
|
end
|
@@ -84,126 +84,126 @@ module Solve
|
|
84
84
|
private
|
85
85
|
|
86
86
|
# DepSelector::DependencyGraph object representing the problem.
|
87
|
-
|
87
|
+
attr_reader :ds_graph
|
88
88
|
|
89
89
|
# Timeout in milliseconds. Hardcoded to 1s for now.
|
90
|
-
|
90
|
+
attr_reader :timeout_ms
|
91
91
|
|
92
92
|
# Runs the solver with the set of demands given. If any DepSelector
|
93
93
|
# exceptions are raised, they are rescued and re-raised
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
94
|
+
def solve_demands(demands_as_constraints)
|
95
|
+
selector = DepSelector::Selector.new(ds_graph, (timeout_ms / 1000.0))
|
96
|
+
selector.find_solution(demands_as_constraints, all_artifacts)
|
97
|
+
rescue DepSelector::Exceptions::InvalidSolutionConstraints => e
|
98
|
+
report_invalid_constraints_error(e)
|
99
|
+
rescue DepSelector::Exceptions::NoSolutionExists => e
|
100
|
+
report_no_solution_error(e)
|
101
|
+
rescue DepSelector::Exceptions::TimeBoundExceeded
|
102
|
+
# DepSelector timed out trying to find the solution. There may or may
|
103
|
+
# not be a solution.
|
104
|
+
raise Solve::Errors::NoSolutionError.new(
|
105
|
+
"The dependency constraints could not be solved in the time allotted.")
|
106
|
+
rescue DepSelector::Exceptions::TimeBoundExceededNoSolution
|
107
|
+
# DepSelector determined there wasn't a solution to the problem, then
|
108
|
+
# timed out trying to determine which constraints cause the conflict.
|
109
|
+
raise Solve::Errors::NoSolutionCauseUnknown.new(
|
110
|
+
"There is a dependency conflict, but the solver could not determine the precise cause in the time allotted.")
|
111
|
+
end
|
112
112
|
|
113
113
|
# Maps demands to corresponding DepSelector::SolutionConstraint objects.
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
114
|
+
def demands_as_constraints
|
115
|
+
@demands_as_constraints ||= demands_array.map do |demands_item|
|
116
|
+
item_name, constraint_with_operator = demands_item
|
117
|
+
version_constraint = Semverse::Constraint.new(constraint_with_operator)
|
118
|
+
DepSelector::SolutionConstraint.new(ds_graph.package(item_name), version_constraint)
|
120
119
|
end
|
120
|
+
end
|
121
121
|
|
122
122
|
# Maps all artifacts in the graph to DepSelector::Package objects. If not
|
123
123
|
# already done, artifacts are added to the ds_graph as a necessary side effect.
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
def all_artifacts
|
125
|
+
return @all_artifacts if @all_artifacts
|
126
|
+
populate_ds_graph!
|
127
|
+
@all_artifacts
|
128
|
+
end
|
129
129
|
|
130
130
|
# Converts artifacts to DepSelector::Package objects and adds them to the
|
131
131
|
# DepSelector graph. This should only be called once; use #all_artifacts
|
132
132
|
# to safely get the set of all artifacts.
|
133
|
-
|
134
|
-
|
133
|
+
def populate_ds_graph!
|
134
|
+
@all_artifacts = Set.new
|
135
135
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
136
|
+
graph.artifacts.each do |artifact|
|
137
|
+
add_artifact_to_ds_graph(artifact)
|
138
|
+
@all_artifacts << ds_graph.package(artifact.name)
|
140
139
|
end
|
140
|
+
end
|
141
141
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
package_version
|
142
|
+
def add_artifact_to_ds_graph(artifact)
|
143
|
+
package_version = ds_graph.package(artifact.name).add_version(artifact.version)
|
144
|
+
artifact.dependencies.each do |dependency|
|
145
|
+
dependency = DepSelector::Dependency.new(ds_graph.package(dependency.name), dependency.constraint)
|
146
|
+
package_version.dependencies << dependency
|
149
147
|
end
|
148
|
+
package_version
|
149
|
+
end
|
150
150
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
constrained_to_no_versions = e.constrained_to_no_versions.inject([]) do |list, constraint|
|
157
|
-
list << [constraint.package.name, constraint.constraint.to_s]
|
158
|
-
end
|
151
|
+
def report_invalid_constraints_error(e)
|
152
|
+
non_existent_cookbooks = e.non_existent_packages.inject([]) do |list, constraint|
|
153
|
+
list << constraint.package.name
|
154
|
+
end
|
159
155
|
|
160
|
-
|
161
|
-
|
162
|
-
missing_artifacts: non_existent_cookbooks,
|
163
|
-
constraints_excluding_all_artifacts: constrained_to_no_versions
|
164
|
-
)
|
156
|
+
constrained_to_no_versions = e.constrained_to_no_versions.inject([]) do |list, constraint|
|
157
|
+
list << [constraint.package.name, constraint.constraint.to_s]
|
165
158
|
end
|
166
159
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
160
|
+
raise Solve::Errors::NoSolutionError.new(
|
161
|
+
"Required artifacts do not exist at the desired version",
|
162
|
+
missing_artifacts: non_existent_cookbooks,
|
163
|
+
constraints_excluding_all_artifacts: constrained_to_no_versions
|
164
|
+
)
|
165
|
+
end
|
171
166
|
|
172
|
-
|
173
|
-
|
174
|
-
|
167
|
+
def report_no_solution_error(e)
|
168
|
+
most_constrained_cookbooks = e.disabled_most_constrained_packages.inject([]) do |list, package|
|
169
|
+
list << "#{package.name} = #{package.versions.first}"
|
170
|
+
end
|
175
171
|
|
176
|
-
|
177
|
-
|
178
|
-
unsatisfiable_demand: e.unsatisfiable_solution_constraint.to_s,
|
179
|
-
missing_artifacts: non_existent_cookbooks,
|
180
|
-
artifacts_with_no_satisfactory_version: most_constrained_cookbooks
|
181
|
-
)
|
172
|
+
non_existent_cookbooks = e.disabled_non_existent_packages.inject([]) do |list, package|
|
173
|
+
list << package.name
|
182
174
|
end
|
183
175
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
176
|
+
raise Solve::Errors::NoSolutionError.new(
|
177
|
+
e.message,
|
178
|
+
unsatisfiable_demand: e.unsatisfiable_solution_constraint.to_s,
|
179
|
+
missing_artifacts: non_existent_cookbooks,
|
180
|
+
artifacts_with_no_satisfactory_version: most_constrained_cookbooks
|
181
|
+
)
|
182
|
+
end
|
189
183
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
fetch(node).each(&block)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
begin
|
199
|
-
sorted_names = nodes.tsort
|
200
|
-
rescue TSort::Cyclic => e
|
201
|
-
raise Solve::Errors::UnsortableSolutionError.new(e, unsorted_solution)
|
202
|
-
end
|
184
|
+
def build_sorted_solution(unsorted_solution)
|
185
|
+
nodes = Hash.new
|
186
|
+
unsorted_solution.each do |name, version|
|
187
|
+
nodes[name] = @graph.artifact(name, version).dependencies.map(&:name)
|
188
|
+
end
|
203
189
|
|
204
|
-
|
205
|
-
|
190
|
+
# Modified from http://ruby-doc.org/stdlib-1.9.3/libdoc/tsort/rdoc/TSort.html
|
191
|
+
class << nodes
|
192
|
+
include TSort
|
193
|
+
alias tsort_each_node each_key
|
194
|
+
def tsort_each_child(node, &block)
|
195
|
+
fetch(node).each(&block)
|
206
196
|
end
|
207
197
|
end
|
198
|
+
begin
|
199
|
+
sorted_names = nodes.tsort
|
200
|
+
rescue TSort::Cyclic => e
|
201
|
+
raise Solve::Errors::UnsortableSolutionError.new(e, unsorted_solution)
|
202
|
+
end
|
203
|
+
|
204
|
+
sorted_names.map do |artifact|
|
205
|
+
[artifact, unsorted_solution[artifact]]
|
206
|
+
end
|
207
|
+
end
|
208
208
|
end
|
209
209
|
end
|