solve 1.2.1 → 2.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/.gitignore +1 -0
- data/.travis.yml +11 -6
- data/Gemfile +8 -8
- data/NoGecode.gemfile +4 -0
- data/README.md +16 -0
- data/Rakefile +1 -0
- data/Thorfile +5 -0
- data/lib/solve.rb +43 -2
- data/lib/solve/demand.rb +2 -2
- data/lib/solve/errors.rb +6 -0
- data/lib/solve/{solver.rb → gecode_solver.rb} +12 -4
- data/lib/solve/ruby_solver.rb +207 -0
- data/lib/solve/solver/serializer.rb +37 -15
- data/lib/solve/version.rb +1 -1
- data/solve.gemspec +7 -1
- data/spec/acceptance/benchmark.rb +17 -3
- data/spec/acceptance/ruby_solver_solutions_spec.rb +307 -0
- data/spec/acceptance/solutions_spec.rb +6 -1
- data/spec/unit/solve/{solver_spec.rb → gecode_solver_spec.rb} +34 -4
- data/spec/unit/solve/ruby_solver_spec.rb +166 -0
- data/spec/unit/solve/solver/serializer_spec.rb +22 -14
- data/spec/unit/solve_spec.rb +2 -2
- metadata +71 -8
@@ -1,12 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
require 'solve/gecode_solver'
|
4
|
+
|
5
|
+
describe Solve::GecodeSolver, :gecode do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
described_class.activate
|
9
|
+
end
|
10
|
+
|
4
11
|
describe "ClassMethods" do
|
5
12
|
describe "::timeout" do
|
6
13
|
subject { described_class.timeout }
|
7
14
|
|
8
|
-
it "returns
|
9
|
-
expect(subject).to eql(
|
15
|
+
it "returns 30,000 by default" do
|
16
|
+
expect(subject).to eql(30_000)
|
10
17
|
end
|
11
18
|
|
12
19
|
context "when the SOLVE_TIMEOUT env variable is set" do
|
@@ -17,6 +24,28 @@ describe Solve::Solver do
|
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
27
|
+
|
28
|
+
describe "::activate" do
|
29
|
+
|
30
|
+
context "when dep_selector is not installed" do
|
31
|
+
|
32
|
+
it "raises EngineNotAvailable" do
|
33
|
+
exception = LoadError.new("cannot load such file -- dep_selector")
|
34
|
+
allow(described_class).to receive(:require).with("dep_selector").and_raise(exception)
|
35
|
+
expect { described_class.activate }.to raise_error(Solve::Errors::EngineNotAvailable)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when dep_selector is installed" do
|
41
|
+
|
42
|
+
it "requires dep_selector" do
|
43
|
+
expect(described_class).to receive(:require).with("dep_selector").and_call_original
|
44
|
+
described_class.activate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
20
49
|
end
|
21
50
|
|
22
51
|
let(:graph) { double(Solve::Graph) }
|
@@ -162,7 +191,8 @@ describe Solve::Solver do
|
|
162
191
|
end
|
163
192
|
|
164
193
|
it "implements the required interface" do
|
165
|
-
|
194
|
+
problem = Solve::Problem.from_solver(solver)
|
195
|
+
json_string = serializer.serialize(problem)
|
166
196
|
problem_data = JSON.parse(json_string)
|
167
197
|
expected_demands = [
|
168
198
|
{"name" => "mysql", "constraint" => ">= 0.0.0"},
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Solve::RubySolver do
|
4
|
+
describe "ClassMethods" do
|
5
|
+
describe "::timeout" do
|
6
|
+
subject { described_class.timeout }
|
7
|
+
|
8
|
+
it "returns 30,000 by default" do
|
9
|
+
expect(subject).to eql(30_000)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when the SOLVE_TIMEOUT env variable is set" do
|
13
|
+
before { ENV.stub(:[]).with("SOLVE_TIMEOUT") { "30" } }
|
14
|
+
|
15
|
+
it "returns the value multiplied by a thousand" do
|
16
|
+
expect(subject).to eql(30_000)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "::activate" do
|
22
|
+
|
23
|
+
it "is a no-op" do
|
24
|
+
described_class.activate
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:graph) { double(Solve::Graph) }
|
31
|
+
let(:demands) { [["mysql"], ["nginx"]] }
|
32
|
+
subject(:solver) { described_class.new(graph, demands, dependency_source: "Berksfile") }
|
33
|
+
|
34
|
+
it "has a list of demands as ruby literals" do
|
35
|
+
solver.demands_array.should == demands
|
36
|
+
end
|
37
|
+
|
38
|
+
it "has a list of demands as model objects" do
|
39
|
+
expected = [
|
40
|
+
Solve::Demand.new(solver, "mysql"),
|
41
|
+
Solve::Demand.new(solver, "nginx")
|
42
|
+
]
|
43
|
+
solver.demands.should == expected
|
44
|
+
end
|
45
|
+
|
46
|
+
it "has a graph" do
|
47
|
+
solver.graph.should == graph
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when the constraints are solvable" do
|
51
|
+
let(:graph) do
|
52
|
+
graph = Solve::Graph.new
|
53
|
+
graph.artifact("A", "1.0.0")
|
54
|
+
graph.artifact("B", "1.0.0").depends("A")
|
55
|
+
graph
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:demands) { [["A"], ["B"]] }
|
59
|
+
|
60
|
+
it "gives the solution as a Hash" do
|
61
|
+
solver.resolve.should == {"A"=>"1.0.0", "B"=>"1.0.0"}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "gives the solution in sorted form" do
|
65
|
+
solver.resolve(sorted: true).should == [["A", "1.0.0"], ["B", "1.0.0"]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "when the constraints are not solvable" do
|
70
|
+
let(:error) do
|
71
|
+
begin
|
72
|
+
solver.resolve
|
73
|
+
rescue => e
|
74
|
+
e
|
75
|
+
else
|
76
|
+
raise "Expected resolve to cause an error"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "and molinillo identifies missing artifacts" do
|
81
|
+
let(:graph) do
|
82
|
+
graph = Solve::Graph.new
|
83
|
+
graph.artifact("A", "1.0.0")
|
84
|
+
graph
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:demands) { [ ["Z"] ] }
|
88
|
+
|
89
|
+
it "raises an error detailing the missing artifacts" do
|
90
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
91
|
+
expected_error = <<-ERROR_MESSAGE
|
92
|
+
Unable to satisfy the following requirements:
|
93
|
+
|
94
|
+
- `Z (>= 0.0.0)` required by `Berksfile`
|
95
|
+
ERROR_MESSAGE
|
96
|
+
expect(error.to_s).to eq(expected_error)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "and molinillo identifies constraints that exclude all known versions" do
|
101
|
+
let(:graph) do
|
102
|
+
graph = Solve::Graph.new
|
103
|
+
graph.artifact("A", "1.0.0")
|
104
|
+
graph
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:demands) { [ ["A", "> 1.0.0"] ] }
|
108
|
+
|
109
|
+
it "raises an error detailing the missing artifacts" do
|
110
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
111
|
+
expected_error = <<-ERROR_MESSAGE
|
112
|
+
Unable to satisfy the following requirements:
|
113
|
+
|
114
|
+
- `A (> 1.0.0)` required by `Berksfile`
|
115
|
+
ERROR_MESSAGE
|
116
|
+
expect(error.to_s).to eq(expected_error)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "and molinillo identifies dependency conflicts" do
|
121
|
+
let(:graph) do
|
122
|
+
graph = Solve::Graph.new
|
123
|
+
graph.artifact("A", "1.0.0").depends("B").depends("C")
|
124
|
+
graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
|
125
|
+
graph.artifact("C", "1.0.0").depends("D", "= 2.0.0")
|
126
|
+
graph.artifact("D", "1.0.0")
|
127
|
+
graph.artifact("D", "2.0.0")
|
128
|
+
graph
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:demands) { [ [ "A" ] ] }
|
132
|
+
|
133
|
+
it "raises an error detailing the missing artifacts" do
|
134
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
135
|
+
expected_error = <<-ERROR_MESSAGE
|
136
|
+
Unable to satisfy the following requirements:
|
137
|
+
|
138
|
+
- `D (= 1.0.0)` required by `B-1.0.0`
|
139
|
+
- `D (= 2.0.0)` required by `C-1.0.0`
|
140
|
+
ERROR_MESSAGE
|
141
|
+
expect(error.to_s).to eq(expected_error)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "supporting Serializer interface" do
|
147
|
+
let(:serializer) { Solve::Solver::Serializer.new }
|
148
|
+
|
149
|
+
before do
|
150
|
+
graph.stub(:artifacts).and_return([])
|
151
|
+
end
|
152
|
+
|
153
|
+
it "implements the required interface" do
|
154
|
+
problem = Solve::Problem.from_solver(solver)
|
155
|
+
json_string = serializer.serialize(problem)
|
156
|
+
problem_data = JSON.parse(json_string)
|
157
|
+
expected_demands = [
|
158
|
+
{"name" => "mysql", "constraint" => ">= 0.0.0"},
|
159
|
+
{"name" => "nginx", "constraint" => ">= 0.0.0"}
|
160
|
+
]
|
161
|
+
|
162
|
+
problem_data["demands"].should =~ expected_demands
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
@@ -1,25 +1,33 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'solve/ruby_solver'
|
2
3
|
|
3
4
|
describe Solve::Solver::Serializer do
|
4
|
-
it "deserializes a serialized solver to an equivalent solver" do
|
5
|
-
graph = Solve::Graph.new
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
let(:graph) do
|
7
|
+
Solve::Graph.new.tap do |g|
|
8
|
+
g.artifact("A", "1.0.0").depends("B", "1.0.0")
|
9
|
+
g.artifact("B", "1.0.0").depends("C", "1.0.0")
|
10
|
+
g.artifact("C", "1.0.0")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:demands) { [["A", "1.0.0"]] }
|
10
15
|
|
11
|
-
|
16
|
+
let(:serializer) { Solve::Solver::Serializer.new }
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
serialized = serializer.serialize(
|
18
|
+
it "deserializes a serialized problem to an equivalent problem" do
|
19
|
+
problem = Solve::Problem.new(graph, demands)
|
20
|
+
serialized = serializer.serialize(problem)
|
16
21
|
deserialized = serializer.deserialize(serialized)
|
17
22
|
|
18
|
-
|
19
|
-
|
23
|
+
problem.graph.should eql(deserialized.graph)
|
24
|
+
problem.demands.should eql(deserialized.demands)
|
25
|
+
end
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
27
|
+
it "creates a problem from a solver" do
|
28
|
+
solver = Solve::RubySolver.new(graph, demands)
|
29
|
+
problem = Solve::Problem.from_solver(solver)
|
30
|
+
expect(problem.demands).to eq([["A", "= 1.0.0"]])
|
31
|
+
expect(problem.graph).to eq(graph)
|
24
32
|
end
|
25
33
|
end
|
data/spec/unit/solve_spec.rb
CHANGED
@@ -6,13 +6,13 @@ describe Solve do
|
|
6
6
|
|
7
7
|
describe "#it" do
|
8
8
|
it "returns nil if a solution does not exist" do
|
9
|
-
|
9
|
+
skip
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
describe "#it!" do
|
14
14
|
it "raises NoSolutionError if a solution does not exist" do
|
15
|
-
|
15
|
+
skip
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solve
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Winsor
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: semverse
|
@@ -27,19 +27,75 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '1.1'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
30
|
+
name: molinillo
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: 0.2.3
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 0.2.3
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: thor
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.16.0
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.16.0
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rake
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.9.2.2
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.9.2.2
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: spork
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: rspec
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '3.0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '3.0'
|
43
99
|
description: A Ruby version constraint solver
|
44
100
|
email:
|
45
101
|
- jamie@vialstudios.com
|
@@ -54,7 +110,9 @@ files:
|
|
54
110
|
- Gemfile
|
55
111
|
- Guardfile
|
56
112
|
- LICENSE
|
113
|
+
- NoGecode.gemfile
|
57
114
|
- README.md
|
115
|
+
- Rakefile
|
58
116
|
- Thorfile
|
59
117
|
- lib/solve.rb
|
60
118
|
- lib/solve/artifact.rb
|
@@ -62,22 +120,25 @@ files:
|
|
62
120
|
- lib/solve/demand.rb
|
63
121
|
- lib/solve/dependency.rb
|
64
122
|
- lib/solve/errors.rb
|
123
|
+
- lib/solve/gecode_solver.rb
|
65
124
|
- lib/solve/graph.rb
|
66
|
-
- lib/solve/
|
125
|
+
- lib/solve/ruby_solver.rb
|
67
126
|
- lib/solve/solver/serializer.rb
|
68
127
|
- lib/solve/version.rb
|
69
128
|
- solve.gemspec
|
70
129
|
- spec/acceptance/benchmark.rb
|
71
130
|
- spec/acceptance/large_graph_no_solution.rb
|
72
131
|
- spec/acceptance/opscode_ci_graph.rb
|
132
|
+
- spec/acceptance/ruby_solver_solutions_spec.rb
|
73
133
|
- spec/acceptance/solutions_spec.rb
|
74
134
|
- spec/spec_helper.rb
|
75
135
|
- spec/unit/solve/artifact_spec.rb
|
76
136
|
- spec/unit/solve/demand_spec.rb
|
77
137
|
- spec/unit/solve/dependency_spec.rb
|
138
|
+
- spec/unit/solve/gecode_solver_spec.rb
|
78
139
|
- spec/unit/solve/graph_spec.rb
|
140
|
+
- spec/unit/solve/ruby_solver_spec.rb
|
79
141
|
- spec/unit/solve/solver/serializer_spec.rb
|
80
|
-
- spec/unit/solve/solver_spec.rb
|
81
142
|
- spec/unit/solve_spec.rb
|
82
143
|
homepage: https://github.com/berkshelf/solve
|
83
144
|
licenses:
|
@@ -107,13 +168,15 @@ test_files:
|
|
107
168
|
- spec/acceptance/benchmark.rb
|
108
169
|
- spec/acceptance/large_graph_no_solution.rb
|
109
170
|
- spec/acceptance/opscode_ci_graph.rb
|
171
|
+
- spec/acceptance/ruby_solver_solutions_spec.rb
|
110
172
|
- spec/acceptance/solutions_spec.rb
|
111
173
|
- spec/spec_helper.rb
|
112
174
|
- spec/unit/solve/artifact_spec.rb
|
113
175
|
- spec/unit/solve/demand_spec.rb
|
114
176
|
- spec/unit/solve/dependency_spec.rb
|
177
|
+
- spec/unit/solve/gecode_solver_spec.rb
|
115
178
|
- spec/unit/solve/graph_spec.rb
|
179
|
+
- spec/unit/solve/ruby_solver_spec.rb
|
116
180
|
- spec/unit/solve/solver/serializer_spec.rb
|
117
|
-
- spec/unit/solve/solver_spec.rb
|
118
181
|
- spec/unit/solve_spec.rb
|
119
182
|
has_rdoc:
|