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,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+ require "uri"
5
+ require "net/http"
6
+
7
+ require_relative "httpool"
8
+
9
+ class Gel::TailFile
10
+ # The number of redirects etc we'll follow before giving up
11
+ MAXIMUM_CHAIN = 8
12
+
13
+ # When attempting a partial file download, we'll back up by this many
14
+ # bytes to ensure the preceding content matches our local file
15
+ CONTENT_OVERLAP = 100
16
+
17
+ # Only bother trying for a partial download if we have at least this
18
+ # many bytes of local content. If we *don't* make a partial request,
19
+ # 1) we're guaranteed not to need a second request due to bad overlap,
20
+ # and 2) the response can be gzipped.
21
+ PARTIAL_MINIMUM = 65536
22
+
23
+ attr_accessor :uri, :pinboard, :filename
24
+ def initialize(uri, pinboard, httpool: Gel::Httpool.new)
25
+ @uri = uri
26
+ @pinboard = pinboard
27
+ @httpool = httpool
28
+
29
+ @filename = pinboard.filename(uri)
30
+ @etag = pinboard.etag(uri)
31
+
32
+ @done = false
33
+ end
34
+
35
+ def done?
36
+ @done
37
+ end
38
+
39
+ def update(force_reset: false)
40
+ uri = self.uri
41
+
42
+ File.open(@filename, "a+b") do |f|
43
+ f.seek(0, IO::SEEK_END)
44
+
45
+ MAXIMUM_CHAIN.times do
46
+ f.seek(0, IO::SEEK_SET) if force_reset
47
+
48
+ request = Net::HTTP::Get.new(uri)
49
+
50
+ requested_from = 0
51
+
52
+ if f.pos > PARTIAL_MINIMUM
53
+ requested_from = f.pos - CONTENT_OVERLAP
54
+ request["Range"] = "bytes=#{requested_from}-"
55
+ request["Accept-Encoding"] = "identity"
56
+ else
57
+ f.pos = 0
58
+ end
59
+ request["If-None-Match"] = @etag if @etag
60
+
61
+ response = @httpool.request(uri, request)
62
+
63
+ case response
64
+ when Net::HTTPNotModified
65
+ @done = true
66
+ pinboard.updated(uri, response["ETag"], false)
67
+
68
+ return # no-op
69
+
70
+ when Net::HTTPRequestedRangeNotSatisfiable
71
+ # This should never happen, but sometimes does: either the
72
+ # file has been rebuilt, and we should do a full fetch, or
73
+ # we're ahead of the server (because an intermediate is
74
+ # caching too aggressively, say), and we should do nothing.
75
+
76
+ if response["Content-Range"] =~ /\Abytes \*\/(\d+)\z/
77
+ current_length = $1.to_i
78
+
79
+ debug "File is smaller than we expected: only #{current_length} bytes"
80
+
81
+ # Back up a bit, and check whether the end matches what we
82
+ # already have
83
+
84
+ f.pos = current_length
85
+ next
86
+ else
87
+ force_reset = true
88
+ next
89
+ end
90
+
91
+ when Net::HTTPOK
92
+ f.pos = 0
93
+ f.truncate(0)
94
+ f.write response.body
95
+ f.flush
96
+
97
+ @done = true
98
+ pinboard.updated(uri, response["ETag"], true)
99
+
100
+ return # Done
101
+
102
+ when Net::HTTPPartialContent
103
+ if response["Content-Range"] =~ /\Abytes (\d+)-(\d+)\/(\d+)\z/
104
+ from, to, size = $1.to_i, $2.to_i, $3.to_i
105
+ else
106
+ # Not what we asked for
107
+ debug "Bad response range"
108
+
109
+ force_reset = true
110
+ next
111
+ end
112
+
113
+ if from != requested_from
114
+ # Server didn't give us what we asked for
115
+ debug "Incorrect response range"
116
+
117
+ force_reset = true
118
+ next
119
+ end
120
+
121
+ if to - from + 1 != response.body.size
122
+ # Server didn't give us what it claimed to
123
+ debug "Bad response length"
124
+
125
+ force_reset = true
126
+ next
127
+ end
128
+
129
+ debug "Current file size is #{File.size(@filename)}"
130
+ debug "Remote size is #{size}"
131
+
132
+ f.pos = from
133
+
134
+ if to < f.size
135
+ # No new content, but check the overlap in case the file's
136
+ # been reset
137
+
138
+ overlap = f.read(to - from + 1)
139
+ if response.body == overlap
140
+ # Good overlap, but nothing new
141
+ debug "Overlap is good, but no new content"
142
+
143
+ @done = true
144
+ pinboard.updated(uri, @etag, false) # keep old etag
145
+
146
+ return # Done
147
+ else
148
+ # Bad overlap
149
+ debug "Bad overlap on short response"
150
+
151
+ force_reset = true
152
+ next
153
+ end
154
+ else
155
+ overlap = f.read
156
+ if response.body[0, overlap.size] == overlap
157
+ # Good overlap; use rest
158
+ rest = response.body[overlap.size..-1]
159
+
160
+ debug "#{overlap.size} byte overlap is okay"
161
+ debug "Using remaining #{rest.size} bytes"
162
+
163
+ f.write(rest)
164
+ f.flush
165
+
166
+ @done = true
167
+ pinboard.updated(uri, response["ETag"], true)
168
+
169
+ return # Done
170
+ else
171
+ # Bad overlap
172
+ debug "Bad overlap on long response"
173
+
174
+ force_reset = true
175
+ next
176
+ end
177
+ end
178
+
179
+ when Net::HTTPRedirection
180
+ uri = URI(response["Location"])
181
+ next
182
+
183
+ when Net::HTTPTooManyRequests
184
+ # https://github.com/rubygems/rubygems-infrastructure/blob/adc0668c1f1539f281ffe86c6e0ad12743c5c8bd/cookbooks/rubygems-balancer/templates/default/site.conf.erb#L12
185
+ debug "Rate limited"
186
+
187
+ sleep 1 + rand
188
+ next
189
+
190
+ else
191
+ # splat
192
+ response.value
193
+
194
+ raise "Unexpected HTTP success code"
195
+ end
196
+ end
197
+
198
+ raise "Giving up after #{MAXIMUM_CHAIN} requests"
199
+ end
200
+ end
201
+
202
+ def debug(message)
203
+ #$stderr.puts message if $DEBUG
204
+ end
205
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gel
4
+ VERSION = "0.2.0"
5
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ class Gel::WorkPool
6
+ attr_accessor :queue_order
7
+
8
+ attr_reader :count
9
+ attr_reader :errors
10
+
11
+ def initialize(concurrency, monitor: Monitor.new, name: nil, collect_errors: false)
12
+ @monitor = monitor
13
+ @name = name
14
+
15
+ @queue_order = nil
16
+
17
+ @concurrency = concurrency
18
+ @workers = []
19
+ @shutdown = false
20
+
21
+ @work_cond = @monitor.new_cond
22
+ @idle_cond = @monitor.new_cond
23
+
24
+ @queue = []
25
+ @count = 0
26
+ @errors = collect_errors ? [] : nil
27
+
28
+ if block_given?
29
+ begin
30
+ result = yield self
31
+ join
32
+ result
33
+ ensure
34
+ stop
35
+ end
36
+ end
37
+ end
38
+
39
+ def start
40
+ @monitor.synchronize do
41
+ while @workers.size < @concurrency
42
+ @workers << Thread.new do
43
+ Thread.current.name = @name if @name && Thread.current.respond_to?(:name=)
44
+ Thread.current.abort_on_exception = true
45
+
46
+ catch(:stop) do
47
+ loop do
48
+ current_job = nil
49
+ @monitor.synchronize do
50
+ Thread.current[:active] = nil
51
+ @work_cond.wait_until do
52
+ @idle_cond.broadcast
53
+ @shutdown || @queue.first
54
+ end
55
+ throw :stop if @shutdown
56
+ current_job = @queue.shift
57
+ Thread.current[:active] = current_job[1]
58
+ @idle_cond.broadcast
59
+ end
60
+
61
+ begin
62
+ current_job[0].call
63
+ rescue Exception => ex
64
+ if @errors
65
+ $stderr.puts ex if $DEBUG
66
+ @monitor.synchronize do
67
+ @errors << [current_job, ex]
68
+ end
69
+ else
70
+ $stderr.puts "Unhandled exception in work pool #{@name.inspect} for job #{current_job[1].inspect}:\n#{ex.inspect}\n#{ex.backtrace.map { |s| s.sub(/^/, " ") }.join("\n")}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def stop
81
+ @monitor.synchronize do
82
+ @shutdown = true
83
+ @work_cond.broadcast
84
+ end
85
+ @workers.each(&:join).clear
86
+ end
87
+
88
+ def idle?
89
+ @monitor.synchronize do
90
+ @queue.empty? && @workers.none? { |w| w[:active] }
91
+ end
92
+ end
93
+
94
+ def tick!
95
+ @monitor.synchronize do
96
+ @idle_cond.broadcast
97
+ end
98
+ end
99
+
100
+ def wait
101
+ @monitor.synchronize do
102
+ start if @workers.empty?
103
+
104
+ @idle_cond.wait_until do
105
+ (!block_given? || yield) && idle?
106
+ end
107
+ end
108
+ end
109
+
110
+ def join
111
+ wait
112
+ @monitor.synchronize do
113
+ if @errors && e = @errors.first
114
+ raise e.last
115
+ end
116
+ end
117
+ end
118
+
119
+ def status
120
+ @monitor.synchronize do
121
+ { active: @workers.map { |w| w[:active] }.compact, queued: @queue.size }
122
+ end
123
+ end
124
+
125
+ def queue(job = nil, label, &block)
126
+ raise ArgumentError if job && block
127
+ job ||= block
128
+ label ||= job
129
+
130
+ @monitor.synchronize do
131
+ @queue << [job, label]
132
+ @count += 1
133
+ reorder_queue!
134
+ @work_cond.signal
135
+ end
136
+ end
137
+
138
+ def reorder_queue!
139
+ @monitor.synchronize do
140
+ @queue.sort_by!(&@queue_order)
141
+ end if @queue_order
142
+ end
143
+ end
@@ -0,0 +1,16 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "GEL\-EXEC" "1" "March 2019" "" "Gel Manual"
5
+ .
6
+ .SH "NAME"
7
+ \fBgel\-exec\fR \- run an executable with gel enabled
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBgel\fR \fBexec\fR \fIexecutable\fR [\fIargs\fR]
11
+ .
12
+ .SH "DESCRIPTION"
13
+ Run an executable with the Gemfile activated\.
14
+ .
15
+ .SH "SEE ALSO"
16
+ bundle\-exec(1)
@@ -0,0 +1,16 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "GEL\-INSTALL" "1" "March 2019" "" "Gel Manual"
5
+ .
6
+ .SH "NAME"
7
+ \fBgel\-install\fR \- install gems
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBgel install\fR
11
+ .
12
+ .SH "DESCRIPTION"
13
+ Install gems listed in \fBGemfile\.lock\fR\.
14
+ .
15
+ .SH "SEE ALSO"
16
+ gemfile(5), gel\-lock(1), bundle\-install(1)
@@ -0,0 +1,30 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "GEL" "1" "March 2019" "" "Gel Manual"
5
+ .
6
+ .SH "NAME"
7
+ \fBgel\fR \- a modern gem manager
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBgel\fR [\fB\-\-version\fR] [\fB\-\-help\fR] \fIcommand\fR [\fIargs\fR]
11
+ .
12
+ .SH "DESCRIPTION"
13
+ Gel is a minimal package manager for the Ruby programming language\.
14
+ .
15
+ .SH "GEL COMMANDS"
16
+ .
17
+ .TP
18
+ gel\-install(1)
19
+ Install all the gems listed in the Gemfile\.lock
20
+ .
21
+ .TP
22
+ gel\-lock(1)
23
+ Resolve the dependencies listed in Gemfile into a Gemfile\.lock
24
+ .
25
+ .TP
26
+ gel\-exec(1)
27
+ Run an executable with the Gemfile activated
28
+ .
29
+ .SH "SEE ALSO"
30
+ ruby(1), gem(1), bundle(1)
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Gel Authors
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pub_grub
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.0
27
+ description:
28
+ email:
29
+ - team@gel.dev
30
+ executables:
31
+ - gel
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - CODE_OF_CONDUCT.md
36
+ - LICENSE.txt
37
+ - README.md
38
+ - exe/gel
39
+ - lib/gel.rb
40
+ - lib/gel/catalog.rb
41
+ - lib/gel/catalog/common.rb
42
+ - lib/gel/catalog/compact_index.rb
43
+ - lib/gel/catalog/dependency_index.rb
44
+ - lib/gel/catalog/legacy_index.rb
45
+ - lib/gel/catalog/marshal_hacks.rb
46
+ - lib/gel/command.rb
47
+ - lib/gel/command/config.rb
48
+ - lib/gel/command/env.rb
49
+ - lib/gel/command/exec.rb
50
+ - lib/gel/command/help.rb
51
+ - lib/gel/command/install.rb
52
+ - lib/gel/command/install_gem.rb
53
+ - lib/gel/command/lock.rb
54
+ - lib/gel/command/ruby.rb
55
+ - lib/gel/command/shell_setup.rb
56
+ - lib/gel/command/stub.rb
57
+ - lib/gel/command/update.rb
58
+ - lib/gel/compatibility.rb
59
+ - lib/gel/compatibility/bundler.rb
60
+ - lib/gel/compatibility/bundler/cli.rb
61
+ - lib/gel/compatibility/bundler/friendly_errors.rb
62
+ - lib/gel/compatibility/bundler/setup.rb
63
+ - lib/gel/compatibility/rubygems.rb
64
+ - lib/gel/compatibility/rubygems/command.rb
65
+ - lib/gel/compatibility/rubygems/dependency_installer.rb
66
+ - lib/gel/compatibility/rubygems/gem_runner.rb
67
+ - lib/gel/config.rb
68
+ - lib/gel/db.rb
69
+ - lib/gel/direct_gem.rb
70
+ - lib/gel/environment.rb
71
+ - lib/gel/error.rb
72
+ - lib/gel/gemfile_parser.rb
73
+ - lib/gel/gemspec_parser.rb
74
+ - lib/gel/git_catalog.rb
75
+ - lib/gel/git_depot.rb
76
+ - lib/gel/httpool.rb
77
+ - lib/gel/installer.rb
78
+ - lib/gel/lock_loader.rb
79
+ - lib/gel/lock_parser.rb
80
+ - lib/gel/locked_store.rb
81
+ - lib/gel/multi_store.rb
82
+ - lib/gel/package.rb
83
+ - lib/gel/package/inspector.rb
84
+ - lib/gel/package/installer.rb
85
+ - lib/gel/path_catalog.rb
86
+ - lib/gel/pinboard.rb
87
+ - lib/gel/pub_grub/preference_strategy.rb
88
+ - lib/gel/pub_grub/source.rb
89
+ - lib/gel/runtime.rb
90
+ - lib/gel/store.rb
91
+ - lib/gel/store_catalog.rb
92
+ - lib/gel/store_gem.rb
93
+ - lib/gel/stub_set.rb
94
+ - lib/gel/support/gem_platform.rb
95
+ - lib/gel/support/gem_requirement.rb
96
+ - lib/gel/support/gem_version.rb
97
+ - lib/gel/support/tar.rb
98
+ - lib/gel/support/tar/tar_header.rb
99
+ - lib/gel/support/tar/tar_reader.rb
100
+ - lib/gel/support/tar/tar_reader/entry.rb
101
+ - lib/gel/support/tar/tar_writer.rb
102
+ - lib/gel/tail_file.rb
103
+ - lib/gel/version.rb
104
+ - lib/gel/work_pool.rb
105
+ - man/man1/gel-exec.1
106
+ - man/man1/gel-install.1
107
+ - man/man1/gel.1
108
+ homepage: https://gel.dev
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.0.1
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: A modern gem manager
131
+ test_files: []