gel 0.3.0 → 0.8.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -3
- data/RELEASING.md +12 -0
- data/exe/gel +4 -2
- data/gemlib/gel/stub.rb +20 -0
- data/lib/gel/catalog/common.rb +4 -2
- data/lib/gel/catalog/compact_index.rb +6 -10
- data/lib/gel/catalog/dependency_index.rb +10 -10
- data/lib/gel/catalog/legacy_index.rb +4 -6
- data/lib/gel/catalog/marshal_hacks.rb +2 -0
- data/lib/gel/catalog.rb +33 -52
- data/lib/gel/catalog_set.rb +100 -0
- data/lib/gel/command/help.rb +13 -2
- data/lib/gel/command/lock.rb +3 -3
- data/lib/gel/command/open.rb +24 -0
- data/lib/gel/command/shell_setup.rb +11 -8
- data/lib/gel/command/stub.rb +45 -2
- data/lib/gel/command/version.rb +7 -0
- data/lib/gel/command.rb +43 -6
- data/lib/gel/compatibility/rubygems.rb +10 -197
- data/lib/gel/compatibility.rb +2 -2
- data/lib/gel/config.rb +41 -7
- data/lib/gel/db.rb +93 -83
- data/lib/gel/direct_gem.rb +16 -4
- data/lib/gel/environment.rb +542 -249
- data/lib/gel/error.rb +156 -24
- data/lib/gel/gemfile_parser.rb +74 -12
- data/lib/gel/gemspec_parser.rb +26 -7
- data/lib/gel/git_catalog.rb +15 -3
- data/lib/gel/git_depot.rb +62 -28
- data/lib/gel/httpool.rb +5 -2
- data/lib/gel/installer.rb +61 -23
- data/lib/gel/lock_loader.rb +87 -112
- data/lib/gel/lock_parser.rb +23 -31
- data/lib/gel/locked_store.rb +30 -21
- data/lib/gel/multi_store.rb +13 -4
- data/lib/gel/null_solver.rb +67 -0
- data/lib/gel/package/abortable.rb +18 -0
- data/lib/gel/package/installer.rb +124 -49
- data/lib/gel/package.rb +21 -4
- data/lib/gel/path_catalog.rb +1 -1
- data/lib/gel/pinboard.rb +4 -2
- data/lib/gel/platform.rb +38 -0
- data/lib/gel/pub_grub/package.rb +67 -0
- data/lib/gel/pub_grub/preference_strategy.rb +10 -6
- data/lib/gel/pub_grub/solver.rb +37 -0
- data/lib/gel/pub_grub/source.rb +64 -92
- data/lib/gel/resolved_gem_set.rb +234 -0
- data/lib/gel/runtime.rb +3 -3
- data/lib/gel/set.rb +62 -0
- data/lib/gel/stdlib.rb +83 -0
- data/lib/gel/store.rb +94 -25
- data/lib/gel/store_catalog.rb +2 -2
- data/lib/gel/store_gem.rb +54 -6
- data/lib/gel/stub_set.rb +32 -2
- data/lib/gel/support/cgi_escape.rb +34 -0
- data/lib/gel/support/gem_platform.rb +0 -2
- data/lib/gel/support/sha512.rb +142 -0
- data/lib/gel/support/tar/tar_writer.rb +2 -2
- data/lib/gel/tail_file.rb +2 -1
- data/lib/gel/util.rb +108 -0
- data/lib/gel/vendor/pstore.rb +3 -0
- data/lib/gel/vendor/pub_grub.rb +3 -0
- data/lib/gel/vendor/ruby_digest.rb +3 -0
- data/lib/gel/vendor_catalog.rb +38 -0
- data/lib/gel/version.rb +1 -1
- data/lib/gel.rb +15 -0
- data/man/man1/gel-exec.1 +1 -1
- data/man/man1/gel-install.1 +1 -1
- data/man/man1/gel.1 +14 -1
- data/{lib/gel/compatibility → slib}/bundler/cli.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler/friendly_errors.rb +0 -0
- data/{lib/gel/compatibility/rubygems/dependency_installer.rb → slib/bundler/gem_helper.rb} +0 -0
- data/slib/bundler/gem_tasks.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler/setup.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler.rb +39 -3
- data/{lib/gel/compatibility → slib}/rubygems/command.rb +0 -0
- data/slib/rubygems/dependency_installer.rb +12 -0
- data/{lib/gel/compatibility → slib}/rubygems/gem_runner.rb +0 -0
- data/slib/rubygems/package.rb +6 -0
- data/slib/rubygems/package_task.rb +7 -0
- data/slib/rubygems/specification.rb +0 -0
- data/slib/rubygems/version.rb +0 -0
- data/slib/rubygems.rb +297 -0
- data/vendor/pstore/LICENSE.txt +22 -0
- data/vendor/pstore/lib/pstore.rb +488 -0
- data/vendor/pub_grub/LICENSE.txt +21 -0
- data/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
- data/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +183 -0
- data/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
- data/vendor/pub_grub/lib/pub_grub/incompatibility.rb +143 -0
- data/vendor/pub_grub/lib/pub_grub/package.rb +35 -0
- data/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
- data/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
- data/vendor/pub_grub/lib/pub_grub/solve_failure.rb +17 -0
- data/vendor/pub_grub/lib/pub_grub/static_package_source.rb +53 -0
- data/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
- data/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
- data/vendor/pub_grub/lib/pub_grub/version_constraint.rb +124 -0
- data/vendor/pub_grub/lib/pub_grub/version_range.rb +399 -0
- data/vendor/pub_grub/lib/pub_grub/version_solver.rb +247 -0
- data/vendor/pub_grub/lib/pub_grub/version_union.rb +174 -0
- data/vendor/pub_grub/lib/pub_grub.rb +31 -0
- data/vendor/ruby-digest/UNLICENSE +24 -0
- data/vendor/ruby-digest/lib/ruby_digest.rb +812 -0
- metadata +95 -19
@@ -0,0 +1,182 @@
|
|
1
|
+
module Gel::Vendor::PubGrub
|
2
|
+
class FailureWriter
|
3
|
+
def initialize(root)
|
4
|
+
@root = root
|
5
|
+
|
6
|
+
# { Incompatibility => Integer }
|
7
|
+
@derivations = {}
|
8
|
+
|
9
|
+
# [ [ String, Integer or nil ] ]
|
10
|
+
@lines = []
|
11
|
+
|
12
|
+
# { Incompatibility => Integer }
|
13
|
+
@line_numbers = {}
|
14
|
+
|
15
|
+
count_derivations(root)
|
16
|
+
end
|
17
|
+
|
18
|
+
def write
|
19
|
+
return @root.to_s unless @root.conflict?
|
20
|
+
|
21
|
+
visit(@root)
|
22
|
+
|
23
|
+
padding = @line_numbers.empty? ? 0 : "(#{@line_numbers.values.last}) ".length
|
24
|
+
|
25
|
+
@lines.map do |message, number|
|
26
|
+
next "" if message.empty?
|
27
|
+
|
28
|
+
lead = number ? "(#{number}) " : ""
|
29
|
+
lead = lead.ljust(padding)
|
30
|
+
message = message.gsub("\n", "\n" + " " * (padding + 2))
|
31
|
+
"#{lead}#{message}"
|
32
|
+
end.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def write_line(incompatibility, message, numbered:)
|
38
|
+
if numbered
|
39
|
+
number = @line_numbers.length + 1
|
40
|
+
@line_numbers[incompatibility] = number
|
41
|
+
end
|
42
|
+
|
43
|
+
@lines << [message, number]
|
44
|
+
end
|
45
|
+
|
46
|
+
def visit(incompatibility, conclusion: false)
|
47
|
+
raise unless incompatibility.conflict?
|
48
|
+
|
49
|
+
numbered = conclusion || @derivations[incompatibility] > 1;
|
50
|
+
conjunction = conclusion || incompatibility == @root ? "So," : "And"
|
51
|
+
|
52
|
+
cause = incompatibility.cause
|
53
|
+
|
54
|
+
if cause.conflict.conflict? && cause.other.conflict?
|
55
|
+
conflict_line = @line_numbers[cause.conflict]
|
56
|
+
other_line = @line_numbers[cause.other]
|
57
|
+
|
58
|
+
if conflict_line && other_line
|
59
|
+
write_line(
|
60
|
+
incompatibility,
|
61
|
+
"Because #{cause.conflict} (#{conflict_line})\nand #{cause.other} (#{other_line}),\n#{incompatibility}.",
|
62
|
+
numbered: numbered
|
63
|
+
)
|
64
|
+
elsif conflict_line || other_line
|
65
|
+
with_line = conflict_line ? cause.conflict : cause.other
|
66
|
+
without_line = conflict_line ? cause.other : cause.conflict
|
67
|
+
line = @line_numbers[with_line]
|
68
|
+
|
69
|
+
visit(without_line);
|
70
|
+
write_line(
|
71
|
+
incompatibility,
|
72
|
+
"#{conjunction} because #{with_line} (#{line}),\n#{incompatibility}.",
|
73
|
+
numbered: numbered
|
74
|
+
)
|
75
|
+
else
|
76
|
+
single_line_conflict = single_line?(cause.conflict.cause)
|
77
|
+
single_line_other = single_line?(cause.other.cause)
|
78
|
+
|
79
|
+
if single_line_conflict || single_line_other
|
80
|
+
first = single_line_other ? cause.conflict : cause.other
|
81
|
+
second = single_line_other ? cause.other : cause.conflict
|
82
|
+
visit(first)
|
83
|
+
visit(second)
|
84
|
+
write_line(
|
85
|
+
incompatibility,
|
86
|
+
"Thus, #{incompatibility}.",
|
87
|
+
numbered: numbered
|
88
|
+
)
|
89
|
+
else
|
90
|
+
visit(cause.conflict, conclusion: true)
|
91
|
+
@lines << ["", nil]
|
92
|
+
visit(cause.other)
|
93
|
+
|
94
|
+
write_line(
|
95
|
+
incompatibility,
|
96
|
+
"#{conjunction} because #{cause.conflict} (#{@line_numbers[cause.conflict]}),\n#{incompatibility}.",
|
97
|
+
numbered: numbered
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
elsif cause.conflict.conflict? || cause.other.conflict?
|
102
|
+
derived = cause.conflict.conflict? ? cause.conflict : cause.other
|
103
|
+
ext = cause.conflict.conflict? ? cause.other : cause.conflict
|
104
|
+
|
105
|
+
derived_line = @line_numbers[derived]
|
106
|
+
if derived_line
|
107
|
+
write_line(
|
108
|
+
incompatibility,
|
109
|
+
"Because #{ext}\nand #{derived} (#{derived_line}),\n#{incompatibility}.",
|
110
|
+
numbered: numbered
|
111
|
+
)
|
112
|
+
elsif collapsible?(derived)
|
113
|
+
derived_cause = derived.cause
|
114
|
+
if derived_cause.conflict.conflict?
|
115
|
+
collapsed_derived = derived_cause.conflict
|
116
|
+
collapsed_ext = derived_cause.other
|
117
|
+
else
|
118
|
+
collapsed_derived = derived_cause.other
|
119
|
+
collapsed_ext = derived_cause.conflict
|
120
|
+
end
|
121
|
+
|
122
|
+
visit(collapsed_derived)
|
123
|
+
|
124
|
+
write_line(
|
125
|
+
incompatibility,
|
126
|
+
"#{conjunction} because #{collapsed_ext}\nand #{ext},\n#{incompatibility}.",
|
127
|
+
numbered: numbered
|
128
|
+
)
|
129
|
+
else
|
130
|
+
visit(derived)
|
131
|
+
write_line(
|
132
|
+
incompatibility,
|
133
|
+
"#{conjunction} because #{ext},\n#{incompatibility}.",
|
134
|
+
numbered: numbered
|
135
|
+
)
|
136
|
+
end
|
137
|
+
else
|
138
|
+
write_line(
|
139
|
+
incompatibility,
|
140
|
+
"Because #{cause.conflict}\nand #{cause.other},\n#{incompatibility}.",
|
141
|
+
numbered: numbered
|
142
|
+
)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def single_line?(cause)
|
147
|
+
!cause.conflict.conflict? && !cause.other.conflict?
|
148
|
+
end
|
149
|
+
|
150
|
+
def collapsible?(incompatibility)
|
151
|
+
return false if @derivations[incompatibility] > 1
|
152
|
+
|
153
|
+
cause = incompatibility.cause
|
154
|
+
# If incompatibility is derived from two derived incompatibilities,
|
155
|
+
# there are too many transitive causes to display concisely.
|
156
|
+
return false if cause.conflict.conflict? && cause.other.conflict?
|
157
|
+
|
158
|
+
# If incompatibility is derived from two external incompatibilities, it
|
159
|
+
# tends to be confusing to collapse it.
|
160
|
+
return false unless cause.conflict.conflict? || cause.other.conflict?
|
161
|
+
|
162
|
+
# If incompatibility's internal cause is numbered, collapsing it would
|
163
|
+
# get too noisy.
|
164
|
+
complex = cause.conflict.conflict? ? cause.conflict : cause.other
|
165
|
+
|
166
|
+
!@line_numbers.has_key?(complex)
|
167
|
+
end
|
168
|
+
|
169
|
+
def count_derivations(incompatibility)
|
170
|
+
if @derivations.has_key?(incompatibility)
|
171
|
+
@derivations[incompatibility] += 1
|
172
|
+
else
|
173
|
+
@derivations[incompatibility] = 1
|
174
|
+
if incompatibility.conflict?
|
175
|
+
cause = incompatibility.cause
|
176
|
+
count_derivations(cause.conflict)
|
177
|
+
count_derivations(cause.other)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Gel::Vendor::PubGrub
|
2
|
+
class Incompatibility
|
3
|
+
ConflictCause = Struct.new(:incompatibility, :satisfier) do
|
4
|
+
alias_method :conflict, :incompatibility
|
5
|
+
alias_method :other, :satisfier
|
6
|
+
end
|
7
|
+
|
8
|
+
InvalidDependency = Struct.new(:package, :constraint) do
|
9
|
+
end
|
10
|
+
|
11
|
+
NoVersions = Struct.new(:constraint) do
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :terms, :cause
|
15
|
+
|
16
|
+
def initialize(terms, cause:)
|
17
|
+
@cause = cause
|
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
|
23
|
+
end
|
24
|
+
|
25
|
+
def hash
|
26
|
+
cause.hash ^ terms.hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql?(other)
|
30
|
+
cause.eql?(other.cause) &&
|
31
|
+
terms.eql?(other.terms)
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure?
|
35
|
+
terms.empty? || (terms.length == 1 && terms[0].package == Package.root && terms[0].positive?)
|
36
|
+
end
|
37
|
+
|
38
|
+
def conflict?
|
39
|
+
ConflictCause === cause
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns all external incompatibilities in this incompatibility's
|
43
|
+
# derivation graph
|
44
|
+
def external_incompatibilities
|
45
|
+
if conflict?
|
46
|
+
[
|
47
|
+
cause.conflict,
|
48
|
+
cause.other
|
49
|
+
].flat_map(&:external_incompatibilities)
|
50
|
+
else
|
51
|
+
[this]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
case cause
|
57
|
+
when :root
|
58
|
+
"(root dependency)"
|
59
|
+
when :dependency
|
60
|
+
"#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
|
61
|
+
when Gel::Vendor::PubGrub::Incompatibility::InvalidDependency
|
62
|
+
"#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
|
63
|
+
when Gel::Vendor::PubGrub::Incompatibility::NoVersions
|
64
|
+
"no versions satisfy #{cause.constraint}"
|
65
|
+
when Gel::Vendor::PubGrub::Incompatibility::ConflictCause
|
66
|
+
if failure?
|
67
|
+
"version solving has failed"
|
68
|
+
elsif terms.length == 1
|
69
|
+
term = terms[0]
|
70
|
+
if term.positive?
|
71
|
+
"#{terms[0].to_s(allow_every: true)} is forbidden"
|
72
|
+
else
|
73
|
+
"#{terms[0].invert} is required"
|
74
|
+
end
|
75
|
+
else
|
76
|
+
if terms.all?(&:positive?)
|
77
|
+
if terms.length == 2
|
78
|
+
"#{terms[0].to_s(allow_every: true)} is incompatible with #{terms[1]}"
|
79
|
+
else
|
80
|
+
"one of #{terms.map(&:to_s).join(" or ")} must be false"
|
81
|
+
end
|
82
|
+
elsif terms.all?(&:negative?)
|
83
|
+
if terms.length == 2
|
84
|
+
"either #{terms[0].invert} or #{terms[1].invert}"
|
85
|
+
else
|
86
|
+
"one of #{terms.map(&:invert).join(" or ")} must be true";
|
87
|
+
end
|
88
|
+
else
|
89
|
+
positive = terms.select(&:positive?)
|
90
|
+
negative = terms.select(&:negative?).map(&:invert)
|
91
|
+
|
92
|
+
if positive.length == 1
|
93
|
+
"#{positive[0].to_s(allow_every: true)} requires #{negative.join(" or ")}"
|
94
|
+
else
|
95
|
+
"if #{positive.join(" and ")} then #{negative.join(" or ")}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
else
|
100
|
+
raise "unhandled cause: #{cause.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def inspect
|
105
|
+
"#<#{self.class} #{to_s}>"
|
106
|
+
end
|
107
|
+
|
108
|
+
def pretty_print(q)
|
109
|
+
q.group 2, "#<#{self.class}", ">" do
|
110
|
+
q.breakable
|
111
|
+
q.text to_s
|
112
|
+
|
113
|
+
q.breakable
|
114
|
+
q.text " caused by "
|
115
|
+
q.pp @cause
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def cleanup_terms(terms)
|
122
|
+
terms.each do |term|
|
123
|
+
raise "#{term.inspect} must be a term" unless term.is_a?(Term)
|
124
|
+
end
|
125
|
+
|
126
|
+
if terms.length != 1 && ConflictCause === cause
|
127
|
+
terms = terms.reject do |term|
|
128
|
+
term.positive? && term.package == Package.root
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Optimized simple cases
|
133
|
+
return terms if terms.length <= 1
|
134
|
+
return terms if terms.length == 2 && terms[0].package != terms[1].package
|
135
|
+
|
136
|
+
terms.group_by(&:package).map do |package, common_terms|
|
137
|
+
common_terms.inject do |acc, term|
|
138
|
+
acc.intersect(term)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gel::Vendor::PubGrub
|
4
|
+
class Package
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"#<#{self.class} #{name.inspect}>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
name <=> other.name
|
18
|
+
end
|
19
|
+
|
20
|
+
ROOT = Package.new(:root)
|
21
|
+
ROOT_VERSION = 0
|
22
|
+
|
23
|
+
def self.root
|
24
|
+
ROOT
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.root_version
|
28
|
+
ROOT_VERSION
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
name.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require_relative '../pub_grub/assignment'
|
2
|
+
|
3
|
+
module Gel::Vendor::PubGrub
|
4
|
+
class PartialSolution
|
5
|
+
attr_reader :assignments, :decisions
|
6
|
+
attr_reader :attempted_solutions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
reset!
|
10
|
+
|
11
|
+
@attempted_solutions = 1
|
12
|
+
@backtracking = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def decision_level
|
16
|
+
@decisions.length
|
17
|
+
end
|
18
|
+
|
19
|
+
def relation(term)
|
20
|
+
package = term.package
|
21
|
+
return :overlap if !@terms.key?(package)
|
22
|
+
|
23
|
+
@relation_cache[package][term] ||=
|
24
|
+
@terms[package].relation(term)
|
25
|
+
end
|
26
|
+
|
27
|
+
def satisfies?(term)
|
28
|
+
relation(term) == :subset
|
29
|
+
end
|
30
|
+
|
31
|
+
def derive(term, cause)
|
32
|
+
add_assignment(Assignment.new(term, cause, decision_level, assignments.length))
|
33
|
+
end
|
34
|
+
|
35
|
+
def satisfier(term)
|
36
|
+
assignment =
|
37
|
+
@assignments_by[term.package].bsearch do |assignment_by|
|
38
|
+
@cumulative_assignments[assignment_by].satisfies?(term)
|
39
|
+
end
|
40
|
+
|
41
|
+
assignment || raise("#{term} unsatisfied")
|
42
|
+
end
|
43
|
+
|
44
|
+
# A list of unsatisfied terms
|
45
|
+
def unsatisfied
|
46
|
+
@required.keys.reject do |package|
|
47
|
+
@decisions.key?(package)
|
48
|
+
end.map do |package|
|
49
|
+
@terms[package]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def decide(package, version)
|
54
|
+
@attempted_solutions += 1 if @backtracking
|
55
|
+
@backtracking = false;
|
56
|
+
|
57
|
+
decisions[package] = version
|
58
|
+
assignment = Assignment.decision(package, version, decision_level, assignments.length)
|
59
|
+
add_assignment(assignment)
|
60
|
+
end
|
61
|
+
|
62
|
+
def backtrack(previous_level)
|
63
|
+
@backtracking = true
|
64
|
+
|
65
|
+
new_assignments = assignments.select do |assignment|
|
66
|
+
assignment.decision_level <= previous_level
|
67
|
+
end
|
68
|
+
|
69
|
+
new_decisions = Hash[decisions.first(previous_level)]
|
70
|
+
|
71
|
+
reset!
|
72
|
+
|
73
|
+
@decisions = new_decisions
|
74
|
+
|
75
|
+
new_assignments.each do |assignment|
|
76
|
+
add_assignment(assignment)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def reset!
|
83
|
+
# { Array<Assignment> }
|
84
|
+
@assignments = []
|
85
|
+
|
86
|
+
# { Package => Array<Assignment> }
|
87
|
+
@assignments_by = Hash.new { |h,k| h[k] = [] }
|
88
|
+
@cumulative_assignments = {}.compare_by_identity
|
89
|
+
|
90
|
+
# { Package => Package::Version }
|
91
|
+
@decisions = {}
|
92
|
+
|
93
|
+
# { Package => Term }
|
94
|
+
@terms = {}
|
95
|
+
@relation_cache = Hash.new { |h,k| h[k] = {} }
|
96
|
+
|
97
|
+
# { Package => Boolean }
|
98
|
+
@required = {}
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_assignment(assignment)
|
102
|
+
term = assignment.term
|
103
|
+
package = term.package
|
104
|
+
|
105
|
+
@assignments << assignment
|
106
|
+
@assignments_by[package] << assignment
|
107
|
+
|
108
|
+
@required[package] = true if term.positive?
|
109
|
+
|
110
|
+
if @terms.key?(package)
|
111
|
+
old_term = @terms[package]
|
112
|
+
@terms[package] = old_term.intersect(term)
|
113
|
+
else
|
114
|
+
@terms[package] = term
|
115
|
+
end
|
116
|
+
@relation_cache[package].clear
|
117
|
+
|
118
|
+
@cumulative_assignments[assignment] = @terms[package]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Gel::Vendor::PubGrub
|
2
|
+
module RubyGems
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def requirement_to_range(requirement)
|
6
|
+
ranges = requirement.requirements.map do |(op, ver)|
|
7
|
+
case op
|
8
|
+
when "~>"
|
9
|
+
name = "~> #{ver}"
|
10
|
+
bump = ver.class.new(ver.bump.to_s + ".A")
|
11
|
+
VersionRange.new(name: name, min: ver, max: bump, include_min: true)
|
12
|
+
when ">"
|
13
|
+
VersionRange.new(min: ver)
|
14
|
+
when ">="
|
15
|
+
VersionRange.new(min: ver, include_min: true)
|
16
|
+
when "<"
|
17
|
+
VersionRange.new(max: ver)
|
18
|
+
when "<="
|
19
|
+
VersionRange.new(max: ver, include_max: true)
|
20
|
+
when "="
|
21
|
+
VersionRange.new(min: ver, max: ver, include_min: true, include_max: true)
|
22
|
+
when "!="
|
23
|
+
VersionRange.new(min: ver, max: ver, include_min: true, include_max: true).invert
|
24
|
+
else
|
25
|
+
raise "bad version specifier: #{op}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ranges.inject(&:intersect)
|
30
|
+
end
|
31
|
+
|
32
|
+
def requirement_to_constraint(package, requirement)
|
33
|
+
Gel::Vendor::PubGrub::VersionConstraint.new(package, range: requirement_to_range(requirement))
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_range(dep)
|
37
|
+
requirement_to_range(Gem::Requirement.new(dep))
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_constraint(package, dep)
|
41
|
+
range = parse_range(dep)
|
42
|
+
Gel::Vendor::PubGrub::VersionConstraint.new(package, range: range)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../pub_grub/failure_writer'
|
2
|
+
|
3
|
+
module Gel::Vendor::PubGrub
|
4
|
+
class SolveFailure < StandardError
|
5
|
+
def initialize(incompatibility)
|
6
|
+
@incompatibility = incompatibility
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"Could not find compatible versions\n\n#{explanation}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def explanation
|
14
|
+
@explanation ||= FailureWriter.new(@incompatibility).write
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../pub_grub/package'
|
2
|
+
require_relative '../pub_grub/version_constraint'
|
3
|
+
require_relative '../pub_grub/incompatibility'
|
4
|
+
require_relative '../pub_grub/basic_package_source'
|
5
|
+
|
6
|
+
module Gel::Vendor::PubGrub
|
7
|
+
class StaticPackageSource < BasicPackageSource
|
8
|
+
class DSL
|
9
|
+
def initialize(packages, root_deps)
|
10
|
+
@packages = packages
|
11
|
+
@root_deps = root_deps
|
12
|
+
end
|
13
|
+
|
14
|
+
def root(deps:)
|
15
|
+
@root_deps.update(deps)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(name, version, deps: {})
|
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
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@root_deps = {}
|
28
|
+
@packages = {}
|
29
|
+
|
30
|
+
yield DSL.new(@packages, @root_deps)
|
31
|
+
|
32
|
+
super()
|
33
|
+
end
|
34
|
+
|
35
|
+
def all_versions_for(package)
|
36
|
+
@packages[package].keys
|
37
|
+
end
|
38
|
+
|
39
|
+
def root_dependencies
|
40
|
+
@root_deps
|
41
|
+
end
|
42
|
+
|
43
|
+
def dependencies_for(package, version)
|
44
|
+
@packages[package][version]
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_dependency(package, dependency)
|
48
|
+
return false unless @packages.key?(package)
|
49
|
+
|
50
|
+
Gel::Vendor::PubGrub::RubyGems.parse_constraint(package, dependency)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Gel::Vendor::PubGrub
|
2
|
+
class Term
|
3
|
+
attr_reader :package, :constraint, :positive
|
4
|
+
|
5
|
+
def initialize(constraint, positive)
|
6
|
+
@constraint = constraint
|
7
|
+
@package = @constraint.package
|
8
|
+
@positive = positive
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s(allow_every: false)
|
12
|
+
if positive
|
13
|
+
@constraint.to_s(allow_every: allow_every)
|
14
|
+
else
|
15
|
+
"not #{@constraint}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
constraint.hash ^ positive.hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def eql?(other)
|
24
|
+
positive == other.positive &&
|
25
|
+
constraint.eql?(other.constraint)
|
26
|
+
end
|
27
|
+
|
28
|
+
def invert
|
29
|
+
self.class.new(@constraint, !@positive)
|
30
|
+
end
|
31
|
+
alias_method :inverse, :invert
|
32
|
+
|
33
|
+
def intersect(other)
|
34
|
+
raise ArgumentError, "packages must match" if package != other.package
|
35
|
+
|
36
|
+
if positive? && other.positive?
|
37
|
+
self.class.new(constraint.intersect(other.constraint), true)
|
38
|
+
elsif negative? && other.negative?
|
39
|
+
self.class.new(constraint.union(other.constraint), false)
|
40
|
+
else
|
41
|
+
positive = positive? ? self : other
|
42
|
+
negative = negative? ? self : other
|
43
|
+
self.class.new(positive.constraint.intersect(negative.constraint.invert), true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def difference(other)
|
48
|
+
intersect(other.invert)
|
49
|
+
end
|
50
|
+
|
51
|
+
def relation(other)
|
52
|
+
if positive? && other.positive?
|
53
|
+
constraint.relation(other.constraint)
|
54
|
+
elsif negative? && other.positive?
|
55
|
+
if constraint.allows_all?(other.constraint)
|
56
|
+
:disjoint
|
57
|
+
else
|
58
|
+
:overlap
|
59
|
+
end
|
60
|
+
elsif positive? && other.negative?
|
61
|
+
if !other.constraint.allows_any?(constraint)
|
62
|
+
:subset
|
63
|
+
elsif other.constraint.allows_all?(constraint)
|
64
|
+
:disjoint
|
65
|
+
else
|
66
|
+
:overlap
|
67
|
+
end
|
68
|
+
elsif negative? && other.negative?
|
69
|
+
if constraint.allows_all?(other.constraint)
|
70
|
+
:subset
|
71
|
+
else
|
72
|
+
:overlap
|
73
|
+
end
|
74
|
+
else
|
75
|
+
raise
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def normalized_constraint
|
80
|
+
@normalized_constraint ||= positive ? constraint : constraint.invert
|
81
|
+
end
|
82
|
+
|
83
|
+
def satisfies?(other)
|
84
|
+
raise ArgumentError, "packages must match" unless package == other.package
|
85
|
+
|
86
|
+
relation(other) == :subset
|
87
|
+
end
|
88
|
+
|
89
|
+
def positive?
|
90
|
+
@positive
|
91
|
+
end
|
92
|
+
|
93
|
+
def negative?
|
94
|
+
!positive?
|
95
|
+
end
|
96
|
+
|
97
|
+
def empty?
|
98
|
+
@empty ||= normalized_constraint.empty?
|
99
|
+
end
|
100
|
+
|
101
|
+
def inspect
|
102
|
+
"#<#{self.class} #{self}>"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|