gel 0.2.0

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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +39 -0
  5. data/exe/gel +13 -0
  6. data/lib/gel.rb +22 -0
  7. data/lib/gel/catalog.rb +153 -0
  8. data/lib/gel/catalog/common.rb +82 -0
  9. data/lib/gel/catalog/compact_index.rb +152 -0
  10. data/lib/gel/catalog/dependency_index.rb +125 -0
  11. data/lib/gel/catalog/legacy_index.rb +157 -0
  12. data/lib/gel/catalog/marshal_hacks.rb +16 -0
  13. data/lib/gel/command.rb +86 -0
  14. data/lib/gel/command/config.rb +11 -0
  15. data/lib/gel/command/env.rb +7 -0
  16. data/lib/gel/command/exec.rb +66 -0
  17. data/lib/gel/command/help.rb +7 -0
  18. data/lib/gel/command/install.rb +7 -0
  19. data/lib/gel/command/install_gem.rb +16 -0
  20. data/lib/gel/command/lock.rb +34 -0
  21. data/lib/gel/command/ruby.rb +10 -0
  22. data/lib/gel/command/shell_setup.rb +25 -0
  23. data/lib/gel/command/stub.rb +12 -0
  24. data/lib/gel/command/update.rb +11 -0
  25. data/lib/gel/compatibility.rb +4 -0
  26. data/lib/gel/compatibility/bundler.rb +54 -0
  27. data/lib/gel/compatibility/bundler/cli.rb +6 -0
  28. data/lib/gel/compatibility/bundler/friendly_errors.rb +3 -0
  29. data/lib/gel/compatibility/bundler/setup.rb +4 -0
  30. data/lib/gel/compatibility/rubygems.rb +192 -0
  31. data/lib/gel/compatibility/rubygems/command.rb +4 -0
  32. data/lib/gel/compatibility/rubygems/dependency_installer.rb +0 -0
  33. data/lib/gel/compatibility/rubygems/gem_runner.rb +6 -0
  34. data/lib/gel/config.rb +80 -0
  35. data/lib/gel/db.rb +294 -0
  36. data/lib/gel/direct_gem.rb +29 -0
  37. data/lib/gel/environment.rb +592 -0
  38. data/lib/gel/error.rb +104 -0
  39. data/lib/gel/gemfile_parser.rb +144 -0
  40. data/lib/gel/gemspec_parser.rb +95 -0
  41. data/lib/gel/git_catalog.rb +38 -0
  42. data/lib/gel/git_depot.rb +119 -0
  43. data/lib/gel/httpool.rb +148 -0
  44. data/lib/gel/installer.rb +251 -0
  45. data/lib/gel/lock_loader.rb +164 -0
  46. data/lib/gel/lock_parser.rb +64 -0
  47. data/lib/gel/locked_store.rb +126 -0
  48. data/lib/gel/multi_store.rb +96 -0
  49. data/lib/gel/package.rb +156 -0
  50. data/lib/gel/package/inspector.rb +23 -0
  51. data/lib/gel/package/installer.rb +267 -0
  52. data/lib/gel/path_catalog.rb +44 -0
  53. data/lib/gel/pinboard.rb +140 -0
  54. data/lib/gel/pub_grub/preference_strategy.rb +82 -0
  55. data/lib/gel/pub_grub/source.rb +153 -0
  56. data/lib/gel/runtime.rb +27 -0
  57. data/lib/gel/store.rb +205 -0
  58. data/lib/gel/store_catalog.rb +31 -0
  59. data/lib/gel/store_gem.rb +80 -0
  60. data/lib/gel/stub_set.rb +51 -0
  61. data/lib/gel/support/gem_platform.rb +225 -0
  62. data/lib/gel/support/gem_requirement.rb +264 -0
  63. data/lib/gel/support/gem_version.rb +398 -0
  64. data/lib/gel/support/tar.rb +13 -0
  65. data/lib/gel/support/tar/tar_header.rb +229 -0
  66. data/lib/gel/support/tar/tar_reader.rb +123 -0
  67. data/lib/gel/support/tar/tar_reader/entry.rb +154 -0
  68. data/lib/gel/support/tar/tar_writer.rb +339 -0
  69. data/lib/gel/tail_file.rb +205 -0
  70. data/lib/gel/version.rb +5 -0
  71. data/lib/gel/work_pool.rb +143 -0
  72. data/man/man1/gel-exec.1 +16 -0
  73. data/man/man1/gel-install.1 +16 -0
  74. data/man/man1/gel.1 +30 -0
  75. metadata +131 -0
