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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -3
  3. data/RELEASING.md +12 -0
  4. data/exe/gel +4 -2
  5. data/gemlib/gel/stub.rb +20 -0
  6. data/lib/gel/catalog/common.rb +4 -2
  7. data/lib/gel/catalog/compact_index.rb +6 -10
  8. data/lib/gel/catalog/dependency_index.rb +10 -10
  9. data/lib/gel/catalog/legacy_index.rb +4 -6
  10. data/lib/gel/catalog/marshal_hacks.rb +2 -0
  11. data/lib/gel/catalog.rb +33 -52
  12. data/lib/gel/catalog_set.rb +100 -0
  13. data/lib/gel/command/help.rb +13 -2
  14. data/lib/gel/command/lock.rb +3 -3
  15. data/lib/gel/command/open.rb +24 -0
  16. data/lib/gel/command/shell_setup.rb +11 -8
  17. data/lib/gel/command/stub.rb +45 -2
  18. data/lib/gel/command/version.rb +7 -0
  19. data/lib/gel/command.rb +43 -6
  20. data/lib/gel/compatibility/rubygems.rb +10 -197
  21. data/lib/gel/compatibility.rb +2 -2
  22. data/lib/gel/config.rb +41 -7
  23. data/lib/gel/db.rb +93 -83
  24. data/lib/gel/direct_gem.rb +16 -4
  25. data/lib/gel/environment.rb +542 -249
  26. data/lib/gel/error.rb +156 -24
  27. data/lib/gel/gemfile_parser.rb +74 -12
  28. data/lib/gel/gemspec_parser.rb +26 -7
  29. data/lib/gel/git_catalog.rb +15 -3
  30. data/lib/gel/git_depot.rb +62 -28
  31. data/lib/gel/httpool.rb +5 -2
  32. data/lib/gel/installer.rb +61 -23
  33. data/lib/gel/lock_loader.rb +87 -112
  34. data/lib/gel/lock_parser.rb +23 -31
  35. data/lib/gel/locked_store.rb +30 -21
  36. data/lib/gel/multi_store.rb +13 -4
  37. data/lib/gel/null_solver.rb +67 -0
  38. data/lib/gel/package/abortable.rb +18 -0
  39. data/lib/gel/package/installer.rb +124 -49
  40. data/lib/gel/package.rb +21 -4
  41. data/lib/gel/path_catalog.rb +1 -1
  42. data/lib/gel/pinboard.rb +4 -2
  43. data/lib/gel/platform.rb +38 -0
  44. data/lib/gel/pub_grub/package.rb +67 -0
  45. data/lib/gel/pub_grub/preference_strategy.rb +10 -6
  46. data/lib/gel/pub_grub/solver.rb +37 -0
  47. data/lib/gel/pub_grub/source.rb +64 -92
  48. data/lib/gel/resolved_gem_set.rb +234 -0
  49. data/lib/gel/runtime.rb +3 -3
  50. data/lib/gel/set.rb +62 -0
  51. data/lib/gel/stdlib.rb +83 -0
  52. data/lib/gel/store.rb +94 -25
  53. data/lib/gel/store_catalog.rb +2 -2
  54. data/lib/gel/store_gem.rb +54 -6
  55. data/lib/gel/stub_set.rb +32 -2
  56. data/lib/gel/support/cgi_escape.rb +34 -0
  57. data/lib/gel/support/gem_platform.rb +0 -2
  58. data/lib/gel/support/sha512.rb +142 -0
  59. data/lib/gel/support/tar/tar_writer.rb +2 -2
  60. data/lib/gel/tail_file.rb +2 -1
  61. data/lib/gel/util.rb +108 -0
  62. data/lib/gel/vendor/pstore.rb +3 -0
  63. data/lib/gel/vendor/pub_grub.rb +3 -0
  64. data/lib/gel/vendor/ruby_digest.rb +3 -0
  65. data/lib/gel/vendor_catalog.rb +38 -0
  66. data/lib/gel/version.rb +1 -1
  67. data/lib/gel.rb +15 -0
  68. data/man/man1/gel-exec.1 +1 -1
  69. data/man/man1/gel-install.1 +1 -1
  70. data/man/man1/gel.1 +14 -1
  71. data/{lib/gel/compatibility → slib}/bundler/cli.rb +0 -0
  72. data/{lib/gel/compatibility → slib}/bundler/friendly_errors.rb +0 -0
  73. data/{lib/gel/compatibility/rubygems/dependency_installer.rb → slib/bundler/gem_helper.rb} +0 -0
  74. data/slib/bundler/gem_tasks.rb +0 -0
  75. data/{lib/gel/compatibility → slib}/bundler/setup.rb +0 -0
  76. data/{lib/gel/compatibility → slib}/bundler.rb +39 -3
  77. data/{lib/gel/compatibility → slib}/rubygems/command.rb +0 -0
  78. data/slib/rubygems/dependency_installer.rb +12 -0
  79. data/{lib/gel/compatibility → slib}/rubygems/gem_runner.rb +0 -0
  80. data/slib/rubygems/package.rb +6 -0
  81. data/slib/rubygems/package_task.rb +7 -0
  82. data/slib/rubygems/specification.rb +0 -0
  83. data/slib/rubygems/version.rb +0 -0
  84. data/slib/rubygems.rb +297 -0
  85. data/vendor/pstore/LICENSE.txt +22 -0
  86. data/vendor/pstore/lib/pstore.rb +488 -0
  87. data/vendor/pub_grub/LICENSE.txt +21 -0
  88. data/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
  89. data/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +183 -0
  90. data/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
  91. data/vendor/pub_grub/lib/pub_grub/incompatibility.rb +143 -0
  92. data/vendor/pub_grub/lib/pub_grub/package.rb +35 -0
  93. data/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
  94. data/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
  95. data/vendor/pub_grub/lib/pub_grub/solve_failure.rb +17 -0
  96. data/vendor/pub_grub/lib/pub_grub/static_package_source.rb +53 -0
  97. data/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
  98. data/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
  99. data/vendor/pub_grub/lib/pub_grub/version_constraint.rb +124 -0
  100. data/vendor/pub_grub/lib/pub_grub/version_range.rb +399 -0
  101. data/vendor/pub_grub/lib/pub_grub/version_solver.rb +247 -0
  102. data/vendor/pub_grub/lib/pub_grub/version_union.rb +174 -0
  103. data/vendor/pub_grub/lib/pub_grub.rb +31 -0
  104. data/vendor/ruby-digest/UNLICENSE +24 -0
  105. data/vendor/ruby-digest/lib/ruby_digest.rb +812 -0
  106. metadata +95 -19
