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
data/lib/gel/error.rb
CHANGED
@@ -41,39 +41,60 @@ end
|
|
41
41
|
# Define all UserError subclasses in this file. (Non-reportable errors,
|
42
42
|
# which describe errors in interaction between internal components, can
|
43
43
|
# and should be defined whereever they're used.)
|
44
|
+
#
|
45
|
+
# To support special cases where external API dictates a different
|
46
|
+
# superclass (e.g. an UnsatisfiedDependencyError must be a ::LoadError),
|
47
|
+
# while retaining most of the conveniences, it's also possible to
|
48
|
+
# include the Gel::UserError::Impl module directly.
|
44
49
|
class Gel::UserError < StandardError
|
45
|
-
|
50
|
+
module Impl
|
51
|
+
include Gel::ReportableError
|
46
52
|
|
47
|
-
|
48
|
-
|
53
|
+
def set_context(context)
|
54
|
+
@context = context
|
55
|
+
end
|
49
56
|
|
50
|
-
|
51
|
-
|
57
|
+
def [](key)
|
58
|
+
@context.fetch(key)
|
59
|
+
end
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
def message
|
62
|
+
self.class.name
|
63
|
+
end
|
56
64
|
|
57
|
-
|
58
|
-
|
59
|
-
end
|
65
|
+
def inner_backtrace
|
66
|
+
return [] unless cause
|
60
67
|
|
61
|
-
|
62
|
-
|
68
|
+
bt = cause.backtrace_locations
|
69
|
+
ignored_bt = backtrace_locations
|
63
70
|
|
64
|
-
|
65
|
-
|
71
|
+
while bt.last.to_s == ignored_bt.last.to_s
|
72
|
+
bt.pop
|
73
|
+
ignored_bt.pop
|
74
|
+
end
|
66
75
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
76
|
+
while bt.last.path == ignored_bt.last.path
|
77
|
+
bt.pop
|
78
|
+
end
|
71
79
|
|
72
|
-
|
73
|
-
bt.pop
|
80
|
+
bt
|
74
81
|
end
|
82
|
+
end
|
83
|
+
|
84
|
+
include Impl
|
85
|
+
|
86
|
+
def initialize(**context)
|
87
|
+
set_context context
|
88
|
+
super message
|
89
|
+
end
|
90
|
+
end
|
75
91
|
|
76
|
-
|
92
|
+
class Gel::LoadError < ::LoadError
|
93
|
+
include Gel::UserError::Impl
|
94
|
+
|
95
|
+
def initialize(**context)
|
96
|
+
set_context context
|
97
|
+
super message
|
77
98
|
end
|
78
99
|
end
|
79
100
|
|
@@ -122,6 +143,18 @@ module Gel::Error
|
|
122
143
|
end
|
123
144
|
end
|
124
145
|
|
146
|
+
class OutdatedLockfileError < Gel::UserError
|
147
|
+
def message
|
148
|
+
"Lockfile out of date; use 'gel lock' or 'gel install' to re-resolve"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class NoLockfileError < OutdatedLockfileError
|
153
|
+
def message
|
154
|
+
"Gemfile has not been resolved; use 'gel lock' or 'gel install' to resolve"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
125
158
|
class UnexpectedConfigError < Gel::UserError
|
126
159
|
def initialize(line:)
|
127
160
|
super
|
@@ -143,12 +176,32 @@ module Gel::Error
|
|
143
176
|
end
|
144
177
|
|
145
178
|
class ExtensionBuildError < Gel::UserError
|
146
|
-
def initialize(program_name:, exitstatus:)
|
179
|
+
def initialize(program_name:, exitstatus:, log:, abort: nil)
|
180
|
+
super
|
181
|
+
end
|
182
|
+
|
183
|
+
def message
|
184
|
+
if self[:exitstatus] == 1 && self[:abort]
|
185
|
+
abort_message = self[:abort]
|
186
|
+
|
187
|
+
if abort_message.include?("\n") || abort_message.size > 100
|
188
|
+
"#{self[:program_name].inspect} aborted:\n#{abort_message.gsub(/^/, " ")}"
|
189
|
+
else
|
190
|
+
"#{self[:program_name].inspect} aborted: #{abort_message.sub(/\A[\[({]?(?:error|err|abort|fatal)[\])}]?:?\s+/i, "")}"
|
191
|
+
end
|
192
|
+
else
|
193
|
+
"#{self[:program_name].inspect} exited with #{self[:exitstatus].inspect}"
|
194
|
+
end + "\n\nBuild log: #{self[:log]}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class ExtensionDependencyError < Gel::UserError
|
199
|
+
def initialize(dependency:, failure:)
|
147
200
|
super
|
148
201
|
end
|
149
202
|
|
150
203
|
def message
|
151
|
-
"#{self[:
|
204
|
+
"Depends on #{self[:dependency].inspect}, which failed to #{self[:failure]}"
|
152
205
|
end
|
153
206
|
end
|
154
207
|
|
@@ -202,9 +255,88 @@ module Gel::Error
|
|
202
255
|
end
|
203
256
|
end
|
204
257
|
|
258
|
+
class UnsatisfiableRubyVersionError < Gel::UserError
|
259
|
+
def initialize(name:, running:, attempted_platforms:)
|
260
|
+
super
|
261
|
+
end
|
262
|
+
|
263
|
+
def message
|
264
|
+
"None of the available #{self[:name].inspect} packages are compatible with Ruby version #{self[:running].inspect}. Found: #{self[:attempted_platforms].inspect}"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
class MissingGemError < Gel::UserError
|
269
|
+
def initialize(name:)
|
270
|
+
super
|
271
|
+
end
|
272
|
+
|
273
|
+
def message
|
274
|
+
"Missing gem #{self[:name].inspect}. Do you need to 'gel install'?"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class AlreadyActivatedError < Gel::LoadError
|
279
|
+
def initialize(name:, existing:, requirements: nil, requested: nil, why:)
|
280
|
+
raise ArgumentError, "exactly one of :requirements and :requested must be supplied" unless requirements.nil? != requested.nil?
|
281
|
+
super
|
282
|
+
end
|
283
|
+
|
284
|
+
def message
|
285
|
+
"Already activated #{self[:name].inspect} #{self[:existing]}" +
|
286
|
+
if self[:requirements]
|
287
|
+
", which is incompatible with: #{self[:requirements]}"
|
288
|
+
else
|
289
|
+
"; cannot also activate #{self[:requested]}"
|
290
|
+
end +
|
291
|
+
(self[:why] ? " (#{self[:why].join("; ")})" : "")
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
class UnsatisfiedDependencyError < Gel::LoadError
|
296
|
+
def initialize(name:, was_locked:, found_any:, requirements:, why:)
|
297
|
+
super
|
298
|
+
end
|
299
|
+
|
300
|
+
def message
|
301
|
+
if self[:was_locked]
|
302
|
+
if self[:found_any]
|
303
|
+
"Locked version of gem #{self[:name].inspect} does not satisfy requirements: #{self[:requirements]}"
|
304
|
+
else
|
305
|
+
"Gem #{self[:name].inspect} is not present in Gemfile; unable to satisfy requirements: #{self[:requirements]}"
|
306
|
+
end
|
307
|
+
else
|
308
|
+
if self[:found_any]
|
309
|
+
"No available version of gem #{self[:name].inspect} satisfies requirements: #{self[:requirements]}"
|
310
|
+
else
|
311
|
+
"No version of gem #{self[:name].inspect} is installed; unable to satisfy requirements: #{self[:requirements]}"
|
312
|
+
end
|
313
|
+
end + (self[:why] ? " (#{self[:why].join("; ")})" : "")
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class MissingExecutableError < Gel::UserError
|
318
|
+
def initialize(executable:, gem_name:, gem_versions:, locked_gem_version:)
|
319
|
+
super
|
320
|
+
end
|
321
|
+
|
322
|
+
def message
|
323
|
+
"Locked gem #{self[:gem_name].inspect} #{self[:locked_gem_version].inspect} does not supply executable #{self[:executable].inspect}. Found in other installed versions: #{self[:gem_versions].inspect}"
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
205
327
|
class ParsedGemspecError < Gel::UserError
|
206
328
|
def message
|
207
329
|
"Gemspec parse failed"
|
208
330
|
end
|
209
331
|
end
|
332
|
+
|
333
|
+
class GitResolveError < Gel::UserError
|
334
|
+
def initialize(remote:, ref:)
|
335
|
+
super
|
336
|
+
end
|
337
|
+
|
338
|
+
def message
|
339
|
+
"Unable to resolve #{self[:ref].inspect} in git repository #{self[:remote].inspect}"
|
340
|
+
end
|
341
|
+
end
|
210
342
|
end
|
data/lib/gel/gemfile_parser.rb
CHANGED
@@ -14,6 +14,29 @@ module Gel::GemfileParser
|
|
14
14
|
raise Gel::Error::GemfileEvaluationError.new(filename: filename)
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.inline(&block)
|
18
|
+
filename, _lineno = block.source_location
|
19
|
+
|
20
|
+
result = GemfileContent.new(filename)
|
21
|
+
context = ParseContext.new(result, filename)
|
22
|
+
context.instance_eval(&block)
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
class RunningRuby
|
27
|
+
def self.version
|
28
|
+
RUBY_VERSION
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.engine
|
32
|
+
RUBY_ENGINE
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.engine_version
|
36
|
+
RUBY_ENGINE_VERSION
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
17
40
|
class ParseContext
|
18
41
|
def initialize(result, filename)
|
19
42
|
@result = result
|
@@ -38,29 +61,40 @@ module Gel::GemfileParser
|
|
38
61
|
@result.git_sources[name] = block
|
39
62
|
end
|
40
63
|
|
41
|
-
def ruby(
|
42
|
-
req = Gel::Support::GemRequirement.new(
|
43
|
-
|
64
|
+
def ruby(*versions, engine: nil, engine_version: nil)
|
65
|
+
req = Gel::Support::GemRequirement.new(versions)
|
66
|
+
running_ruby_version = RunningRuby.version
|
67
|
+
running_engine = RunningRuby.engine
|
68
|
+
running_engine_version = RunningRuby.engine_version
|
69
|
+
|
70
|
+
unless req.satisfied_by?(Gel::Support::GemVersion.new(running_ruby_version))
|
44
71
|
raise Gel::Error::MismatchRubyVersionError.new(
|
45
|
-
running:
|
46
|
-
requested:
|
72
|
+
running: running_ruby_version,
|
73
|
+
requested: versions,
|
47
74
|
)
|
48
75
|
end
|
49
|
-
unless !engine ||
|
76
|
+
unless !engine || running_engine == engine
|
50
77
|
raise Gel::Error::MismatchRubyEngineError.new(
|
51
|
-
running:
|
78
|
+
running: running_engine,
|
52
79
|
engine: engine,
|
53
80
|
)
|
54
81
|
end
|
55
82
|
if engine_version
|
56
83
|
raise "Cannot specify :engine_version without :engine" unless engine
|
57
|
-
req = Gel::Support::GemRequirement.new(
|
58
|
-
raise "Running ruby engine version #{
|
84
|
+
req = Gel::Support::GemRequirement.new(engine_version)
|
85
|
+
raise "Running ruby engine version #{running_engine_version} does not match requested #{engine_version.inspect}" unless req.satisfied_by?(Gel::Support::GemVersion.new(running_engine_version))
|
59
86
|
end
|
60
|
-
@result.ruby << [
|
87
|
+
@result.ruby << [versions, engine: engine, engine_version: engine_version]
|
61
88
|
end
|
62
89
|
|
63
90
|
def gem(name, *requirements, **options)
|
91
|
+
aliases = GemfileContent::OPTION_ALIASES
|
92
|
+
options.keys.each do |key|
|
93
|
+
if original = aliases[key]
|
94
|
+
raise "Duplicate key #{key.inspect} == #{original.inspect}" if options.key?(original)
|
95
|
+
options[original] = options.delete(key)
|
96
|
+
end
|
97
|
+
end
|
64
98
|
options = @result.flatten(options, @stack)
|
65
99
|
@result.add_gem(name, requirements, options)
|
66
100
|
end
|
@@ -77,8 +111,8 @@ module Gel::GemfileParser
|
|
77
111
|
else
|
78
112
|
spec = gemspecs[0]
|
79
113
|
gem spec.name, path: path
|
80
|
-
spec.development_dependencies.each do |
|
81
|
-
gem
|
114
|
+
spec.development_dependencies.each do |dep_name, constraints|
|
115
|
+
gem dep_name, constraints, group: development_group
|
82
116
|
end
|
83
117
|
end
|
84
118
|
end
|
@@ -90,6 +124,20 @@ module Gel::GemfileParser
|
|
90
124
|
@stack.pop
|
91
125
|
end
|
92
126
|
|
127
|
+
def install_if(*conditions)
|
128
|
+
@stack << { install_if: conditions }
|
129
|
+
yield
|
130
|
+
ensure
|
131
|
+
@stack.pop
|
132
|
+
end
|
133
|
+
|
134
|
+
def path(*names)
|
135
|
+
@stack << { path: names }
|
136
|
+
yield
|
137
|
+
ensure
|
138
|
+
@stack.pop
|
139
|
+
end
|
140
|
+
|
93
141
|
def platforms(*names)
|
94
142
|
@stack << { platforms: names }
|
95
143
|
yield
|
@@ -99,6 +147,10 @@ module Gel::GemfileParser
|
|
99
147
|
end
|
100
148
|
|
101
149
|
class GemfileContent
|
150
|
+
OPTION_ALIASES = {
|
151
|
+
platform: :platforms,
|
152
|
+
}
|
153
|
+
|
102
154
|
attr_reader :filename
|
103
155
|
|
104
156
|
attr_reader :sources
|
@@ -133,6 +185,12 @@ module Gel::GemfileParser
|
|
133
185
|
raise "Only git sources can specify a :branch" if options[:branch] && !options[:git]
|
134
186
|
raise "Duplicate entry for gem #{name.inspect}" if @gems.assoc(name)
|
135
187
|
|
188
|
+
if options[:install_if]
|
189
|
+
options[:install_if] = Array(options[:install_if]).all? do |condition|
|
190
|
+
condition.respond_to?(:call) ? condition.call : condition
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
136
194
|
@gems << [name, requirements, options]
|
137
195
|
end
|
138
196
|
|
@@ -158,5 +216,9 @@ module Gel::GemfileParser
|
|
158
216
|
end
|
159
217
|
end
|
160
218
|
end
|
219
|
+
|
220
|
+
def gem_names
|
221
|
+
@gems.map(&:first).flatten.map(&:to_s)
|
222
|
+
end
|
161
223
|
end
|
162
224
|
end
|
data/lib/gel/gemspec_parser.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ostruct"
|
4
|
-
|
5
3
|
class Gel::GemspecParser
|
6
4
|
module Context
|
7
5
|
def self.context
|
@@ -30,16 +28,19 @@ class Gel::GemspecParser
|
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
|
-
class Result
|
31
|
+
class Result
|
34
32
|
def initialize
|
35
|
-
|
33
|
+
@values = {}
|
34
|
+
|
36
35
|
self.specification_version = nil
|
37
36
|
self.metadata = {}
|
38
37
|
self.requirements = []
|
39
38
|
self.rdoc_options = []
|
39
|
+
self.extra_rdoc_files = []
|
40
40
|
self.development_dependencies = []
|
41
41
|
self.runtime_dependencies = []
|
42
42
|
self.executables = []
|
43
|
+
self.extensions = []
|
43
44
|
end
|
44
45
|
|
45
46
|
def add_development_dependency(name, *versions)
|
@@ -50,6 +51,18 @@ class Gel::GemspecParser
|
|
50
51
|
runtime_dependencies << [name, versions.flatten]
|
51
52
|
end
|
52
53
|
alias add_dependency add_runtime_dependency
|
54
|
+
|
55
|
+
def method_missing(name, *args)
|
56
|
+
if name =~ /(.*)=$/
|
57
|
+
@values[$1.to_sym] = args.first
|
58
|
+
else
|
59
|
+
@values[name]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_to_missing?(name, *)
|
64
|
+
name != :marshal_dump && name != :_dump
|
65
|
+
end
|
53
66
|
end
|
54
67
|
|
55
68
|
def self.parse(content, filename, lineno = 1, root: File.dirname(filename), isolate: true)
|
@@ -60,13 +73,19 @@ class Gel::GemspecParser
|
|
60
73
|
in_read, in_write = IO.pipe
|
61
74
|
out_read, out_write = IO.pipe
|
62
75
|
|
63
|
-
pid = spawn({
|
76
|
+
pid = spawn({
|
77
|
+
"RUBYLIB" => Gel::Environment.modified_rubylib,
|
78
|
+
"RUBYOPT" => "",
|
79
|
+
"GEL_DEBUG" => nil,
|
80
|
+
"GEL_GEMFILE" => "",
|
81
|
+
"GEL_LOCKFILE" => "",
|
82
|
+
},
|
64
83
|
RbConfig.ruby,
|
65
84
|
"-r", File.expand_path("compatibility", __dir__),
|
66
85
|
"-r", File.expand_path("gemspec_parser", __dir__),
|
67
|
-
"-e", "
|
86
|
+
"-e", "IO.new(3, 'w').write Marshal.dump(Gel::GemspecParser.parse($stdin.read, ARGV.shift, ARGV.shift.to_i, root: ARGV.shift, isolate: false))",
|
68
87
|
filename, lineno.to_s, root,
|
69
|
-
in: in_read,
|
88
|
+
in: in_read, 3 => out_write)
|
70
89
|
|
71
90
|
in_read.close
|
72
91
|
out_write.close
|
data/lib/gel/git_catalog.rb
CHANGED
@@ -5,11 +5,12 @@ require_relative "path_catalog"
|
|
5
5
|
class Gel::GitCatalog
|
6
6
|
attr_reader :git_depot, :remote, :ref_type, :ref
|
7
7
|
|
8
|
-
def initialize(git_depot, remote, ref_type, ref)
|
8
|
+
def initialize(git_depot, remote, ref_type, ref, revision = nil)
|
9
9
|
@git_depot = git_depot
|
10
10
|
@remote = remote
|
11
11
|
@ref_type = ref_type
|
12
12
|
@ref = ref
|
13
|
+
@revision = revision
|
13
14
|
|
14
15
|
@monitor = Monitor.new
|
15
16
|
@result = nil
|
@@ -17,11 +18,18 @@ class Gel::GitCatalog
|
|
17
18
|
|
18
19
|
def checkout_result
|
19
20
|
@result ||
|
20
|
-
@monitor.synchronize
|
21
|
+
@monitor.synchronize do
|
22
|
+
@result ||=
|
23
|
+
if @revision
|
24
|
+
[@revision, git_depot.checkout(remote, @revision)]
|
25
|
+
else
|
26
|
+
git_depot.resolve_and_checkout(remote, ref)
|
27
|
+
end
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
def revision
|
24
|
-
checkout_result[0]
|
32
|
+
@revision || checkout_result[0]
|
25
33
|
end
|
26
34
|
|
27
35
|
def gem_info(name)
|
@@ -35,4 +43,8 @@ class Gel::GitCatalog
|
|
35
43
|
def prepare
|
36
44
|
checkout_result
|
37
45
|
end
|
46
|
+
|
47
|
+
def path
|
48
|
+
git_depot.git_path(remote, revision)
|
49
|
+
end
|
38
50
|
end
|
data/lib/gel/git_depot.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "vendor/ruby_digest"
|
4
|
+
|
3
5
|
class Gel::GitDepot
|
4
6
|
attr_reader :mirror_root
|
5
7
|
|
6
|
-
require "logger"
|
7
|
-
Logger = ::Logger.new($stderr)
|
8
|
-
Logger.level = $DEBUG ? ::Logger::DEBUG : ::Logger::WARN
|
9
|
-
|
10
8
|
def initialize(store, mirror_root = (ENV["GEL_CACHE"] || "~/.cache/gel") + "/git")
|
11
9
|
@store = store
|
12
10
|
@mirror_root = File.expand_path(mirror_root)
|
@@ -40,15 +38,42 @@ class Gel::GitDepot
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def resolve(remote, ref)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
if ref
|
42
|
+
# ref could be an arbitrarily-complex ref (HEAD~3 or whatever), so
|
43
|
+
# update our mirror and then resolve it locally
|
44
|
+
|
45
|
+
mirror = remote(remote) { false } # always update mirror
|
46
|
+
|
47
|
+
r, w = IO.pipe
|
48
|
+
status = git(remote, "rev-parse", ref || "HEAD", chdir: mirror, out: w)
|
49
|
+
w.close
|
50
|
+
|
51
|
+
if status.success?
|
52
|
+
r.read.chomp
|
53
|
+
else
|
54
|
+
# We didn't keep stderr, but we can infer the nature of the problem
|
55
|
+
# from whether git produced any output: for simple "I don't know what
|
56
|
+
# that is" errors, it returns the input, while more fundamental
|
57
|
+
# problems die earlier and return nothing.
|
58
|
+
if r.read.chomp.empty?
|
59
|
+
# This is an internal error: our mirror must be broken
|
60
|
+
raise "git rev-parse failed"
|
61
|
+
else
|
62
|
+
# This is a user error: the ref doesn't exist
|
63
|
+
raise Gel::Error::GitResolveError.new(remote: remote, ref: ref)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# If we just want to know the remote HEAD, we can ask without even
|
68
|
+
# touching our mirror
|
48
69
|
|
49
|
-
|
70
|
+
r, w = IO.pipe
|
71
|
+
status = git(remote, "ls-remote", remote, "HEAD", out: w)
|
72
|
+
raise "git ls-remote failed" unless status.success?
|
50
73
|
|
51
|
-
|
74
|
+
w.close
|
75
|
+
r.read.split.first
|
76
|
+
end
|
52
77
|
end
|
53
78
|
|
54
79
|
def resolve_and_checkout(remote, ref)
|
@@ -84,36 +109,45 @@ class Gel::GitDepot
|
|
84
109
|
|
85
110
|
t = Time.now
|
86
111
|
pid = spawn("git", *arguments, **kwargs)
|
87
|
-
logger
|
112
|
+
logger&.debug { "#{remote} [#{pid}] #{command_for_log("git", *arguments)}" }
|
88
113
|
|
89
114
|
_, status = Process.waitpid2(pid)
|
90
|
-
logger
|
115
|
+
logger&.debug { "#{remote} [#{pid}] process exited #{status.exitstatus} (#{status.success? ? "success" : "failure"}) after #{Time.now - t}s" }
|
91
116
|
|
92
117
|
status
|
93
118
|
end
|
94
119
|
|
95
120
|
def ident(remote)
|
96
121
|
short = File.basename(remote, ".git")
|
97
|
-
digest =
|
122
|
+
digest = Gel::Vendor::RubyDigest::SHA256.hexdigest(remote)[0..12]
|
98
123
|
"#{short}-#{digest}"
|
99
124
|
end
|
100
125
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
word
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
126
|
+
if $DEBUG
|
127
|
+
require "shellwords"
|
128
|
+
def shellword(word)
|
129
|
+
if word =~ /\A[A-Za-z0-9=+\/,.-]+\z/
|
130
|
+
word
|
131
|
+
elsif word =~ /'/
|
132
|
+
"\"#{Shellwords.shellescape(word).gsub(/\\\s/, "\\1")}\""
|
133
|
+
else
|
134
|
+
"'#{word}'"
|
135
|
+
end
|
109
136
|
end
|
110
|
-
end
|
111
137
|
|
112
|
-
|
113
|
-
|
114
|
-
|
138
|
+
def command_for_log(*parts)
|
139
|
+
parts.map { |part| shellword(part) }.join(" ")
|
140
|
+
end
|
115
141
|
|
116
|
-
|
117
|
-
Logger
|
142
|
+
require "logger"
|
143
|
+
Logger = ::Logger.new($stderr)
|
144
|
+
Logger.level = ::Logger::DEBUG
|
145
|
+
|
146
|
+
def logger
|
147
|
+
Logger
|
148
|
+
end
|
149
|
+
else
|
150
|
+
def logger
|
151
|
+
end
|
118
152
|
end
|
119
153
|
end
|
data/lib/gel/httpool.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "monitor"
|
4
|
-
require "net/http"
|
5
4
|
|
6
5
|
class Gel::Httpool
|
7
6
|
include MonitorMixin
|
@@ -25,7 +24,11 @@ class Gel::Httpool
|
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
|
-
def request(uri, request =
|
27
|
+
def request(uri, request = nil)
|
28
|
+
require "net/http"
|
29
|
+
|
30
|
+
request ||= Net::HTTP::Get.new(uri)
|
31
|
+
|
29
32
|
with_connection(uri) do |http|
|
30
33
|
logger.debug { "GET #{uri}" }
|
31
34
|
|