@@ -0,0 +1,123 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+ #--
4
+ # Copyright (C) 2004 Mauricio Julio Fernández Pradier
5
+ # Redistributed under the terms of the MIT license.
6
+ #++
7
+
8
+ ##
9
+ # TarReader reads tar files and allows iteration over their items
10
+
11
+ class Gel::Support::Tar::TarReader
12
+
13
+ include Enumerable
14
+
15
+ ##
16
+ # Raised if the tar IO is not seekable
17
+
18
+ class UnexpectedEOF < StandardError; end
19
+
20
+ ##
21
+ # Creates a new TarReader on +io+ and yields it to the block, if given.
22
+
23
+ def self.new(io)
24
+ reader = super
25
+
26
+ return reader unless block_given?
27
+
28
+ begin
29
+ yield reader
30
+ ensure
31
+ reader.close
32
+ end
33
+
34
+ nil
35
+ end
36
+
37
+ ##
38
+ # Creates a new tar file reader on +io+ which needs to respond to #pos,
39
+ # #eof?, #read, #getc and #pos=
40
+
41
+ def initialize(io)
42
+ @io = io
43
+ @init_pos = io.pos
44
+ end
45
+
46
+ ##
47
+ # Close the tar file
48
+
49
+ def close
50
+ end
51
+
52
+ ##
53
+ # Iterates over files in the tarball yielding each entry
54
+
55
+ def each
56
+ return enum_for __method__ unless block_given?
57
+
58
+ until @io.eof? do
59
+ header = Gel::Support::Tar::TarHeader.from @io
60
+ return if header.empty?
61
+
62
+ entry = Gel::Support::Tar::TarReader::Entry.new header, @io
63
+ size = entry.header.size
64
+
65
+ yield entry
66
+
67
+ skip = (512 - (size % 512)) % 512
68
+ pending = size - entry.bytes_read
69
+
70
+ begin
71
+ # avoid reading...
72
+ @io.seek pending, IO::SEEK_CUR
73
+ pending = 0
74
+ rescue Errno::EINVAL, NameError
75
+ while pending > 0 do
76
+ bytes_read = @io.read([pending, 4096].min).size
77
+ raise UnexpectedEOF if @io.eof?
78
+ pending -= bytes_read
79
+ end
80
+ end
81
+
82
+ @io.read skip # discard trailing zeros
83
+
84
+ # make sure nobody can use #read, #getc or #rewind anymore
85
+ entry.close
86
+ end
87
+ end
88
+
89
+ alias each_entry each
90
+
91
+ ##
92
+ # NOTE: Do not call #rewind during #each
93
+
94
+ def rewind
95
+ if @init_pos == 0 then
96
+ raise Gel::Support::Tar::NonSeekableIO unless @io.respond_to? :rewind
97
+ @io.rewind
98
+ else
99
+ raise Gel::Support::Tar::NonSeekableIO unless @io.respond_to? :pos=
100
+ @io.pos = @init_pos
101
+ end
102
+ end
103
+
104
+ ##
105
+ # Seeks through the tar file until it finds the +entry+ with +name+ and
106
+ # yields it. Rewinds the tar file to the beginning when the block
107
+ # terminates.
108
+
109
+ def seek name # :yields: entry
110
+ found = find do |entry|
111
+ entry.full_name == name
112
+ end
113
+
114
+ return unless found
115
+
116
+ return yield found
117
+ ensure
118
+ rewind
119
+ end
120
+
121
+ end
122
+
123
+ require_relative "tar_reader/entry"
@@ -0,0 +1,154 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+ #++
4
+ # Copyright (C) 2004 Mauricio Julio Fernández Pradier
5
+ # Redistributed under the terms of the MIT license.
6
+ #--
7
+
8
+ ##
9
+ # Class for reading entries out of a tar file
10
+
11
+ class Gel::Support::Tar::TarReader::Entry
12
+
13
+ ##
14
+ # Header for this tar entry
15
+
16
+ attr_reader :header
17
+
18
+ ##
19
+ # Creates a new tar entry for +header+ that will be read from +io+
20
+
21
+ def initialize(header, io)
22
+ @closed = false
23
+ @header = header
24
+ @io = io
25
+ @orig_pos = @io.pos
26
+ @read = 0
27
+ end
28
+
29
+ def check_closed # :nodoc:
30
+ raise IOError, "closed #{self.class}" if closed?
31
+ end
32
+
33
+ ##
34
+ # Number of bytes read out of the tar entry
35
+
36
+ def bytes_read
37
+ @read
38
+ end
39
+
40
+ ##
41
+ # Closes the tar entry
42
+
43
+ def close
44
+ @closed = true
45
+ end
46
+
47
+ ##
48
+ # Is the tar entry closed?
49
+
50
+ def closed?
51
+ @closed
52
+ end
53
+
54
+ ##
55
+ # Are we at the end of the tar entry?
56
+
57
+ def eof?
58
+ check_closed
59
+
60
+ @read >= @header.size
61
+ end
62
+
63
+ ##
64
+ # Full name of the tar entry
65
+
66
+ def full_name
67
+ if @header.prefix != "" then
68
+ File.join @header.prefix, @header.name
69
+ else
70
+ @header.name
71
+ end
72
+ rescue ArgumentError => e
73
+ raise unless e.message == 'string contains null byte'
74
+ raise Gel::Support::Tar::TarInvalidError,
75
+ 'tar is corrupt, name contains null byte'
76
+ end
77
+
78
+ ##
79
+ # Read one byte from the tar entry
80
+
81
+ def getc
82
+ check_closed
83
+
84
+ return nil if @read >= @header.size
85
+
86
+ ret = @io.getc
87
+ @read += 1 if ret
88
+
89
+ ret
90
+ end
91
+
92
+ ##
93
+ # Is this tar entry a directory?
94
+
95
+ def directory?
96
+ @header.typeflag == "5"
97
+ end
98
+
99
+ ##
100
+ # Is this tar entry a file?
101
+
102
+ def file?
103
+ @header.typeflag == "0"
104
+ end
105
+
106
+ ##
107
+ # Is this tar entry a symlink?
108
+
109
+ def symlink?
110
+ @header.typeflag == "2"
111
+ end
112
+
113
+ ##
114
+ # The position in the tar entry
115
+
116
+ def pos
117
+ check_closed
118
+
119
+ bytes_read
120
+ end
121
+
122
+ ##
123
+ # Reads +len+ bytes from the tar file entry, or the rest of the entry if
124
+ # nil
125
+
126
+ def read(len = nil)
127
+ check_closed
128
+
129
+ return nil if @read >= @header.size
130
+
131
+ len ||= @header.size - @read
132
+ max_read = [len, @header.size - @read].min
133
+
134
+ ret = @io.read max_read
135
+ @read += ret.size
136
+
137
+ ret
138
+ end
139
+
140
+ alias readpartial read # :nodoc:
141
+
142
+ ##
143
+ # Rewinds to the beginning of the tar file entry
144
+
145
+ def rewind
146
+ check_closed
147
+
148
+ raise Gel::Support::Tar::NonSeekableIO unless @io.respond_to? :pos=
149
+
150
+ @io.pos = @orig_pos
151
+ @read = 0
152
+ end
153
+
154
+ end
@@ -0,0 +1,339 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+ #--
4
+ # Copyright (C) 2004 Mauricio Julio Fernández Pradier
5
+ # Redistributed under the terms of the MIT license.
6
+ #++
7
+
8
+ require 'digest'
9
+
10
+ ##
11
+ # Allows writing of tar files
12
+
13
+ class Gel::Support::Tar::TarWriter
14
+
15
+ class FileOverflow < StandardError; end
16
+
17
+ ##
18
+ # IO wrapper that allows writing a limited amount of data
19
+
20
+ class BoundedStream
21
+
22
+ ##
23
+ # Maximum number of bytes that can be written
24
+
25
+ attr_reader :limit
26
+
27
+ ##
28
+ # Number of bytes written
29
+
30
+ attr_reader :written
31
+
32
+ ##
33
+ # Wraps +io+ and allows up to +limit+ bytes to be written
34
+
35
+ def initialize(io, limit)
36
+ @io = io
37
+ @limit = limit
38
+ @written = 0
39
+ end
40
+
41
+ ##
42
+ # Writes +data+ onto the IO, raising a FileOverflow exception if the
43
+ # number of bytes will be more than #limit
44
+
45
+ def write(data)
46
+ if data.bytesize + @written > @limit
47
+ raise FileOverflow, "You tried to feed more data than fits in the file."
48
+ end
49
+ @io.write data
50
+ @written += data.bytesize
51
+ data.bytesize
52
+ end
53
+
54
+ end
55
+
56
+ ##
57
+ # IO wrapper that provides only #write
58
+
59
+ class RestrictedStream
60
+
61
+ ##
62
+ # Creates a new RestrictedStream wrapping +io+
63
+
64
+ def initialize(io)
65
+ @io = io
66
+ end
67
+
68
+ ##
69
+ # Writes +data+ onto the IO
70
+
71
+ def write(data)
72
+ @io.write data
73
+ end
74
+
75
+ end
76
+
77
+ ##
78
+ # Creates a new TarWriter, yielding it if a block is given
79
+
80
+ def self.new(io)
81
+ writer = super
82
+
83
+ return writer unless block_given?
84
+
85
+ begin
86
+ yield writer
87
+ ensure
88
+ writer.close
89
+ end
90
+
91
+ nil
92
+ end
93
+
94
+ ##
95
+ # Creates a new TarWriter that will write to +io+
96
+
97
+ def initialize(io)
98
+ @io = io
99
+ @closed = false
100
+ end
101
+
102
+ ##
103
+ # Adds file +name+ with permissions +mode+, and yields an IO for writing the
104
+ # file to
105
+
106
+ def add_file(name, mode) # :yields: io
107
+ check_closed
108
+
109
+ raise Gel::Support::Tar::NonSeekableIO unless @io.respond_to? :pos=
110
+
111
+ name, prefix = split_name name
112
+
113
+ init_pos = @io.pos
114
+ @io.write "\0" * 512 # placeholder for the header
115
+
116
+ yield RestrictedStream.new(@io) if block_given?
117
+
118
+ size = @io.pos - init_pos - 512
119
+
120
+ remainder = (512 - (size % 512)) % 512
121
+ @io.write "\0" * remainder
122
+
123
+ final_pos = @io.pos
124
+ @io.pos = init_pos
125
+
126
+ header = Gel::Support::Tar::TarHeader.new :name => name, :mode => mode,
127
+ :size => size, :prefix => prefix,
128
+ :mtime => Time.now
129
+
130
+ @io.write header
131
+ @io.pos = final_pos
132
+
133
+ self
134
+ end
135
+
136
+ ##
137
+ # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
138
+ # the file. The +digest_algorithm+ is written to a read-only +name+.sum
139
+ # file following the given file contents containing the digest name and
140
+ # hexdigest separated by a tab.
141
+ #
142
+ # The created digest object is returned.
143
+
144
+ def add_file_digest name, mode, digest_algorithms # :yields: io
145
+ digests = digest_algorithms.map do |digest_algorithm|
146
+ digest = digest_algorithm.new
147
+ digest_name =
148
+ if digest.respond_to? :name then
149
+ digest.name
150
+ else
151
+ /::([^:]+)$/ =~ digest_algorithm.name
152
+ $1
153
+ end
154
+
155
+ [digest_name, digest]
156
+ end
157
+
158
+ digests = Hash[*digests.flatten]
159
+
160
+ add_file name, mode do |io|
161
+ Gel::Support::Tar::DigestIO.wrap io, digests do |digest_io|
162
+ yield digest_io
163
+ end
164
+ end
165
+
166
+ digests
167
+ end
168
+
169
+ ##
170
+ # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
171
+ # the file. The +signer+ is used to add a digest file using its
172
+ # digest_algorithm per add_file_digest and a cryptographic signature in
173
+ # +name+.sig. If the signer has no key only the checksum file is added.
174
+ #
175
+ # Returns the digest.
176
+
177
+ def add_file_signed name, mode, signer
178
+ digest_algorithms = [
179
+ signer.digest_algorithm,
180
+ Digest::SHA512,
181
+ ].compact.uniq
182
+
183
+ digests = add_file_digest name, mode, digest_algorithms do |io|
184
+ yield io
185
+ end
186
+
187
+ signature_digest = digests.values.compact.find do |digest|
188
+ digest_name =
189
+ if digest.respond_to? :name then
190
+ digest.name
191
+ else
192
+ /::([^:]+)$/ =~ digest.class.name
193
+ $1
194
+ end
195
+
196
+ digest_name == signer.digest_name
197
+ end
198
+
199
+ if signer.key then
200
+ signature = signer.sign signature_digest.digest
201
+
202
+ add_file_simple "#{name}.sig", 0444, signature.length do |io|
203
+ io.write signature
204
+ end
205
+ end
206
+
207
+ digests
208
+ end
209
+
210
+ ##
211
+ # Add file +name+ with permissions +mode+ +size+ bytes long. Yields an IO
212
+ # to write the file to.
213
+
214
+ def add_file_simple(name, mode, size) # :yields: io
215
+ check_closed
216
+
217
+ name, prefix = split_name name
218
+
219
+ header = Gel::Support::Tar::TarHeader.new(:name => name, :mode => mode,
220
+ :size => size, :prefix => prefix,
221
+ :mtime => Time.now).to_s
222
+
223
+ @io.write header
224
+ os = BoundedStream.new @io, size
225
+
226
+ yield os if block_given?
227
+
228
+ min_padding = size - os.written
229
+ @io.write("\0" * min_padding)
230
+
231
+ remainder = (512 - (size % 512)) % 512
232
+ @io.write("\0" * remainder)
233
+
234
+ self
235
+ end
236
+
237
+ ##
238
+ # Adds symlink +name+ with permissions +mode+, linking to +target+.
239
+
240
+ def add_symlink(name, target, mode)
241
+ check_closed
242
+
243
+ name, prefix = split_name name
244
+
245
+ header = Gel::Support::Tar::TarHeader.new(:name => name, :mode => mode,
246
+ :size => 0, :typeflag => "2",
247
+ :linkname => target,
248
+ :prefix => prefix,
249
+ :mtime => Time.now).to_s
250
+
251
+ @io.write header
252
+
253
+ self
254
+ end
255
+
256
+ ##
257
+ # Raises IOError if the TarWriter is closed
258
+
259
+ def check_closed
260
+ raise IOError, "closed #{self.class}" if closed?
261
+ end
262
+
263
+ ##
264
+ # Closes the TarWriter
265
+
266
+ def close
267
+ check_closed
268
+
269
+ @io.write "\0" * 1024
270
+ flush
271
+
272
+ @closed = true
273
+ end
274
+
275
+ ##
276
+ # Is the TarWriter closed?
277
+
278
+ def closed?
279
+ @closed
280
+ end
281
+
282
+ ##
283
+ # Flushes the TarWriter's IO
284
+
285
+ def flush
286
+ check_closed
287
+
288
+ @io.flush if @io.respond_to? :flush
289
+ end
290
+
291
+ ##
292
+ # Creates a new directory in the tar file +name+ with +mode+
293
+
294
+ def mkdir(name, mode)
295
+ check_closed
296
+
297
+ name, prefix = split_name(name)
298
+
299
+ header = Gel::Support::Tar::TarHeader.new :name => name, :mode => mode,
300
+ :typeflag => "5", :size => 0,
301
+ :prefix => prefix,
302
+ :mtime => Time.now
303
+
304
+ @io.write header
305
+
306
+ self
307
+ end
308
+
309
+ ##
310
+ # Splits +name+ into a name and prefix that can fit in the TarHeader
311
+
312
+ def split_name(name) # :nodoc:
313
+ if name.bytesize > 256 then
314
+ raise Gel::Support::Tar::TooLongFileName.new("File \"#{name}\" has a too long path (should be 256 or less)")
315
+ end
316
+
317
+ prefix = ''
318
+ if name.bytesize > 100 then
319
+ parts = name.split('/', -1) # parts are never empty here
320
+ name = parts.pop # initially empty for names with a trailing slash ("foo/.../bar/")
321
+ prefix = parts.join('/') # if empty, then it's impossible to split (parts is empty too)
322
+ while !parts.empty? && (prefix.bytesize > 155 || name.empty?)
323
+ name = parts.pop + '/' + name
324
+ prefix = parts.join('/')
325
+ end
326
+
327
+ if name.bytesize > 100 or prefix.empty? then
328
+ raise Gel::Support::Tar::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long name (should be 100 or less)")
329
+ end
330
+
331
+ if prefix.bytesize > 155 then
332
+ raise Gel::Support::Tar::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long base path (should be 155 or less)")
333
+ end
334
+ end
335
+
336
+ return name, prefix
337
+ end
338
+
339
+ end