solve 4.0.0 → 4.0.1
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 +5 -5
- data/lib/solve/constraint.rb +1 -1
- data/lib/solve/gecode_solver.rb +1 -1
- data/lib/solve/ruby_solver.rb +1 -1
- data/lib/solve/version.rb +1 -1
- metadata +5 -42
- data/.gitignore +0 -20
- data/.travis.yml +0 -25
- data/Gemfile +0 -36
- data/Guardfile +0 -17
- data/NoGecode.gemfile +0 -4
- data/README.md +0 -85
- data/Rakefile +0 -11
- data/Thorfile +0 -36
- data/solve.gemspec +0 -26
- data/spec/acceptance/benchmark.rb +0 -59
- data/spec/acceptance/large_graph_no_solution.rb +0 -18730
- data/spec/acceptance/opscode_ci_graph.rb +0 -18600
- data/spec/acceptance/ruby_solver_solutions_spec.rb +0 -306
- data/spec/acceptance/solutions_spec.rb +0 -316
- data/spec/spec_helper.rb +0 -32
- data/spec/unit/solve/artifact_spec.rb +0 -137
- data/spec/unit/solve/demand_spec.rb +0 -53
- data/spec/unit/solve/dependency_spec.rb +0 -25
- data/spec/unit/solve/gecode_solver_spec.rb +0 -205
- data/spec/unit/solve/graph_spec.rb +0 -130
- data/spec/unit/solve/ruby_solver_spec.rb +0 -165
- data/spec/unit/solve/solver/serializer_spec.rb +0 -33
- data/spec/unit/solve_spec.rb +0 -19
data/spec/spec_helper.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "bundler"
|
3
|
-
require "spork"
|
4
|
-
|
5
|
-
Spork.prefork do
|
6
|
-
require "rspec"
|
7
|
-
|
8
|
-
APP_ROOT = File.expand_path("../../", __FILE__)
|
9
|
-
|
10
|
-
Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each { |f| require f }
|
11
|
-
|
12
|
-
RSpec.configure do |config|
|
13
|
-
config.mock_with :rspec
|
14
|
-
config.filter_run focus: true
|
15
|
-
config.run_all_when_everything_filtered = true
|
16
|
-
|
17
|
-
# Run specs in a random order
|
18
|
-
config.order = :random
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
Spork.each_run do
|
23
|
-
require "solve"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Useful for debugging the solver - simply add `ui: TestUI` to a resolver call
|
27
|
-
class TestUI
|
28
|
-
def self.say(message = "")
|
29
|
-
$stdout.print(message + "\n")
|
30
|
-
$stdout.flush
|
31
|
-
end
|
32
|
-
end
|
@@ -1,137 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Solve::Artifact do
|
4
|
-
let(:graph) do
|
5
|
-
package = double("package")
|
6
|
-
package_version = double("package_version")
|
7
|
-
package_version.stub(:dependencies).and_return([])
|
8
|
-
package.stub(:add_version).and_return(package_version)
|
9
|
-
double("graph", dep_graph: double("dep_graph", package: package))
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:name) { "league" }
|
13
|
-
let(:version) { "1.0.0" }
|
14
|
-
subject { Solve::Artifact.new(graph, name, version) }
|
15
|
-
|
16
|
-
describe "equality" do
|
17
|
-
context "given an artifact with the same name and version" do
|
18
|
-
let(:one) { Solve::Artifact.new(graph, "riot", "1.0.0") }
|
19
|
-
let(:two) { Solve::Artifact.new(graph, "riot", "1.0.0") }
|
20
|
-
|
21
|
-
it "is equal" do
|
22
|
-
expect(one).to eq(two)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "given an artifact with the same name but different version" do
|
27
|
-
let(:one) { Solve::Artifact.new(graph, "riot", "1.0.0") }
|
28
|
-
let(:two) { Solve::Artifact.new(graph, "riot", "2.0.0") }
|
29
|
-
|
30
|
-
it "is not equal" do
|
31
|
-
expect(one).to_not eq(two)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "given an artifact with the same version but different name" do
|
36
|
-
let(:one) { Solve::Artifact.new(graph, "riot", "1.0.0") }
|
37
|
-
let(:two) { Solve::Artifact.new(graph, "league", "1.0.0") }
|
38
|
-
|
39
|
-
it "is not equal" do
|
40
|
-
expect(one).to_not eq(two)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "sorting" do
|
46
|
-
let(:one) { Solve::Artifact.new(graph, "riot", "1.0.0") }
|
47
|
-
let(:two) { Solve::Artifact.new(graph, "riot", "2.0.0") }
|
48
|
-
let(:three) { Solve::Artifact.new(graph, "riot", "3.0.0") }
|
49
|
-
|
50
|
-
let(:artifacts) do
|
51
|
-
[
|
52
|
-
one,
|
53
|
-
two,
|
54
|
-
three,
|
55
|
-
].shuffle
|
56
|
-
end
|
57
|
-
|
58
|
-
it "orders artifacts by their version number" do
|
59
|
-
sorted = artifacts.sort
|
60
|
-
|
61
|
-
expect(sorted[0]).to eq(one)
|
62
|
-
expect(sorted[1]).to eq(two)
|
63
|
-
expect(sorted[2]).to eq(three)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "#dependency?" do
|
68
|
-
before { subject.depends("nginx", "1.0.0") }
|
69
|
-
|
70
|
-
it "returns false when the dependency does not exist" do
|
71
|
-
expect(subject).to have_dependency("nginx", "1.0.0")
|
72
|
-
end
|
73
|
-
|
74
|
-
it "returns true when the dependendency exists" do
|
75
|
-
expect(subject).to_not have_dependency("apache2", "2.0.0")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "#dependency" do
|
80
|
-
before { subject.depends("nginx", "~> 1.2.3") }
|
81
|
-
|
82
|
-
it "returns an instance of Solve::Dependency matching the given name and constraint" do
|
83
|
-
dependency = subject.dependency("nginx", "~> 1.2.3")
|
84
|
-
|
85
|
-
expect(dependency).to be_a(Solve::Dependency)
|
86
|
-
expect(dependency.name).to eq("nginx")
|
87
|
-
expect(dependency.constraint.to_s).to eq("~> 1.2.3")
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "#dependencies" do
|
92
|
-
it "returns an array" do
|
93
|
-
expect(subject.dependencies).to be_a(Array)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "returns an empty array if no dependencies have been accessed" do
|
97
|
-
expect(subject.dependencies).to be_empty
|
98
|
-
end
|
99
|
-
|
100
|
-
it "returns all dependencies" do
|
101
|
-
subject.depends("nginx", "1.0.0")
|
102
|
-
subject.depends("nginx", "~> 2.0.0")
|
103
|
-
|
104
|
-
expect(subject.dependencies.size).to eq(2)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "#depends" do
|
109
|
-
context "given a name and constraint argument" do
|
110
|
-
let(:name) { "nginx" }
|
111
|
-
let(:constraint) { "~> 1.0.0" }
|
112
|
-
|
113
|
-
context "given the dependency of the given name and constraint does not exist" do
|
114
|
-
it "returns a Solve::Artifact" do
|
115
|
-
expect(subject.depends(name, constraint)).to be_a(Solve::Artifact)
|
116
|
-
end
|
117
|
-
|
118
|
-
it "adds a dependency with the given name and constraint to the list of dependencies" do
|
119
|
-
subject.depends(name, constraint)
|
120
|
-
|
121
|
-
expect(subject.dependencies.size).to eq(1)
|
122
|
-
expect(subject.dependencies.first.name).to eq(name)
|
123
|
-
expect(subject.dependencies.first.constraint.to_s).to eq(constraint)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
context "given only a name argument" do
|
129
|
-
it "adds a dependency with a all constraint (>= 0.0.0)" do
|
130
|
-
subject.depends("nginx")
|
131
|
-
|
132
|
-
expect(subject.dependencies.size).to eq(1)
|
133
|
-
expect(subject.dependencies.first.constraint.to_s).to eq(">= 0.0.0")
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Solve::Demand do
|
4
|
-
let(:solver) { double("solver") }
|
5
|
-
let(:name) { "league" }
|
6
|
-
|
7
|
-
describe "#initialize" do
|
8
|
-
it "accepts a string for the constraint parameter" do
|
9
|
-
demand = Solve::Demand.new(solver, name, "= 0.0.1")
|
10
|
-
expect(demand.constraint.to_s).to eq("= 0.0.1")
|
11
|
-
end
|
12
|
-
|
13
|
-
it "accepts a Semverse::Constraint for the constraint parameter" do
|
14
|
-
constraint = Semverse::Constraint.new("= 0.0.1")
|
15
|
-
demand = Solve::Demand.new(solver, name, constraint)
|
16
|
-
|
17
|
-
expect(demand.constraint).to eq(constraint)
|
18
|
-
end
|
19
|
-
|
20
|
-
context "when no value for 'constraint' is given" do
|
21
|
-
it "uses a default of >= 0.0.0" do
|
22
|
-
demand = Solve::Demand.new(solver, name)
|
23
|
-
|
24
|
-
expect(demand.constraint.operator).to eq(">=")
|
25
|
-
expect(demand.constraint.version.to_s).to eq("0.0.0")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
let(:constraint) { "~> 1.0.0" }
|
31
|
-
subject { Solve::Demand.new(solver, name, constraint) }
|
32
|
-
|
33
|
-
describe "equality" do
|
34
|
-
it "returns true when other is a Solve::Demand with the same name and constriant" do
|
35
|
-
other = Solve::Demand.new(solver, name, constraint)
|
36
|
-
expect(subject).to eq(other)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "returns false when other isn't a Solve::Demand" do
|
40
|
-
expect(subject).to_not eq("chicken")
|
41
|
-
end
|
42
|
-
|
43
|
-
it "returns false when other is a Solve::Demand with the same name but a different constraint" do
|
44
|
-
other = Solve::Demand.new(solver, name, "< 3.4.5")
|
45
|
-
expect(subject).to_not eq(other)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "returns false when other is a Solve::Demand with the same constraint but a different name" do
|
49
|
-
other = Solve::Demand.new(solver, "chicken", constraint)
|
50
|
-
expect(subject).to_not eq(other)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Solve::Dependency do
|
4
|
-
describe "#initialize" do
|
5
|
-
it "uses a default of >= 0.0.0" do
|
6
|
-
dep = Solve::Dependency.new(double("artifact"), "ntp")
|
7
|
-
|
8
|
-
expect(dep.constraint.operator).to eq(">=")
|
9
|
-
expect(dep.constraint.version.to_s).to eq("0.0.0")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
let(:artifact) { double("artifact") }
|
14
|
-
let(:name) { "nginx" }
|
15
|
-
let(:constraint) { "~> 0.0.1" }
|
16
|
-
|
17
|
-
subject { Solve::Dependency.new(artifact, name, constraint) }
|
18
|
-
|
19
|
-
describe "#==" do
|
20
|
-
it "returns true if the other object is an instance of Solve::Dependency with the same constraint and artifact" do
|
21
|
-
other = Solve::Dependency.new(artifact, name, constraint)
|
22
|
-
expect(subject).to eq(other)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,205 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
require "solve/gecode_solver"
|
4
|
-
|
5
|
-
describe Solve::GecodeSolver, :gecode do
|
6
|
-
|
7
|
-
before(:all) do
|
8
|
-
described_class.activate
|
9
|
-
end
|
10
|
-
|
11
|
-
describe "ClassMethods" do
|
12
|
-
describe "::timeout" do
|
13
|
-
subject { described_class.timeout }
|
14
|
-
|
15
|
-
it "returns 30,000 by default" do
|
16
|
-
expect(subject).to eql(30_000)
|
17
|
-
end
|
18
|
-
|
19
|
-
context "when the SOLVE_TIMEOUT env variable is set" do
|
20
|
-
before { ENV.stub(:[]).with("SOLVE_TIMEOUT") { "30" } }
|
21
|
-
|
22
|
-
it "returns the value multiplied by a thousand" do
|
23
|
-
expect(subject).to eql(30_000)
|
24
|
-
end
|
25
|
-
end
|
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
|
49
|
-
end
|
50
|
-
|
51
|
-
let(:graph) { double(Solve::Graph) }
|
52
|
-
let(:demands) { [["mysql"], ["nginx"]] }
|
53
|
-
subject(:solver) { described_class.new(graph, demands) }
|
54
|
-
|
55
|
-
it "has a list of demands as ruby literals" do
|
56
|
-
solver.demands_array.should == demands
|
57
|
-
end
|
58
|
-
|
59
|
-
it "has a list of demands as model objects" do
|
60
|
-
expected = [
|
61
|
-
Solve::Demand.new(solver, "mysql"),
|
62
|
-
Solve::Demand.new(solver, "nginx"),
|
63
|
-
]
|
64
|
-
solver.demands.should == expected
|
65
|
-
end
|
66
|
-
|
67
|
-
it "has a graph" do
|
68
|
-
solver.graph.should == graph
|
69
|
-
end
|
70
|
-
|
71
|
-
describe "when the constraints are solvable" do
|
72
|
-
let(:graph) do
|
73
|
-
graph = Solve::Graph.new
|
74
|
-
graph.artifact("A", "1.0.0")
|
75
|
-
graph.artifact("B", "1.0.0").depends("A")
|
76
|
-
graph
|
77
|
-
end
|
78
|
-
|
79
|
-
let(:demands) { [["A"], ["B"]] }
|
80
|
-
|
81
|
-
it "gives the solution as a Hash" do
|
82
|
-
solver.resolve.should == { "A" => "1.0.0", "B" => "1.0.0" }
|
83
|
-
end
|
84
|
-
|
85
|
-
it "gives the solution in sorted form" do
|
86
|
-
solver.resolve(sorted: true).should == [["A", "1.0.0"], ["B", "1.0.0"]]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "when the constraints are not solvable" do
|
91
|
-
let(:error) do
|
92
|
-
begin
|
93
|
-
solver.resolve
|
94
|
-
rescue => e
|
95
|
-
e
|
96
|
-
else
|
97
|
-
raise "Expected resolve to cause an error"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
context "and dep-selector identifies missing artifacts" do
|
102
|
-
let(:graph) do
|
103
|
-
graph = Solve::Graph.new
|
104
|
-
graph.artifact("A", "1.0.0")
|
105
|
-
graph
|
106
|
-
end
|
107
|
-
|
108
|
-
let(:demands) { [ ["Z"] ] }
|
109
|
-
|
110
|
-
it "raises an error detailing the missing artifacts" do
|
111
|
-
error.to_s.should include("Missing artifacts: Z")
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context "and dep-selector identifies constraints that exclude all known versions" do
|
116
|
-
let(:graph) do
|
117
|
-
graph = Solve::Graph.new
|
118
|
-
graph.artifact("A", "1.0.0")
|
119
|
-
graph
|
120
|
-
end
|
121
|
-
|
122
|
-
let(:demands) { [ ["A", "> 1.0.0"] ] }
|
123
|
-
|
124
|
-
it "raises an error detailing the missing artifacts" do
|
125
|
-
error.to_s.should include("Required artifacts do not exist at the desired version")
|
126
|
-
error.to_s.should include("Constraints that match no available version: (A > 1.0.0)")
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
context "and dep-selector identifies dependency conflicts" do
|
131
|
-
let(:graph) do
|
132
|
-
graph = Solve::Graph.new
|
133
|
-
graph.artifact("A", "1.0.0").depends("B").depends("C")
|
134
|
-
graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
|
135
|
-
graph.artifact("C", "1.0.0").depends("D", "= 2.0.0")
|
136
|
-
graph.artifact("D", "1.0.0")
|
137
|
-
graph.artifact("D", "2.0.0")
|
138
|
-
graph
|
139
|
-
end
|
140
|
-
|
141
|
-
let(:demands) { [ [ "A" ] ] }
|
142
|
-
|
143
|
-
it "raises an error detailing the missing artifacts" do
|
144
|
-
error.to_s.should include("Demand that cannot be met: (A >= 0.0.0)")
|
145
|
-
error.to_s.should include("Artifacts for which there are conflicting dependencies: D = 1.0.0 -> []")
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context "and dep-selector times out looking for a solution" do
|
150
|
-
let(:selector) { double(DepSelector::Selector) }
|
151
|
-
|
152
|
-
before do
|
153
|
-
graph.stub(:artifacts).and_return([])
|
154
|
-
DepSelector::Selector.stub(:new).and_return(selector)
|
155
|
-
selector.stub(:find_solution).and_raise(DepSelector::Exceptions::TimeBoundExceeded)
|
156
|
-
end
|
157
|
-
|
158
|
-
it "raises an error explaining no solution could be found" do
|
159
|
-
error.to_s.should include("The dependency constraints could not be solved in the time allotted.")
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
context "and dep-selector times out looking for dependency conflicts" do
|
164
|
-
let(:selector) { double(DepSelector::Selector) }
|
165
|
-
|
166
|
-
before do
|
167
|
-
graph.stub(:artifacts).and_return([])
|
168
|
-
DepSelector::Selector.stub(:new).and_return(selector)
|
169
|
-
selector.stub(:find_solution).and_raise(DepSelector::Exceptions::TimeBoundExceededNoSolution)
|
170
|
-
end
|
171
|
-
|
172
|
-
it "raises a NoSolutionCauseUnknown error to indicate that no debug info was generated" do
|
173
|
-
error.should be_a_kind_of(Solve::Errors::NoSolutionCauseUnknown)
|
174
|
-
end
|
175
|
-
|
176
|
-
it "raises an error explaining that no solution exists but the cause could not be determined" do
|
177
|
-
error.to_s.should include("There is a dependency conflict, but the solver could not determine the precise cause in the time allotted.")
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
describe "finding unsatisfiable demands" do
|
183
|
-
it "partitions demands into satisfiable and not satisfiable"
|
184
|
-
end
|
185
|
-
|
186
|
-
describe "supporting Serializer interface" do
|
187
|
-
let(:serializer) { Solve::Solver::Serializer.new }
|
188
|
-
|
189
|
-
before do
|
190
|
-
graph.stub(:artifacts).and_return([])
|
191
|
-
end
|
192
|
-
|
193
|
-
it "implements the required interface" do
|
194
|
-
problem = Solve::Problem.from_solver(solver)
|
195
|
-
json_string = serializer.serialize(problem)
|
196
|
-
problem_data = JSON.parse(json_string)
|
197
|
-
expected_demands = [
|
198
|
-
{ "name" => "mysql", "constraint" => ">= 0.0.0" },
|
199
|
-
{ "name" => "nginx", "constraint" => ">= 0.0.0" },
|
200
|
-
]
|
201
|
-
|
202
|
-
problem_data["demands"].should =~ expected_demands
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|