pub_grub 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/pub_grub.rb +1 -1
- data/lib/pub_grub/basic_package_source.rb +166 -0
- data/lib/pub_grub/failure_writer.rb +2 -0
- data/lib/pub_grub/incompatibility.rb +4 -1
- data/lib/pub_grub/package.rb +4 -0
- data/lib/pub_grub/static_package_source.rb +19 -75
- data/lib/pub_grub/version_constraint.rb +2 -2
- data/lib/pub_grub/version_solver.rb +28 -14
- data/lib/pub_grub/version_union.rb +1 -1
- data/pub_grub.gemspec +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 906d1263305a0df7b8082cf01fd1abb3ddbd92f294744b1d9131603396be31a1
|
4
|
+
data.tar.gz: 6566971cf3a8ed458d15d21233614351d12b407c3e056f3bc580b0efe810fef0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d793abfc4b0481e6a056f2355310c60e8450058f777754284e011369d2e420a14c37939a8631b3d1ae01ec3f7b1f7c4250234a245ba4b2b6d6d4fc4ea90a5ee
|
7
|
+
data.tar.gz: 526cc6588093a2ec82b44fdad8a2bf6c09f3520c02d1c9a248e11576ca80e6c2817dc8564573b95d8da637e29ea5bed80379632f176a8729bb7c4eecba227950
|
data/Gemfile.lock
CHANGED
data/lib/pub_grub.rb
CHANGED
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'pub_grub/version_constraint'
|
2
|
+
require 'pub_grub/incompatibility'
|
3
|
+
|
4
|
+
module PubGrub
|
5
|
+
# Types:
|
6
|
+
#
|
7
|
+
# Where possible, PubGrub will accept user-defined types, so long as they quack.
|
8
|
+
#
|
9
|
+
# ## "Package":
|
10
|
+
#
|
11
|
+
# This class will be used to represent the various packages being solved for.
|
12
|
+
# .to_s will be called when displaying errors and debugging info, it should
|
13
|
+
# probably return the package's name.
|
14
|
+
# It must also have a reasonable definition of #== and #hash
|
15
|
+
#
|
16
|
+
# Example classes: String ("rails")
|
17
|
+
#
|
18
|
+
#
|
19
|
+
# ## "Version":
|
20
|
+
#
|
21
|
+
# This class will be used to represent a single version number.
|
22
|
+
#
|
23
|
+
# Versions don't need to store their associated package, however they will
|
24
|
+
# only be compared against other versions of the same package.
|
25
|
+
#
|
26
|
+
# It must be Comparible (and implement <=> reasonably)
|
27
|
+
#
|
28
|
+
# Example classes: Gem::Version, Integer
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# ## "Dependency"
|
32
|
+
#
|
33
|
+
# This class represents the requirement one package has on another. It is
|
34
|
+
# returned by dependencies_for(package, version) and will be passed to
|
35
|
+
# parse_dependency to convert it to a format PubGrub understands.
|
36
|
+
#
|
37
|
+
# It must also have a reasonable definition of #==
|
38
|
+
#
|
39
|
+
# Example classes: String ("~> 1.0"), Gem::Requirement
|
40
|
+
#
|
41
|
+
class BasicPackageSource
|
42
|
+
# Override me!
|
43
|
+
#
|
44
|
+
# This is called per package to find all possible versions of a package.
|
45
|
+
#
|
46
|
+
# It is called at most once per-package
|
47
|
+
#
|
48
|
+
# Returns: Array of versions for a package, in preferred order of selection
|
49
|
+
def all_versions_for(package)
|
50
|
+
raise NotImplementedError
|
51
|
+
end
|
52
|
+
|
53
|
+
# Override me!
|
54
|
+
#
|
55
|
+
# Returns: Hash in the form of { package => requirement, ... }
|
56
|
+
def dependencies_for(package, version)
|
57
|
+
raise NotImplementedError
|
58
|
+
end
|
59
|
+
|
60
|
+
# Override me!
|
61
|
+
#
|
62
|
+
# Convert a (user-defined) dependency into a format PubGrub understands.
|
63
|
+
#
|
64
|
+
# Package is passed to this method but for many implementations is not
|
65
|
+
# needed.
|
66
|
+
#
|
67
|
+
# Returns: either a PubGrub::VersionRange, PubGrub::VersionUnion, or a
|
68
|
+
# PubGrub::VersionConstraint
|
69
|
+
def parse_dependency(package, dependency)
|
70
|
+
raise NotImplementedError
|
71
|
+
end
|
72
|
+
|
73
|
+
# Override me!
|
74
|
+
#
|
75
|
+
# If not overridden, this will call dependencies_for with the root package.
|
76
|
+
#
|
77
|
+
# Returns: Hash in the form of { package => requirement, ... } (see dependencies_for)
|
78
|
+
def root_dependencies
|
79
|
+
dependencies_for(@root_package, @root_version)
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize
|
83
|
+
@root_package = Package.root
|
84
|
+
@root_version = Package.root_version
|
85
|
+
|
86
|
+
@cached_versions = Hash.new do |h,k|
|
87
|
+
if k == @root_package
|
88
|
+
h[k] = [0]
|
89
|
+
else
|
90
|
+
h[k] = all_versions_for(k)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@sorted_versions = Hash.new { |h,k| h[k] = @cached_versions[k].sort }
|
94
|
+
|
95
|
+
@cached_dependencies = Hash.new do |packages, package|
|
96
|
+
if package == @root_package
|
97
|
+
packages[package] = {
|
98
|
+
@root_version => root_dependencies
|
99
|
+
}
|
100
|
+
else
|
101
|
+
packages[package] = Hash.new do |versions, version|
|
102
|
+
versions[version] = dependencies_for(package, version)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def versions_for(package, range=VersionRange.any)
|
109
|
+
@cached_versions[package].select do |version|
|
110
|
+
range.include?(version)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def incompatibilities_for(package, version)
|
115
|
+
package_deps = @cached_dependencies[package]
|
116
|
+
sorted_versions = @sorted_versions[package]
|
117
|
+
package_deps[version].map do |dep_package, dep_constraint_name|
|
118
|
+
low = high = sorted_versions.index(version)
|
119
|
+
|
120
|
+
# find version low such that all >= low share the same dep
|
121
|
+
while low > 0 &&
|
122
|
+
package_deps[sorted_versions[low - 1]][dep_package] == dep_constraint_name
|
123
|
+
low -= 1
|
124
|
+
end
|
125
|
+
low =
|
126
|
+
if low == 0
|
127
|
+
nil
|
128
|
+
else
|
129
|
+
sorted_versions[low]
|
130
|
+
end
|
131
|
+
|
132
|
+
# find version high such that all < high share the same dep
|
133
|
+
while high < sorted_versions.length &&
|
134
|
+
package_deps[sorted_versions[high]][dep_package] == dep_constraint_name
|
135
|
+
high += 1
|
136
|
+
end
|
137
|
+
high =
|
138
|
+
if high == sorted_versions.length
|
139
|
+
nil
|
140
|
+
else
|
141
|
+
sorted_versions[high]
|
142
|
+
end
|
143
|
+
|
144
|
+
range = VersionRange.new(min: low, max: high, include_min: true)
|
145
|
+
|
146
|
+
self_constraint = VersionConstraint.new(package, range: range)
|
147
|
+
|
148
|
+
if !@packages.include?(dep_package)
|
149
|
+
# no such package -> this version is invalid
|
150
|
+
end
|
151
|
+
|
152
|
+
dep_constraint = parse_dependency(dep_package, dep_constraint_name)
|
153
|
+
if !dep_constraint
|
154
|
+
# falsey indicates this dependency was invalid
|
155
|
+
cause = PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint_name)
|
156
|
+
return [Incompatibility.new([Term.new(self_constraint, true)], cause: cause)]
|
157
|
+
elsif !dep_constraint.is_a?(VersionConstraint)
|
158
|
+
# Upgrade range/union to VersionConstraint
|
159
|
+
dep_constraint = VersionConstraint.new(dep_package, range: dep_constraint)
|
160
|
+
end
|
161
|
+
|
162
|
+
Incompatibility.new([Term.new(self_constraint, true), Term.new(dep_constraint, false)], cause: :dependency)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -16,6 +16,10 @@ module PubGrub
|
|
16
16
|
def initialize(terms, cause:)
|
17
17
|
@cause = cause
|
18
18
|
@terms = cleanup_terms(terms)
|
19
|
+
|
20
|
+
if cause == :dependency && @terms.length != 2
|
21
|
+
raise ArgumentError, "a dependency Incompatibility must have exactly two terms. Got #{terms.inspect}"
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
def failure?
|
@@ -44,7 +48,6 @@ module PubGrub
|
|
44
48
|
when :root
|
45
49
|
"(root dependency)"
|
46
50
|
when :dependency
|
47
|
-
raise unless terms.length == 2
|
48
51
|
"#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
|
49
52
|
when PubGrub::Incompatibility::InvalidDependency
|
50
53
|
"#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
|
data/lib/pub_grub/package.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'pub_grub/package'
|
2
2
|
require 'pub_grub/version_constraint'
|
3
3
|
require 'pub_grub/incompatibility'
|
4
|
+
require 'pub_grub/basic_package_source'
|
4
5
|
|
5
6
|
module PubGrub
|
6
|
-
class StaticPackageSource
|
7
|
+
class StaticPackageSource < BasicPackageSource
|
7
8
|
class DSL
|
8
9
|
def initialize(packages, root_deps)
|
9
10
|
@packages = packages
|
@@ -15,95 +16,38 @@ module PubGrub
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def add(name, version, deps: {})
|
18
|
-
|
19
|
+
version = Gem::Version.new(version)
|
20
|
+
@packages[name] ||= {}
|
21
|
+
raise ArgumentError, "#{name} #{version} declared twice" if @packages[name].key?(version)
|
22
|
+
@packages[name][version] = deps
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def initialize
|
23
27
|
@root_deps = {}
|
24
|
-
@
|
25
|
-
yield DSL.new(@package_list, @root_deps)
|
26
|
-
|
27
|
-
@packages = {
|
28
|
-
root: Package.root
|
29
|
-
}
|
30
|
-
@package_versions = Hash.new{ |h, k| h[k] = [] }
|
31
|
-
|
32
|
-
@deps_by_version = Hash.new { |h, k| h[k] = {} }
|
33
|
-
|
34
|
-
root_version = Package.root_version
|
35
|
-
@package_versions[Package.root] = [root_version]
|
36
|
-
@deps_by_version[Package.root][root_version] = @root_deps
|
28
|
+
@packages = {}
|
37
29
|
|
38
|
-
@
|
39
|
-
@packages[name] ||= Package.new(name)
|
40
|
-
package = @packages[name]
|
30
|
+
yield DSL.new(@packages, @root_deps)
|
41
31
|
|
42
|
-
|
43
|
-
@package_versions[package] << version
|
44
|
-
@deps_by_version[package][version] = deps
|
45
|
-
end
|
32
|
+
super()
|
46
33
|
end
|
47
34
|
|
48
|
-
def
|
49
|
-
@packages[
|
50
|
-
raise("No such package in source: #{name.inspect}")
|
35
|
+
def all_versions_for(package)
|
36
|
+
@packages[package].keys
|
51
37
|
end
|
52
|
-
alias_method :package, :get_package
|
53
38
|
|
54
|
-
def
|
55
|
-
@
|
56
|
-
range.include?(version)
|
57
|
-
end
|
39
|
+
def root_dependencies
|
40
|
+
@root_deps
|
58
41
|
end
|
59
42
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
package_deps[version].map do |dep_package_name, dep_constraint_name|
|
64
|
-
sorted_versions = package_versions.sort
|
65
|
-
low = high = sorted_versions.index(version)
|
66
|
-
|
67
|
-
# find version low such that all >= low share the same dep
|
68
|
-
while low > 0 &&
|
69
|
-
package_deps[sorted_versions[low - 1]][dep_package_name] == dep_constraint_name
|
70
|
-
low -= 1
|
71
|
-
end
|
72
|
-
low =
|
73
|
-
if low == 0
|
74
|
-
nil
|
75
|
-
else
|
76
|
-
sorted_versions[low]
|
77
|
-
end
|
78
|
-
|
79
|
-
# find version high such that all < high share the same dep
|
80
|
-
while high < sorted_versions.length &&
|
81
|
-
package_deps[sorted_versions[high]][dep_package_name] == dep_constraint_name
|
82
|
-
high += 1
|
83
|
-
end
|
84
|
-
high =
|
85
|
-
if high == sorted_versions.length
|
86
|
-
nil
|
87
|
-
else
|
88
|
-
sorted_versions[high]
|
89
|
-
end
|
90
|
-
|
91
|
-
range = VersionRange.new(min: low, max: high, include_min: true)
|
92
|
-
|
93
|
-
self_constraint = VersionConstraint.new(package, range: range)
|
94
|
-
|
95
|
-
dep_package = @packages[dep_package_name]
|
96
|
-
|
97
|
-
if !dep_package
|
98
|
-
# no such package -> this version is invalid
|
99
|
-
cause = PubGrub::Incompatibility::InvalidDependency.new(dep_package_name, dep_constraint_name)
|
100
|
-
return [Incompatibility.new([Term.new(self_constraint, true)], cause: cause)]
|
101
|
-
end
|
43
|
+
def dependencies_for(package, version)
|
44
|
+
@packages[package][version]
|
45
|
+
end
|
102
46
|
|
103
|
-
|
47
|
+
def parse_dependency(package, dependency)
|
48
|
+
return false unless @packages.key?(package)
|
104
49
|
|
105
|
-
|
106
|
-
end
|
50
|
+
PubGrub::RubyGems.parse_constraint(package, dependency)
|
107
51
|
end
|
108
52
|
end
|
109
53
|
end
|
@@ -85,9 +85,9 @@ module PubGrub
|
|
85
85
|
if package == Package.root
|
86
86
|
"root"
|
87
87
|
elsif allow_every && any?
|
88
|
-
"every version of #{package
|
88
|
+
"every version of #{package}"
|
89
89
|
else
|
90
|
-
"#{package
|
90
|
+
"#{package} #{constraint_string}"
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -8,7 +8,7 @@ module PubGrub
|
|
8
8
|
attr_reader :source
|
9
9
|
attr_reader :solution
|
10
10
|
|
11
|
-
def initialize(source:)
|
11
|
+
def initialize(source:, root: Package.root)
|
12
12
|
@source = source
|
13
13
|
|
14
14
|
# { package => [incompatibility, ...]}
|
@@ -19,29 +19,43 @@ module PubGrub
|
|
19
19
|
@solution = PartialSolution.new
|
20
20
|
|
21
21
|
add_incompatibility Incompatibility.new([
|
22
|
-
Term.new(VersionConstraint.any(
|
22
|
+
Term.new(VersionConstraint.any(root), false)
|
23
23
|
], cause: :root)
|
24
|
+
|
25
|
+
propagate(root)
|
24
26
|
end
|
25
27
|
|
26
|
-
def
|
27
|
-
|
28
|
+
def solved?
|
29
|
+
solution.unsatisfied.empty?
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
32
|
+
# Returns true if there is more work to be done, false otherwise
|
33
|
+
def work
|
34
|
+
return false if solved?
|
31
35
|
|
32
|
-
|
33
|
-
|
36
|
+
next_package = choose_package_version
|
37
|
+
propagate(next_package)
|
34
38
|
|
35
|
-
|
39
|
+
if solved?
|
40
|
+
logger.info "Solution found after #{solution.attempted_solutions} attempts:"
|
41
|
+
solution.decisions.each do |package, version|
|
42
|
+
logger.info "* #{package} #{version}"
|
43
|
+
end
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
false
|
46
|
+
else
|
47
|
+
true
|
40
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def solve
|
52
|
+
work until solved?
|
41
53
|
|
42
|
-
|
54
|
+
solution.decisions
|
43
55
|
end
|
44
56
|
|
57
|
+
alias_method :result, :solve
|
58
|
+
|
45
59
|
private
|
46
60
|
|
47
61
|
def propagate(initial_package)
|
@@ -121,7 +135,7 @@ module PubGrub
|
|
121
135
|
end
|
122
136
|
|
123
137
|
unless conflict
|
124
|
-
logger.info("selecting #{package
|
138
|
+
logger.info("selecting #{package} #{version}")
|
125
139
|
|
126
140
|
solution.decide(package, version)
|
127
141
|
end
|
@@ -55,7 +55,7 @@ module PubGrub
|
|
55
55
|
def select_versions(all_versions)
|
56
56
|
versions = []
|
57
57
|
ranges.inject(all_versions) do |acc, range|
|
58
|
-
|
58
|
+
_, matching, higher = range.partition_versions(acc)
|
59
59
|
versions.concat matching
|
60
60
|
higher
|
61
61
|
end
|
data/pub_grub.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pub_grub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Hawthorn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -99,6 +99,7 @@ files:
|
|
99
99
|
- bin/setup
|
100
100
|
- lib/pub_grub.rb
|
101
101
|
- lib/pub_grub/assignment.rb
|
102
|
+
- lib/pub_grub/basic_package_source.rb
|
102
103
|
- lib/pub_grub/failure_writer.rb
|
103
104
|
- lib/pub_grub/incompatibility.rb
|
104
105
|
- lib/pub_grub/package.rb
|
@@ -132,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
133
|
version: '0'
|
133
134
|
requirements: []
|
134
135
|
rubyforge_project:
|
135
|
-
rubygems_version: 2.7.
|
136
|
+
rubygems_version: 2.7.6
|
136
137
|
signing_key:
|
137
138
|
specification_version: 4
|
138
139
|
summary: A version solver based on dart's PubGrub
|