dep_selector_over_http 0.0.9
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.
- data/lib/dep_selector/densely_packed_set.rb +59 -0
- data/lib/dep_selector/dep_selector_version.rb +3 -0
- data/lib/dep_selector/dependency.rb +46 -0
- data/lib/dep_selector/dependency_graph.rb +71 -0
- data/lib/dep_selector/error_reporter/simple_tree_traverser.rb +183 -0
- data/lib/dep_selector/error_reporter.rb +28 -0
- data/lib/dep_selector/exceptions.rb +67 -0
- data/lib/dep_selector/package.rb +116 -0
- data/lib/dep_selector/package_version.rb +68 -0
- data/lib/dep_selector/selector.rb +46 -0
- data/lib/dep_selector/solution_constraint.rb +22 -0
- data/lib/dep_selector/version.rb +74 -0
- data/lib/dep_selector/version_constraint.rb +120 -0
- data/lib/dep_selector.rb +34 -0
- metadata +63 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/exceptions'
|
21
|
+
|
22
|
+
module DepSelector
|
23
|
+
class DenselyPackedSet
|
24
|
+
attr_reader :sorted_elements
|
25
|
+
|
26
|
+
def initialize(elements)
|
27
|
+
@sorted_elements = elements.sort
|
28
|
+
@element_to_index = {}
|
29
|
+
@sorted_elements.each_with_index{|elt, idx| @element_to_index[elt] = idx}
|
30
|
+
end
|
31
|
+
|
32
|
+
def range
|
33
|
+
Range.new(0, @sorted_elements.size-1)
|
34
|
+
end
|
35
|
+
|
36
|
+
def index(element)
|
37
|
+
unless @element_to_index.has_key?(element)
|
38
|
+
msg = "#{element} is not a valid version for this package"
|
39
|
+
raise Exceptions::InvalidVersion.new(msg)
|
40
|
+
end
|
41
|
+
@element_to_index[element]
|
42
|
+
end
|
43
|
+
|
44
|
+
def [](constraint)
|
45
|
+
# TODO [cw/mark,2010/11/22]: don't actually need an array here, re-write
|
46
|
+
range = []
|
47
|
+
started = false
|
48
|
+
done = false
|
49
|
+
sorted_elements.each_with_index do |element, idx|
|
50
|
+
if constraint.include?(element)
|
51
|
+
raise "Currently only handle continuous gap between #{range.last} and #{idx} for #{constraint.to_s} over #{@sorted_elements.join(', ')}" if (range.any? && range.last+1 != idx)
|
52
|
+
range << idx
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
range.empty? ? [] : Range.new(range.first, range.last)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/version_constraint'
|
21
|
+
|
22
|
+
module DepSelector
|
23
|
+
class Dependency
|
24
|
+
attr_reader :package, :constraint
|
25
|
+
|
26
|
+
def initialize(package, constraint=nil)
|
27
|
+
@package = package
|
28
|
+
@constraint = constraint || VersionConstraint.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s(incl_densely_packed_versions = false)
|
32
|
+
range = package.densely_packed_versions[constraint]
|
33
|
+
"(#{package.name} #{constraint.to_s}#{incl_densely_packed_versions ? " (#{range})" : ''})"
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(o)
|
37
|
+
o.respond_to?(:package) && package == o.package &&
|
38
|
+
o.respond_to?(:constraint) && constraint == o.constraint
|
39
|
+
end
|
40
|
+
|
41
|
+
def eql?(o)
|
42
|
+
self.class == o.class && self == o
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/package'
|
21
|
+
|
22
|
+
# DependencyGraphs contain Packages, which in turn contain
|
23
|
+
# PackageVersions. Packages are created at access-time through
|
24
|
+
# #package
|
25
|
+
module DepSelector
|
26
|
+
class DependencyGraph
|
27
|
+
|
28
|
+
DebugOptionFile = "/tmp/DepSelectorDebugOn"
|
29
|
+
|
30
|
+
attr_reader :packages
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@packages = {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def package(name)
|
37
|
+
packages.has_key?(name) ? packages[name] : (packages[name]=Package.new(self, name))
|
38
|
+
end
|
39
|
+
|
40
|
+
def each_package
|
41
|
+
packages.each do |name, pkg|
|
42
|
+
yield pkg
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def gecode_wrapper
|
47
|
+
raise "Must invoke generate_gecode_wrapper_constraints before attempting to access gecode_wrapper" unless @gecode_wrapper
|
48
|
+
@gecode_wrapper
|
49
|
+
end
|
50
|
+
|
51
|
+
# Note: only invoke this method once all Packages and
|
52
|
+
# PackageVersions have been added.
|
53
|
+
def generate_gecode_wrapper_constraints(packages_to_include_in_solve=nil)
|
54
|
+
raise "#generate_gecode_wrapper_constraints references c extensions. don't use."
|
55
|
+
end
|
56
|
+
|
57
|
+
def gecode_model_vars
|
58
|
+
packages.inject({}){|acc, elt| acc[elt.first] = elt.last.gecode_model_var ; acc }
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s(incl_densely_packed_versions = false)
|
62
|
+
packages.keys.sort.map{|name| packages[name].to_s(incl_densely_packed_versions)}.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
# TODO [cw,2010/11/23]: this is a simple but inefficient impl. Do
|
66
|
+
# it for realz.
|
67
|
+
def clone
|
68
|
+
Marshal.load(Marshal.dump(self))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/error_reporter'
|
21
|
+
|
22
|
+
# This error reporter simply maps the versions of packages explicitly
|
23
|
+
# included in the list of solution constraints to the restrictions
|
24
|
+
# placed on the most constrained package.
|
25
|
+
module DepSelector
|
26
|
+
class ErrorReporter
|
27
|
+
class SimpleTreeTraverser < ErrorReporter
|
28
|
+
|
29
|
+
def give_feedback(dep_graph, soln_constraints, unsatisfiable_constraint_idx, most_constrained_pkg)
|
30
|
+
unsatisfiable_soln_constraint = soln_constraints[unsatisfiable_constraint_idx]
|
31
|
+
feedback = "Unable to satisfy constraints on package #{most_constrained_pkg.name}"
|
32
|
+
feedback << ", which does not exist," unless most_constrained_pkg.valid?
|
33
|
+
feedback << " due to solution constraint #{unsatisfiable_soln_constraint}. "
|
34
|
+
|
35
|
+
all_paths = paths_from_soln_constraints_to_pkg_constraints(dep_graph, soln_constraints, most_constrained_pkg)
|
36
|
+
collapsed_paths = collapse_adjacent_paths(all_paths).map{|collapsed_path| "[#{print_path(collapsed_path).join(' -> ')}]"}
|
37
|
+
|
38
|
+
feedback << "Solution constraints that may result in a constraint on #{most_constrained_pkg.name}: #{collapsed_paths.join(', ')}"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def paths_from_soln_constraints_to_pkg_constraints(dep_graph, soln_constraints, most_constrained_pkg)
|
44
|
+
all_paths = []
|
45
|
+
soln_constraints.each do |soln_constraint|
|
46
|
+
paths_to_pkg(dep_graph,
|
47
|
+
soln_constraint.package,
|
48
|
+
soln_constraint.constraint,
|
49
|
+
most_constrained_pkg,
|
50
|
+
[],
|
51
|
+
all_paths)
|
52
|
+
end
|
53
|
+
|
54
|
+
all_paths
|
55
|
+
end
|
56
|
+
|
57
|
+
def paths_to_pkg(dep_graph, curr_pkg, version_constraint, target_pkg, curr_path, all_paths)
|
58
|
+
if curr_pkg == target_pkg
|
59
|
+
# register the culminating constraint
|
60
|
+
all_paths.push(Array.new(curr_path).push(SolutionConstraint.new(curr_pkg, version_constraint)))
|
61
|
+
return
|
62
|
+
end
|
63
|
+
|
64
|
+
# curr_pkg has no versions, it is invalid so don't recurse
|
65
|
+
if curr_pkg.versions.empty?
|
66
|
+
# TODO [cw, 2011/2/17]: find a way to track these invalid
|
67
|
+
# packages and return as potential conflict-causing
|
68
|
+
# constraints.
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
if curr_path.select{|elt| elt.package == curr_pkg}.any?
|
73
|
+
# TODO [cw, 2011/2/18]: this indicates a circular dependency
|
74
|
+
# in the dependency graph. This might be useful warning
|
75
|
+
# information to report to the user.
|
76
|
+
return
|
77
|
+
end
|
78
|
+
|
79
|
+
# determine all versions of curr_pkg that match
|
80
|
+
# version_constraint and recurse into them
|
81
|
+
curr_pkg[version_constraint].each do |curr_pkg_ver|
|
82
|
+
curr_path.push(curr_pkg_ver)
|
83
|
+
curr_pkg_ver.dependencies.each do |dep|
|
84
|
+
paths_to_pkg(dep_graph, dep.package, dep.constraint, target_pkg, curr_path, all_paths)
|
85
|
+
end
|
86
|
+
curr_path.pop
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# This is a simple collapsing function. For each adjacent path,
|
91
|
+
# if there is only one element different between the two paths
|
92
|
+
# and their packages are the same (meaning only the version
|
93
|
+
# binding is different), then the elements are considered
|
94
|
+
# collasable. The merged path has all the common elements and a
|
95
|
+
# set containing the two version bindings in place of the
|
96
|
+
# contentious path item.
|
97
|
+
def collapse_adjacent_paths(paths)
|
98
|
+
return paths if paths.length < 2
|
99
|
+
|
100
|
+
paths.inject([]) do |collapsed_paths, path|
|
101
|
+
merge_path_into_collapsed_paths(collapsed_paths, path)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def print_path(path)
|
106
|
+
path.map do |step|
|
107
|
+
if step.respond_to? :version
|
108
|
+
"(#{step.package.name} = #{step.version})"
|
109
|
+
elsif step.respond_to? :constraint
|
110
|
+
step.to_s
|
111
|
+
elsif step.kind_of?(Array)
|
112
|
+
# TODO [cw, 2011/2/23]: consider detecting complete
|
113
|
+
# ranges here instead of calling each out individually
|
114
|
+
"(#{step.first.package.name} = {#{step.map{|elt| "#{elt.version}"}.join(',')}})"
|
115
|
+
else
|
116
|
+
raise "don't know how to print step"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# collapses path_under_consideration onto the end of
|
122
|
+
# collapsed_paths or adds a new path to be used in the next
|
123
|
+
# round(s) of collapsing.
|
124
|
+
#
|
125
|
+
# Note: collapsed_paths is side-effected
|
126
|
+
def merge_path_into_collapsed_paths(collapsed_paths, path_under_consideration)
|
127
|
+
curr_collapsed_path = collapsed_paths.last
|
128
|
+
|
129
|
+
# if there is no curr_collapsed_path or it isn't the same
|
130
|
+
# length as path_under_consideration, then they cannot
|
131
|
+
# possibly be mergeable
|
132
|
+
if curr_collapsed_path.nil? || curr_collapsed_path.length != path_under_consideration.length
|
133
|
+
# TODO [cw.2011/2/7]: do we need this to be a new array, or
|
134
|
+
# can we save ourselves a little memory and work by just
|
135
|
+
# pushing the reference to path_under_consideration?
|
136
|
+
return collapsed_paths << Array.new(path_under_consideration)
|
137
|
+
end
|
138
|
+
|
139
|
+
# lengths are equal, so find the first path element where
|
140
|
+
# curr_collapsed_path and path_under_consideration diverge, if
|
141
|
+
# that is the only unequal element, it's for the same package,
|
142
|
+
# and they are both PackageVersion objects then merge;
|
143
|
+
# otherwise, this is a new path
|
144
|
+
#
|
145
|
+
# TODO [cw,2011/2/7]: should we merge even if they're not for
|
146
|
+
# the same package?
|
147
|
+
unequal_idx = nil
|
148
|
+
merged_set = nil
|
149
|
+
mergeable = true
|
150
|
+
path_under_consideration.each_with_index do |path_element, curr_idx|
|
151
|
+
if path_element != curr_collapsed_path[curr_idx]
|
152
|
+
unless unequal_idx
|
153
|
+
merged_set = [curr_collapsed_path[curr_idx]].flatten
|
154
|
+
if merged_set.first.package == path_element.package &&
|
155
|
+
merged_set.first.is_a?(PackageVersion) &&
|
156
|
+
path_element.is_a?(PackageVersion)
|
157
|
+
merged_set << path_element
|
158
|
+
else
|
159
|
+
mergeable = false
|
160
|
+
break
|
161
|
+
end
|
162
|
+
unequal_idx = curr_idx
|
163
|
+
else
|
164
|
+
# this is the second place they are unequal. fast-fail,
|
165
|
+
# because we know we can't merge the paths.
|
166
|
+
mergeable = false
|
167
|
+
break
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
if unequal_idx && mergeable
|
173
|
+
curr_collapsed_path[unequal_idx] = merged_set
|
174
|
+
else
|
175
|
+
collapsed_paths << Array.new(path_under_consideration)
|
176
|
+
end
|
177
|
+
|
178
|
+
collapsed_paths
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module DepSelector
|
21
|
+
class ErrorReporter
|
22
|
+
|
23
|
+
def give_feedback(workspace, solution_constraints, unsatisfiable_constraint_idx, most_constrained_package)
|
24
|
+
raise "Sub-class must implement"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module DepSelector
|
21
|
+
module Exceptions
|
22
|
+
|
23
|
+
# This exception is what the client of dep_selector should
|
24
|
+
# catch. It contains the solution constraint that introduces
|
25
|
+
# unsatisfiability, as well as the set of packages that are
|
26
|
+
# required to be disabled due to
|
27
|
+
class NoSolutionExists < StandardError
|
28
|
+
attr_reader :message, :unsatisfiable_solution_constraint,
|
29
|
+
:disabled_non_existent_packages,
|
30
|
+
:disabled_most_constrained_packages
|
31
|
+
def initialize(message, unsatisfiable_solution_constraint,
|
32
|
+
disabled_non_existent_packages = [],
|
33
|
+
disabled_most_constrained_packages = [])
|
34
|
+
@message = message
|
35
|
+
@unsatisfiable_solution_constraint = unsatisfiable_solution_constraint
|
36
|
+
@disabled_non_existent_packages = disabled_non_existent_packages
|
37
|
+
@disabled_most_constrained_packages = disabled_most_constrained_packages
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# This exception is thrown by gecode_wrapper and only used
|
42
|
+
# internally
|
43
|
+
class NoSolutionFound < StandardError
|
44
|
+
attr_reader :unsatisfiable_problem
|
45
|
+
def initialize(unsatisfiable_problem=nil)
|
46
|
+
@unsatisfiable_problem = unsatisfiable_problem
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# This exception is thrown during Selector#find_solution if any of
|
51
|
+
# the solution constraints make finding solution impossible. The
|
52
|
+
# two cases are if a solution constraint references a package that
|
53
|
+
# doesn't exist or if the constraint on an extant package matches
|
54
|
+
# no versions.
|
55
|
+
class InvalidSolutionConstraints < ArgumentError
|
56
|
+
attr_reader :non_existent_packages, :constrained_to_no_versions
|
57
|
+
def initialize(non_existent_packages, constrained_to_no_versions)
|
58
|
+
@non_existent_packages = non_existent_packages
|
59
|
+
@constrained_to_no_versions = constrained_to_no_versions
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class InvalidVersion < ArgumentError ; end
|
64
|
+
class InvalidVersionConstraint < ArgumentError; end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/package_version'
|
21
|
+
require 'dep_selector/densely_packed_set'
|
22
|
+
|
23
|
+
module DepSelector
|
24
|
+
class Package
|
25
|
+
attr_reader :dependency_graph, :name, :versions
|
26
|
+
|
27
|
+
def initialize(dependency_graph, name)
|
28
|
+
@dependency_graph = dependency_graph
|
29
|
+
@name = name
|
30
|
+
@versions = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_version(version)
|
34
|
+
versions << (pv = PackageVersion.new(self, version))
|
35
|
+
pv
|
36
|
+
end
|
37
|
+
|
38
|
+
# Note: only invoke this method after all PackageVersions have been added
|
39
|
+
def densely_packed_versions
|
40
|
+
@densely_packed_versions ||= DenselyPackedSet.new(versions.map{|pkg_version| pkg_version.version})
|
41
|
+
end
|
42
|
+
|
43
|
+
# Given a version, this method returns the corresonding
|
44
|
+
# PackageVersion. Given a version constraint, this method returns
|
45
|
+
# an array of matching PackageVersions.
|
46
|
+
#--
|
47
|
+
# TODO [cw,2011/2/4]: rationalize this with DenselyPackedSet#[]
|
48
|
+
def [](version_or_constraint)
|
49
|
+
# version constraints must abide the include? contract
|
50
|
+
if version_or_constraint.respond_to?(:include?)
|
51
|
+
versions.select do |ver|
|
52
|
+
version_or_constraint.include?(ver)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
versions.find{|pkg_version| pkg_version.version == version_or_constraint}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# A Package is considered valid if it has at least one version
|
60
|
+
def valid?
|
61
|
+
versions.any?
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s(incl_densely_packed_versions = false)
|
65
|
+
components = []
|
66
|
+
components << "Package #{name}"
|
67
|
+
if incl_densely_packed_versions
|
68
|
+
components << " (#{densely_packed_versions.range})"
|
69
|
+
end
|
70
|
+
versions.each{|version| components << "\n #{version.to_s(incl_densely_packed_versions)}"}
|
71
|
+
components.flatten.join
|
72
|
+
end
|
73
|
+
|
74
|
+
# Note: only invoke this method after all PackageVersions have been added
|
75
|
+
def gecode_package_id
|
76
|
+
# Note: gecode does naive bounds propagation at every post,
|
77
|
+
# which means that any package with exactly one version is
|
78
|
+
# considered bound and its dependencies propagated even though
|
79
|
+
# there might not be a solution constraint that requires that
|
80
|
+
# package to be bound, which means that otherwise-irrelevant
|
81
|
+
# constraints (e.g. A1->B1 when the solution constraint is B=2
|
82
|
+
# and there is nothing to induce a dependency on A) can cause
|
83
|
+
# unsatisfiability. Therefore, we want every package to have at
|
84
|
+
# least two versions, one of which is neither the target of
|
85
|
+
# other packages' dependencies nor induces other
|
86
|
+
# dependencies. Package version id -1 serves this purpose.
|
87
|
+
#
|
88
|
+
# TODO [cw, 2011/2/22]: Do we likewise want to leave packages
|
89
|
+
# with no versions (the target of an invalid dependency) with
|
90
|
+
# two versions in order to allow the solver to explore the
|
91
|
+
# invalid portion of the state space instead of naively limiting
|
92
|
+
# it for the purposes of having failure count heuristics?
|
93
|
+
max = densely_packed_versions.range.max || -1
|
94
|
+
@gecode_package_id ||= dependency_graph.gecode_wrapper.add_package(-1, max, 0)
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_gecode_wrapper_constraints
|
98
|
+
# if this is a valid package (has versions), we don't need to
|
99
|
+
# explicitly call gecode_package_id, because they will do it for
|
100
|
+
# us; however, if this package isn't valid (it only exists as an
|
101
|
+
# invalid dependency and thus has no versions), the solver gets
|
102
|
+
# confused, because we won't have generated its package id by
|
103
|
+
# the time it starts solving.
|
104
|
+
gecode_package_id
|
105
|
+
versions.each{|version| version.generate_gecode_wrapper_constraints }
|
106
|
+
end
|
107
|
+
|
108
|
+
def eql?(o)
|
109
|
+
# TODO [cw,2011/2/7]: this is really shallow. should implement
|
110
|
+
# == for DependencyGraph
|
111
|
+
self.class == o.class && name == o.name
|
112
|
+
end
|
113
|
+
alias :== :eql?
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module DepSelector
|
21
|
+
class PackageVersion
|
22
|
+
attr_accessor :package, :version, :dependencies
|
23
|
+
|
24
|
+
def initialize(package, version)
|
25
|
+
@package = package
|
26
|
+
@version = version
|
27
|
+
@dependencies = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_gecode_wrapper_constraints
|
31
|
+
pkg_densely_packed_version = package.densely_packed_versions.index(version)
|
32
|
+
|
33
|
+
dependencies.each do |dep|
|
34
|
+
dep_pkg_range = dep.package.densely_packed_versions[dep.constraint]
|
35
|
+
package.dependency_graph.gecode_wrapper.add_version_constraint(package.gecode_package_id, pkg_densely_packed_version, dep.package.gecode_package_id, dep_pkg_range.min, dep_pkg_range.max)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s(incl_densely_packed_versions = false)
|
40
|
+
components = []
|
41
|
+
components << "#{version}"
|
42
|
+
if incl_densely_packed_versions
|
43
|
+
components << " (#{package.densely_packed_versions.index(version)})"
|
44
|
+
end
|
45
|
+
components << " -> [#{dependencies.map{|d|d.to_s(incl_densely_packed_versions)}.join(', ')}]"
|
46
|
+
components.join
|
47
|
+
end
|
48
|
+
|
49
|
+
def hash
|
50
|
+
# Didn't put any thought or research into this, probably can be
|
51
|
+
# done better
|
52
|
+
to_s.hash
|
53
|
+
end
|
54
|
+
|
55
|
+
def eql?(o)
|
56
|
+
o.class == self.class &&
|
57
|
+
package == o.package &&
|
58
|
+
version == o.version &&
|
59
|
+
dependencies == o.dependencies
|
60
|
+
end
|
61
|
+
alias :== :eql?
|
62
|
+
|
63
|
+
def to_hash
|
64
|
+
{ :package_name => package.name, :version => version }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/dependency_graph'
|
21
|
+
require 'dep_selector/exceptions'
|
22
|
+
require 'dep_selector/error_reporter'
|
23
|
+
require 'dep_selector/error_reporter/simple_tree_traverser'
|
24
|
+
|
25
|
+
# A Selector contains the a DependencyGraph, which is populated with
|
26
|
+
# the dependency relationships, and an array of solution
|
27
|
+
# constraints. When a solution is asked for (via #find_solution),
|
28
|
+
# either a valid assignment is returned or the first solution
|
29
|
+
# constraint that makes a solution impossible.
|
30
|
+
module DepSelector
|
31
|
+
class Selector
|
32
|
+
attr_accessor :dep_graph, :error_reporter
|
33
|
+
|
34
|
+
DEFAULT_ERROR_REPORTER = ErrorReporter::SimpleTreeTraverser.new
|
35
|
+
|
36
|
+
def initialize(dep_graph, error_reporter = DEFAULT_ERROR_REPORTER)
|
37
|
+
@dep_graph = dep_graph
|
38
|
+
@error_reporter = error_reporter
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_solution(solution_constraints, valid_packages = nil)
|
42
|
+
result = Net::HTTP.post_form(URI('http://localhost:9393/'), {selector: self.to_yaml, solution_constraints: solution_constraints.to_yaml, valid_packages: valid_packages.to_yaml})
|
43
|
+
JSON.parse(result.body)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/dependency'
|
21
|
+
|
22
|
+
class DepSelector::SolutionConstraint < DepSelector::Dependency ; end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Seth Falcon (<seth@opscode.com>)
|
3
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
4
|
+
# Copyright:: Copyright 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/exceptions'
|
21
|
+
|
22
|
+
module DepSelector
|
23
|
+
class Version
|
24
|
+
include Comparable
|
25
|
+
attr_reader :major, :minor, :patch
|
26
|
+
|
27
|
+
def initialize(str="")
|
28
|
+
@major, @minor, @patch = parse(str)
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"#{@major}.#{@minor}.#{@patch}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"#{@major}.#{@minor}.#{@patch}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def <=>(v)
|
40
|
+
[:major, :minor, :patch].each do |method|
|
41
|
+
ans = (self.send(method) <=> v.send(method))
|
42
|
+
return ans if ans != 0
|
43
|
+
end
|
44
|
+
0
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash
|
48
|
+
# Didn't put any thought or research into this, probably can be
|
49
|
+
# done better
|
50
|
+
to_s.hash
|
51
|
+
end
|
52
|
+
|
53
|
+
# For hash
|
54
|
+
def eql?(other)
|
55
|
+
other.is_a?(Version) && self == other
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def parse(str="")
|
61
|
+
@major, @minor, @patch =
|
62
|
+
case str.to_s
|
63
|
+
when /^(\d+)\.(\d+)\.(\d+)$/
|
64
|
+
[ $1.to_i, $2.to_i, $3.to_i ]
|
65
|
+
when /^(\d+)\.(\d+)$/
|
66
|
+
[ $1.to_i, $2.to_i, 0 ]
|
67
|
+
else
|
68
|
+
msg = "'#{str.to_s}' does not match 'x.y.z' or 'x.y'"
|
69
|
+
raise Exceptions::InvalidVersion.new msg
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Seth Falcon (<seth@opscode.com>)
|
3
|
+
# Copyright:: Copyright 2010-2011 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'dep_selector/version'
|
20
|
+
require 'dep_selector/exceptions'
|
21
|
+
|
22
|
+
module DepSelector
|
23
|
+
class VersionConstraint
|
24
|
+
DEFAULT_CONSTRAINT = ">= 0.0.0"
|
25
|
+
STANDARD_OPS = %w(< > <= >=)
|
26
|
+
OPS = %w(< > = <= >= ~>)
|
27
|
+
PATTERN = /^(#{OPS.join('|')}) (.+)$/
|
28
|
+
|
29
|
+
attr_reader :op, :version
|
30
|
+
|
31
|
+
def initialize(constraint_spec=nil)
|
32
|
+
constraint_spec ||= DEFAULT_CONSTRAINT
|
33
|
+
case constraint_spec
|
34
|
+
when nil
|
35
|
+
parse(DEFAULT_CONSTRAINT)
|
36
|
+
when Array
|
37
|
+
parse_from_array(constraint_spec)
|
38
|
+
when String
|
39
|
+
parse(constraint_spec)
|
40
|
+
else
|
41
|
+
msg = "VersionConstraint should be created from a String. You gave: #{constraint_spec.inspect}"
|
42
|
+
raise Exceptions::InvalidVersionConstraint, msg
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def include?(v)
|
47
|
+
version = if v.respond_to? :version
|
48
|
+
Version.new(v.version.to_s)
|
49
|
+
else
|
50
|
+
Version.new(v.to_s)
|
51
|
+
end
|
52
|
+
do_op(version)
|
53
|
+
end
|
54
|
+
|
55
|
+
def inspect
|
56
|
+
"(#{@op} #{@version})"
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#{@op} #{@version}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def eql?(o)
|
64
|
+
o.class == self.class && @op == o.op && @version == o.version
|
65
|
+
end
|
66
|
+
alias_method :==, :eql?
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def do_op(other_version)
|
71
|
+
if STANDARD_OPS.include? @op
|
72
|
+
other_version.send(@op.to_sym, @version)
|
73
|
+
elsif @op == '='
|
74
|
+
other_version == @version
|
75
|
+
elsif @op == '~>'
|
76
|
+
if @missing_patch_level
|
77
|
+
(other_version.major == @version.major &&
|
78
|
+
other_version.minor >= @version.minor)
|
79
|
+
else
|
80
|
+
(other_version.major == @version.major &&
|
81
|
+
other_version.minor == @version.minor &&
|
82
|
+
other_version.patch >= @version.patch)
|
83
|
+
end
|
84
|
+
else # should never happen
|
85
|
+
raise "bad op #{@op}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_from_array(constraint_spec)
|
90
|
+
if constraint_spec.empty?
|
91
|
+
parse(DEFAULT_CONSTRAINT)
|
92
|
+
elsif constraint_spec.size == 1
|
93
|
+
parse(constraint_spec.first)
|
94
|
+
else
|
95
|
+
msg = "only one version constraint operation is supported, but you gave #{constraint_spec.size} "
|
96
|
+
msg << "['#{constraint_spec.join(', ')}']"
|
97
|
+
raise Exceptions::InvalidVersionConstraint, msg
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse(str)
|
102
|
+
@missing_patch_level = false
|
103
|
+
if str.index(" ").nil? && str =~ /^[0-9]/
|
104
|
+
# try for lone version, implied '='
|
105
|
+
@version = Version.new(str)
|
106
|
+
@op = "="
|
107
|
+
elsif PATTERN.match str
|
108
|
+
@op = $1
|
109
|
+
raw_version = $2
|
110
|
+
@version = Version.new(raw_version)
|
111
|
+
if raw_version.split('.').count == 2
|
112
|
+
@missing_patch_level = true
|
113
|
+
end
|
114
|
+
else
|
115
|
+
raise Exceptions::InvalidVersionConstraint, "'#{str}'"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
data/lib/dep_selector.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
3
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dep_selector/dep_selector_version'
|
21
|
+
|
22
|
+
require 'dep_selector/selector'
|
23
|
+
require 'dep_selector/dependency_graph'
|
24
|
+
require 'dep_selector/package'
|
25
|
+
require 'dep_selector/package_version'
|
26
|
+
require 'dep_selector/dependency'
|
27
|
+
require 'dep_selector/solution_constraint'
|
28
|
+
require 'dep_selector/version'
|
29
|
+
require 'dep_selector/version_constraint'
|
30
|
+
require 'dep_selector/exceptions'
|
31
|
+
|
32
|
+
# error reporting
|
33
|
+
require 'dep_selector/error_reporter'
|
34
|
+
require 'dep_selector/error_reporter/simple_tree_traverser'
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dep_selector_over_http
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.9
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Josiah Kiehl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Given packages, versions, and a dependency graph, find a valid assignment
|
15
|
+
of package versions
|
16
|
+
email:
|
17
|
+
- cw@opscode.com
|
18
|
+
- mark@opscode.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/dep_selector/densely_packed_set.rb
|
24
|
+
- lib/dep_selector/dep_selector_version.rb
|
25
|
+
- lib/dep_selector/dependency.rb
|
26
|
+
- lib/dep_selector/dependency_graph.rb
|
27
|
+
- lib/dep_selector/error_reporter/simple_tree_traverser.rb
|
28
|
+
- lib/dep_selector/error_reporter.rb
|
29
|
+
- lib/dep_selector/exceptions.rb
|
30
|
+
- lib/dep_selector/package.rb
|
31
|
+
- lib/dep_selector/package_version.rb
|
32
|
+
- lib/dep_selector/selector.rb
|
33
|
+
- lib/dep_selector/solution_constraint.rb
|
34
|
+
- lib/dep_selector/version.rb
|
35
|
+
- lib/dep_selector/version_constraint.rb
|
36
|
+
- lib/dep_selector.rb
|
37
|
+
homepage: http://github.com/RiotGames/dep-selector-over-http
|
38
|
+
licenses:
|
39
|
+
- Apache v2
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.8.11
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: Given packages, versions, and a dependency graph, find a valid assignment
|
62
|
+
of package versions
|
63
|
+
test_files: []
|