@@ -0,0 +1,247 @@
1
+ require_relative '../pub_grub/partial_solution'
2
+ require_relative '../pub_grub/term'
3
+ require_relative '../pub_grub/incompatibility'
4
+ require_relative '../pub_grub/solve_failure'
5
+
6
+ module Gel::Vendor::PubGrub
7
+ class VersionSolver
8
+ attr_reader :logger
9
+ attr_reader :source
10
+ attr_reader :solution
11
+
12
+ def initialize(source:, root: Package.root, logger: Gel::Vendor::PubGrub.logger)
13
+ @logger = logger
14
+
15
+ @source = source
16
+
17
+ # { package => [incompatibility, ...]}
18
+ @incompatibilities = Hash.new do |h, k|
19
+ h[k] = []
20
+ end
21
+
22
+ @seen_incompatibilities = {}
23
+
24
+ @solution = PartialSolution.new
25
+
26
+ @package_depth = { root => 0 }
27
+
28
+ add_incompatibility Incompatibility.new([
29
+ Term.new(VersionConstraint.any(root), false)
30
+ ], cause: :root)
31
+
32
+ propagate(root)
33
+ end
34
+
35
+ def solved?
36
+ solution.unsatisfied.empty?
37
+ end
38
+
39
+ # Returns true if there is more work to be done, false otherwise
40
+ def work
41
+ return false if solved?
42
+
43
+ next_package = choose_package_version
44
+ propagate(next_package)
45
+
46
+ if solved?
47
+ logger.info { "Solution found after #{solution.attempted_solutions} attempts:" }
48
+ solution.decisions.each do |package, version|
49
+ next if package == Package.root
50
+ logger.info { "* #{package} #{version}" }
51
+ end
52
+
53
+ false
54
+ else
55
+ true
56
+ end
57
+ end
58
+
59
+ def solve
60
+ work until solved?
61
+
62
+ solution.decisions
63
+ end
64
+
65
+ alias_method :result, :solve
66
+
67
+ private
68
+
69
+ def propagate(initial_package)
70
+ changed = [initial_package]
71
+ while package = changed.shift
72
+ @incompatibilities[package].reverse_each do |incompatibility|
73
+ result = propagate_incompatibility(incompatibility)
74
+ if result == :conflict
75
+ root_cause = resolve_conflict(incompatibility)
76
+ changed.clear
77
+ changed << propagate_incompatibility(root_cause)
78
+ elsif result # should be a Package
79
+ changed << result
80
+ end
81
+ end
82
+ changed.uniq!
83
+ end
84
+ end
85
+
86
+ def propagate_incompatibility(incompatibility)
87
+ unsatisfied = nil
88
+ incompatibility.terms.each do |term|
89
+ relation = solution.relation(term)
90
+ if relation == :disjoint
91
+ return nil
92
+ elsif relation == :overlap
93
+ # If more than one term is inconclusive, we can't deduce anything
94
+ return nil if unsatisfied
95
+ unsatisfied = term
96
+ end
97
+ end
98
+
99
+ if !unsatisfied
100
+ return :conflict
101
+ end
102
+
103
+ logger.debug { "derived: #{unsatisfied.invert}" }
104
+
105
+ solution.derive(unsatisfied.invert, incompatibility)
106
+
107
+ unsatisfied.package
108
+ end
109
+
110
+ def next_package_to_try
111
+ solution.unsatisfied.min_by do |term|
112
+ package = term.package
113
+ versions = source.versions_for(package, term.constraint.range)
114
+
115
+ [@package_depth[package], versions.count]
116
+ end.package
117
+ end
118
+
119
+ def choose_package_version
120
+ if solution.unsatisfied.empty?
121
+ logger.info "No packages unsatisfied. Solving complete!"
122
+ return nil
123
+ end
124
+
125
+ package = next_package_to_try
126
+ unsatisfied_term = solution.unsatisfied.find { |t| t.package == package }
127
+ version = source.versions_for(package, unsatisfied_term.constraint.range).first
128
+
129
+ if version.nil?
130
+ cause = Incompatibility::NoVersions.new(unsatisfied_term)
131
+ add_incompatibility Incompatibility.new([unsatisfied_term], cause: cause)
132
+ return package
133
+ end
134
+
135
+ conflict = false
136
+
137
+ source.incompatibilities_for(package, version).each do |incompatibility|
138
+ if @seen_incompatibilities.include?(incompatibility)
139
+ logger.debug { "knew: #{incompatibility}" }
140
+ next
141
+ end
142
+ @seen_incompatibilities[incompatibility] = true
143
+
144
+ add_incompatibility incompatibility
145
+
146
+ conflict ||= incompatibility.terms.all? do |term|
147
+ term.package == package || solution.satisfies?(term)
148
+ end
149
+
150
+ # Update depths of new packages
151
+ depth = @package_depth[package] + 1
152
+ incompatibility.terms.each do |term|
153
+ @package_depth[term.package] ||= depth
154
+ end
155
+ end
156
+
157
+ unless conflict
158
+ logger.info { "selecting #{package} #{version}" }
159
+
160
+ solution.decide(package, version)
161
+ end
162
+
163
+ package
164
+ end
165
+
166
+ def resolve_conflict(incompatibility)
167
+ logger.info { "conflict: #{incompatibility}" }
168
+
169
+ new_incompatibility = false
170
+
171
+ while !incompatibility.failure?
172
+ most_recent_term = nil
173
+ most_recent_satisfier = nil
174
+ difference = nil
175
+
176
+ previous_level = 1
177
+
178
+ incompatibility.terms.each do |term|
179
+ satisfier = solution.satisfier(term)
180
+
181
+ if most_recent_satisfier.nil?
182
+ most_recent_term = term
183
+ most_recent_satisfier = satisfier
184
+ elsif most_recent_satisfier.index < satisfier.index
185
+ previous_level = [previous_level, most_recent_satisfier.decision_level].max
186
+ most_recent_term = term
187
+ most_recent_satisfier = satisfier
188
+ difference = nil
189
+ else
190
+ previous_level = [previous_level, satisfier.decision_level].max
191
+ end
192
+
193
+ if most_recent_term == term
194
+ difference = most_recent_satisfier.term.difference(most_recent_term)
195
+ if difference.empty?
196
+ difference = nil
197
+ else
198
+ difference_satisfier = solution.satisfier(difference.inverse)
199
+ previous_level = [previous_level, difference_satisfier.decision_level].max
200
+ end
201
+ end
202
+ end
203
+
204
+ if previous_level < most_recent_satisfier.decision_level ||
205
+ most_recent_satisfier.decision?
206
+
207
+ logger.info { "backtracking to #{previous_level}" }
208
+ solution.backtrack(previous_level)
209
+
210
+ if new_incompatibility
211
+ add_incompatibility(incompatibility)
212
+ end
213
+
214
+ return incompatibility
215
+ end
216
+
217
+ new_terms = []
218
+ new_terms += incompatibility.terms - [most_recent_term]
219
+ new_terms += most_recent_satisfier.cause.terms.reject { |term|
220
+ term.package == most_recent_satisfier.term.package
221
+ }
222
+ if difference
223
+ new_terms << difference.invert
224
+ end
225
+
226
+ incompatibility = Incompatibility.new(new_terms, cause: Incompatibility::ConflictCause.new(incompatibility, most_recent_satisfier.cause))
227
+
228
+ new_incompatibility = true
229
+
230
+ partially = difference ? " partially" : ""
231
+ logger.info { "! #{most_recent_term} is#{partially} satisfied by #{most_recent_satisfier.term}" }
232
+ logger.info { "! which is caused by #{most_recent_satisfier.cause}" }
233
+ logger.info { "! thus #{incompatibility}" }
234
+ end
235
+
236
+ raise SolveFailure.new(incompatibility)
237
+ end
238
+
239
+ def add_incompatibility(incompatibility)
240
+ logger.debug { "fact: #{incompatibility}" }
241
+ incompatibility.terms.each do |term|
242
+ package = term.package
243
+ @incompatibilities[package] << incompatibility
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gel::Vendor::PubGrub
4
+ class VersionUnion
5
+ attr_reader :ranges
6
+
7
+ def self.normalize_ranges(ranges)
8
+ ranges = ranges.flat_map do |range|
9
+ range.ranges
10
+ end
11
+
12
+ ranges.reject!(&:empty?)
13
+
14
+ return [] if ranges.empty?
15
+
16
+ mins, ranges = ranges.partition { |r| !r.min }
17
+ original_ranges = mins + ranges.sort_by { |r| [r.min, r.include_min ? 0 : 1] }
18
+ ranges = [original_ranges.shift]
19
+ original_ranges.each do |range|
20
+ if ranges.last.contiguous_to?(range)
21
+ ranges << ranges.pop.span(range)
22
+ else
23
+ ranges << range
24
+ end
25
+ end
26
+
27
+ ranges
28
+ end
29
+
30
+ def self.union(ranges, normalize: true)
31
+ ranges = normalize_ranges(ranges) if normalize
32
+
33
+ if ranges.size == 0
34
+ VersionRange.empty
35
+ elsif ranges.size == 1
36
+ ranges[0]
37
+ else
38
+ new(ranges)
39
+ end
40
+ end
41
+
42
+ def initialize(ranges)
43
+ raise ArgumentError unless ranges.all? { |r| r.instance_of?(VersionRange) }
44
+ @ranges = ranges
45
+ end
46
+
47
+ def hash
48
+ ranges.hash
49
+ end
50
+
51
+ def eql?(other)
52
+ ranges.eql?(other.ranges)
53
+ end
54
+
55
+ def include?(version)
56
+ !!ranges.bsearch {|r| r.compare_version(version) }
57
+ end
58
+
59
+ def select_versions(all_versions)
60
+ versions = []
61
+ ranges.inject(all_versions) do |acc, range|
62
+ _, matching, higher = range.partition_versions(acc)
63
+ versions.concat matching
64
+ higher
65
+ end
66
+ versions
67
+ end
68
+
69
+ def intersects?(other)
70
+ my_ranges = ranges.dup
71
+ other_ranges = other.ranges.dup
72
+
73
+ my_range = my_ranges.shift
74
+ other_range = other_ranges.shift
75
+ while my_range && other_range
76
+ if my_range.intersects?(other_range)
77
+ return true
78
+ end
79
+
80
+ if !my_range.max || (other_range.max && other_range.max < my_range.max)
81
+ other_range = other_ranges.shift
82
+ else
83
+ my_range = my_ranges.shift
84
+ end
85
+ end
86
+ end
87
+ alias_method :allows_any?, :intersects?
88
+
89
+ def allows_all?(other)
90
+ my_ranges = ranges.dup
91
+
92
+ my_range = my_ranges.shift
93
+
94
+ other.ranges.all? do |other_range|
95
+ while my_range
96
+ break if my_range.allows_all?(other_range)
97
+ my_range = my_ranges.shift
98
+ end
99
+
100
+ !!my_range
101
+ end
102
+ end
103
+
104
+ def empty?
105
+ false
106
+ end
107
+
108
+ def any?
109
+ false
110
+ end
111
+
112
+ def intersect(other)
113
+ my_ranges = ranges.dup
114
+ other_ranges = other.ranges.dup
115
+ new_ranges = []
116
+
117
+ my_range = my_ranges.shift
118
+ other_range = other_ranges.shift
119
+ while my_range && other_range
120
+ new_ranges << my_range.intersect(other_range)
121
+
122
+ if !my_range.max || (other_range.max && other_range.max < my_range.max)
123
+ other_range = other_ranges.shift
124
+ else
125
+ my_range = my_ranges.shift
126
+ end
127
+ end
128
+ new_ranges.reject!(&:empty?)
129
+ VersionUnion.union(new_ranges, normalize: false)
130
+ end
131
+
132
+ def invert
133
+ ranges.map(&:invert).inject(:intersect)
134
+ end
135
+
136
+ def union(other)
137
+ VersionUnion.union([self, other])
138
+ end
139
+
140
+ def to_s
141
+ output = []
142
+
143
+ ranges = self.ranges.dup
144
+ while !ranges.empty?
145
+ ne = []
146
+ range = ranges.shift
147
+ while !ranges.empty? && ranges[0].min == range.max
148
+ ne << range.max
149
+ range = range.span(ranges.shift)
150
+ end
151
+
152
+ ne.map! {|x| "!= #{x}" }
153
+ if ne.empty?
154
+ output << range.to_s
155
+ elsif range.any?
156
+ output << ne.join(', ')
157
+ else
158
+ output << "#{range}, #{ne.join(', ')}"
159
+ end
160
+ end
161
+
162
+ output.join(" OR ")
163
+ end
164
+
165
+ def inspect
166
+ "#<#{self.class} #{to_s}>"
167
+ end
168
+
169
+ def ==(other)
170
+ self.class == other.class &&
171
+ self.ranges == other.ranges
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "pub_grub/package"
2
+ require_relative "pub_grub/static_package_source"
3
+ require_relative "pub_grub/term"
4
+ require_relative "pub_grub/version_range"
5
+ require_relative "pub_grub/version_constraint"
6
+ require_relative "pub_grub/version_union"
7
+ require_relative "pub_grub/version_solver"
8
+ require_relative "pub_grub/incompatibility"
9
+ require_relative 'pub_grub/solve_failure'
10
+ require_relative 'pub_grub/failure_writer'
11
+ require_relative 'pub_grub/version'
12
+
13
+ module Gel::Vendor::PubGrub
14
+ class << self
15
+ attr_writer :logger
16
+
17
+ def logger
18
+ @logger || default_logger
19
+ end
20
+
21
+ private
22
+
23
+ def default_logger
24
+ require "logger"
25
+
26
+ logger = ::Logger.new(STDERR)
27
+ logger.level = $DEBUG ? ::Logger::DEBUG : ::Logger::WARN
28
+ @logger = logger
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>