geminabox 1.0.1 → 1.3.1
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.
- checksums.yaml +4 -4
- data/README.md +22 -0
- data/lib/geminabox.rb +20 -16
- data/lib/geminabox/gem_list_merge.rb +29 -14
- data/lib/geminabox/proxy/splicer.rb +3 -2
- data/lib/geminabox/server.rb +32 -3
- data/lib/geminabox/version.rb +1 -1
- data/views/atom.erb +4 -4
- data/views/gem.erb +7 -7
- data/views/index.erb +8 -8
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccd8f5577f0719a552b32d62c4291929c6e544738c4eaef8c3e2d10fab373d92
|
4
|
+
data.tar.gz: e6d33dd7903533d09dde5e8ab8528a427b5b20b5d66097f41ba953df99563b15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa8030ff620fbd6843a336f2a93f009e70b2d934fe17681c3fe51a41282544a6f7ff4619250724283ea632e80399a804ecb1a07d2060215727be24a67ac6d2ac
|
7
|
+
data.tar.gz: 8e8a36a99eb8cf115d7b503e4dd9716fcc80138f660c9f8c76746fc5d81554d37e8f2a40f8394be6badc480edb237914b45967b7986fb7ab996bd5d887217e24
|
data/README.md
CHANGED
@@ -92,6 +92,24 @@ local systems SSL certificates.
|
|
92
92
|
|
93
93
|
TemplateFaradayAdapter is provided as an example of an alternative HTTPAdapter.
|
94
94
|
|
95
|
+
## Hooks
|
96
|
+
|
97
|
+
You can add a hook (anything callable) which will be called when a gem is
|
98
|
+
successfully received.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Geminabox.on_gem_received = Proc.new do |gem|
|
102
|
+
puts "Gem received: #{gem.spec.name} #{gem.spec.version}"
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Typically you might use this to push a notification to your team chat. Any
|
107
|
+
exceptions which occur within the hook is silently ignored, so please ensure they
|
108
|
+
are handled properly if this is not desirable.
|
109
|
+
|
110
|
+
Also, please note that this hook blocks `POST /upload` and `POST /api/v1/gems` APIs processing.
|
111
|
+
Hook authors are responsible to perform any action non-blocking/async to avoid HTTP timeout.
|
112
|
+
|
95
113
|
## Client Usage
|
96
114
|
|
97
115
|
Since version 0.10, Geminabox supports the standard gemcutter push API:
|
@@ -104,6 +122,10 @@ You can also use the gem plugin:
|
|
104
122
|
|
105
123
|
gem inabox pkg/my-awesome-gem-1.0.gem
|
106
124
|
|
125
|
+
And since version 1.2.0, Geminabox supports the standard gemcutter yank API:
|
126
|
+
|
127
|
+
gem yank my-awesome-gem -v 1.0 --host HOST
|
128
|
+
|
107
129
|
Configure Gem in a box (interactive prompt to specify where to upload to):
|
108
130
|
|
109
131
|
gem inabox -c
|
data/lib/geminabox.rb
CHANGED
@@ -46,6 +46,7 @@ module Geminabox
|
|
46
46
|
:gem_permissions,
|
47
47
|
:allow_delete,
|
48
48
|
:rubygems_proxy,
|
49
|
+
:rubygems_proxy_merge_strategy,
|
49
50
|
:http_adapter,
|
50
51
|
:lockfile,
|
51
52
|
:retry_interval,
|
@@ -53,6 +54,7 @@ module Geminabox
|
|
53
54
|
:ruby_gems_url,
|
54
55
|
:bundler_ruby_gems_url,
|
55
56
|
:allow_upload,
|
57
|
+
:on_gem_received
|
56
58
|
)
|
57
59
|
|
58
60
|
def set_defaults(defaults)
|
@@ -72,22 +74,24 @@ module Geminabox
|
|
72
74
|
end
|
73
75
|
|
74
76
|
set_defaults(
|
75
|
-
data:
|
76
|
-
public_folder:
|
77
|
-
build_legacy:
|
78
|
-
incremental_updates:
|
79
|
-
views:
|
80
|
-
allow_replace:
|
81
|
-
gem_permissions:
|
82
|
-
rubygems_proxy:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
77
|
+
data: File.join(File.dirname(__FILE__), *%w[.. data]),
|
78
|
+
public_folder: File.join(File.dirname(__FILE__), *%w[.. public]),
|
79
|
+
build_legacy: false,
|
80
|
+
incremental_updates: true,
|
81
|
+
views: File.join(File.dirname(__FILE__), *%w[.. views]),
|
82
|
+
allow_replace: false,
|
83
|
+
gem_permissions: 0644,
|
84
|
+
rubygems_proxy: (ENV['RUBYGEMS_PROXY'] == 'true'),
|
85
|
+
rubygems_proxy_merge_strategy: ENV.fetch('RUBYGEMS_PROXY_MERGE_STRATEGY') { :local_gems_take_precedence_over_remote_gems }.to_sym,
|
86
|
+
allow_delete: true,
|
87
|
+
http_adapter: HttpClientAdapter.new,
|
88
|
+
lockfile: '/tmp/geminabox.lockfile',
|
89
|
+
retry_interval: 60,
|
90
|
+
allow_remote_failure: false,
|
91
|
+
ruby_gems_url: 'https://rubygems.org/',
|
92
|
+
bundler_ruby_gems_url: 'https://bundler.rubygems.org/',
|
93
|
+
allow_upload: true,
|
94
|
+
on_gem_received: nil
|
91
95
|
)
|
92
96
|
|
93
97
|
end
|
@@ -1,23 +1,38 @@
|
|
1
|
-
|
2
|
-
class GemListMerge
|
3
|
-
attr_accessor :list
|
4
|
-
|
5
|
-
IGNORE_DEPENDENCIES = 0..-2
|
1
|
+
require "set"
|
6
2
|
|
7
|
-
|
8
|
-
|
3
|
+
module Geminabox
|
4
|
+
module GemListMerge
|
5
|
+
def self.merge(local_gem_list, remote_gem_list, strategy:)
|
6
|
+
strategy_for(strategy).merge(local_gem_list, remote_gem_list)
|
9
7
|
end
|
10
8
|
|
11
|
-
def
|
12
|
-
|
9
|
+
def self.strategy_for(strategy)
|
10
|
+
case strategy
|
11
|
+
when :local_gems_take_precedence_over_remote_gems
|
12
|
+
LocalGemsTakePrecedenceOverRemoteGems
|
13
|
+
when :combine_local_and_remote_gem_versions
|
14
|
+
CombineLocalAndRemoteGemVersions
|
15
|
+
else
|
16
|
+
raise ArgumentError, "Merge strategy must be :local_gems_take_precedence_over_remote_gems (default) or :merge_local_and_remote_gem_versions"
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
module LocalGemsTakePrecedenceOverRemoteGems
|
21
|
+
def self.merge(local_gem_list, remote_gem_list)
|
22
|
+
names = Set.new(local_gem_list.map { |gem| gem[:name] })
|
23
|
+
local_gem_list + remote_gem_list.reject { |gem| names.include? gem[:name] }
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
27
|
+
module CombineLocalAndRemoteGemVersions
|
28
|
+
IGNORE_DEPENDENCIES = 0..-2
|
29
|
+
|
30
|
+
def self.merge(local_gem_list, remote_gem_list)
|
31
|
+
merged = local_gem_list + remote_gem_list
|
32
|
+
merged.uniq! {|val| val.values[IGNORE_DEPENDENCIES] }
|
33
|
+
merged.sort_by! {|x| x.values[IGNORE_DEPENDENCIES] }
|
34
|
+
merged
|
35
|
+
end
|
36
|
+
end
|
22
37
|
end
|
23
38
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
require 'fileutils'
|
3
|
+
require 'rubygems/util'
|
3
4
|
|
4
5
|
module Geminabox
|
5
6
|
module Proxy
|
@@ -65,11 +66,11 @@ module Geminabox
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def unpackage(content)
|
68
|
-
Marshal.load(Gem.gunzip(content))
|
69
|
+
Marshal.load(Gem::Util.gunzip(content))
|
69
70
|
end
|
70
71
|
|
71
72
|
def package(content)
|
72
|
-
Gem.gzip(Marshal.dump(content))
|
73
|
+
Gem::Util.gzip(Marshal.dump(content))
|
73
74
|
end
|
74
75
|
|
75
76
|
def merge_text_content
|
data/lib/geminabox/server.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'reentrant_flock'
|
2
|
+
require 'rubygems/util'
|
2
3
|
|
3
4
|
module Geminabox
|
4
5
|
|
@@ -130,6 +131,7 @@ module Geminabox
|
|
130
131
|
get '/gems/:gemname' do
|
131
132
|
gems = Hash[load_gems.by_name]
|
132
133
|
@gem = gems[params[:gemname]]
|
134
|
+
@allow_delete = self.class.allow_delete?
|
133
135
|
halt 404 unless @gem
|
134
136
|
erb :gem
|
135
137
|
end
|
@@ -147,6 +149,27 @@ module Geminabox
|
|
147
149
|
|
148
150
|
end
|
149
151
|
|
152
|
+
delete '/api/v1/gems/yank' do
|
153
|
+
unless self.class.allow_delete?
|
154
|
+
error_response(403, 'Gem deletion is disabled')
|
155
|
+
end
|
156
|
+
|
157
|
+
halt 400 unless request.form_data?
|
158
|
+
|
159
|
+
serialize_update do
|
160
|
+
gems = load_gems.select { |gem| request['gem_name'] == gem.name and
|
161
|
+
request['version'] == gem.number.version }
|
162
|
+
halt 404, 'Gem not found' if gems.size == 0
|
163
|
+
gems.each do |gem|
|
164
|
+
gem_path = File.expand_path(File.join(Geminabox.data, 'gems',
|
165
|
+
"#{gem.gemfile_name}.gem"))
|
166
|
+
File.delete gem_path if File.exists? gem_path
|
167
|
+
end
|
168
|
+
self.class.reindex(:force_rebuild)
|
169
|
+
return 200, 'Yanked gem and reindexed'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
150
173
|
post '/upload' do
|
151
174
|
unless self.class.allow_upload?
|
152
175
|
error_response(403, 'Gem uploading is disabled')
|
@@ -197,6 +220,12 @@ module Geminabox
|
|
197
220
|
error_response error.code, error.reason
|
198
221
|
end
|
199
222
|
|
223
|
+
begin
|
224
|
+
Geminabox.on_gem_received.call(gem) if Geminabox.on_gem_received
|
225
|
+
rescue
|
226
|
+
# ignore errors which occur within the hook
|
227
|
+
end
|
228
|
+
|
200
229
|
if api_request?
|
201
230
|
"Gem #{gem.name} received and indexed."
|
202
231
|
else
|
@@ -237,7 +266,7 @@ HTML
|
|
237
266
|
def all_gems_with_duplicates
|
238
267
|
specs_files_paths.map do |specs_file_path|
|
239
268
|
if File.exist?(specs_file_path)
|
240
|
-
Marshal.load(Gem.gunzip(Gem.read_binary(specs_file_path)))
|
269
|
+
Marshal.load(Gem::Util.gunzip(Gem.read_binary(specs_file_path)))
|
241
270
|
else
|
242
271
|
[]
|
243
272
|
end
|
@@ -283,7 +312,7 @@ HTML
|
|
283
312
|
end
|
284
313
|
|
285
314
|
def combined_gem_list
|
286
|
-
GemListMerge.
|
315
|
+
GemListMerge.merge(local_gem_list, remote_gem_list, strategy: Geminabox.rubygems_proxy_merge_strategy)
|
287
316
|
end
|
288
317
|
|
289
318
|
helpers do
|
@@ -305,7 +334,7 @@ HTML
|
|
305
334
|
spec_file = File.join(Geminabox.data, "quick", "Marshal.#{Gem.marshal_version}", "#{filename.join("-")}.gemspec.rz")
|
306
335
|
File::open(spec_file, 'r') do |unzipped_spec_file|
|
307
336
|
unzipped_spec_file.binmode
|
308
|
-
Marshal.load(Gem.inflate(unzipped_spec_file.read))
|
337
|
+
Marshal.load(Gem::Util.inflate(unzipped_spec_file.read))
|
309
338
|
end if File.exist? spec_file
|
310
339
|
end
|
311
340
|
|
data/lib/geminabox/version.rb
CHANGED
data/views/atom.erb
CHANGED
@@ -10,12 +10,12 @@
|
|
10
10
|
<% newest_gem = versions.newest %>
|
11
11
|
<% spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
12
12
|
<entry>
|
13
|
-
<id><%= name %></id>
|
13
|
+
<id><%= h(name) %></id>
|
14
14
|
<updated><%= spec.date.w3cdtf %></updated>
|
15
|
-
<title><%= name %> (<%= versions.size == 1 ? versions.oldest.number : "#{versions.oldest.number} - #{versions.newest.number}" %>)</title>
|
16
|
-
<author><name><%= spec.authors.join(", ") %></name></author>
|
15
|
+
<title><%= h(name) %> (<%= h(versions.size == 1 ? versions.oldest.number : "#{versions.oldest.number} - #{versions.newest.number}") %>)</title>
|
16
|
+
<author><name><%= h(spec.authors.join(", ")) %></name></author>
|
17
17
|
<% versions.each do |version| %>
|
18
|
-
<link href="<%= url "/gems/#{version.gemfile_name}.gem" %>" />
|
18
|
+
<link href="<%= h(url "/gems/#{version.gemfile_name}.gem") %>" />
|
19
19
|
<% end %>
|
20
20
|
</entry>
|
21
21
|
<% end %>
|
data/views/gem.erb
CHANGED
@@ -5,18 +5,18 @@
|
|
5
5
|
<ul class="gemlist">
|
6
6
|
<% @gem.by_name do |name, versions| %>
|
7
7
|
<li class="gem-version">
|
8
|
-
<h2><%= name %> (<%= versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}" %>)</h2>
|
8
|
+
<h2><%= h(name) %> (<%= h(versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}") %>)</h2>
|
9
9
|
<% versions.each.reverse_each do |version| %>
|
10
10
|
<p>
|
11
|
-
<code>gem install <%= version.name %> <%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %> -v "<%= version.number %>"</code>
|
11
|
+
<code>gem install <%= h(version.name) %> <%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %> -v "<%= h(version.number) %>"</code>
|
12
12
|
<% unless version.platform =~ /^ruby/i %>
|
13
|
-
<small class="platform"><%= version.platform %></small>
|
13
|
+
<small class="platform"><%= h(version.platform) %></small>
|
14
14
|
<% end %>
|
15
15
|
</p>
|
16
16
|
<div class="delete-form">
|
17
|
-
<a class="download" href="<%= url("/gems/#{version.gemfile_name}.gem") %>">download</a>
|
17
|
+
<a class="download" href="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">download</a>
|
18
18
|
<% if @allow_delete %>
|
19
|
-
<form method="post" action="<%= url("/gems/#{version.gemfile_name}.gem") %>">
|
19
|
+
<form method="post" action="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">
|
20
20
|
<input type="hidden" name="_method" value="DELETE" />
|
21
21
|
<button type="submit">delete</button>
|
22
22
|
</form>
|
@@ -28,10 +28,10 @@
|
|
28
28
|
<p>
|
29
29
|
<% newest_gem = versions.newest %>
|
30
30
|
<% if spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
31
|
-
<%= spec.description %>
|
31
|
+
<%= h(spec.description) %>
|
32
32
|
<br/>
|
33
33
|
<span class="author">– <%= spec.authors.map do |author|
|
34
|
-
"<a href='#{href(spec.homepage)}'>#{author}</a>"
|
34
|
+
"<a href='#{href(spec.homepage)}'>#{h(author)}</a>"
|
35
35
|
end.join(', ') %></span>
|
36
36
|
<% end %>
|
37
37
|
</p>
|
data/views/index.erb
CHANGED
@@ -18,16 +18,16 @@
|
|
18
18
|
|
19
19
|
<% @gems.by_name do |name, versions| %>
|
20
20
|
<li <%= %{id="jump_#{name[0..0].downcase}"} if @index_gems.delete(name[0..0].downcase) %> class="gem-version">
|
21
|
-
<h2><%= name %> (<%= versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}" %>)</h2>
|
21
|
+
<h2><%= h(name) %> (<%= h(versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}") %>)</h2>
|
22
22
|
<% versions.each.reverse_each.first(5).each do |version| %>
|
23
23
|
<p>
|
24
|
-
<code>gem install <%= version.name %> <%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %> -v "<%= version.number %>"</code>
|
24
|
+
<code>gem install <%= h(version.name) %> <%= "--prerelease" if version.number.to_s.match(/[a-z]/i) %> -v "<%= h(version.number) %>"</code>
|
25
25
|
<% unless version.platform =~ /^ruby/i %>
|
26
|
-
<small class="platform"><%= version.platform %></small>
|
26
|
+
<small class="platform"><%= h(version.platform) %></small>
|
27
27
|
<% end %>
|
28
28
|
</p>
|
29
|
-
<form class="delete-form" method="post" action="<%= url("/gems/#{version.gemfile_name}.gem") %>">
|
30
|
-
<a class="download" href="<%= url("/gems/#{version.gemfile_name}.gem") %>">download</a>
|
29
|
+
<form class="delete-form" method="post" action="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">
|
30
|
+
<a class="download" href="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">download</a>
|
31
31
|
<% if @allow_delete %>
|
32
32
|
<input type="hidden" name="_method" value="DELETE" />
|
33
33
|
<button type="submit">delete</button>
|
@@ -36,17 +36,17 @@
|
|
36
36
|
<% end %>
|
37
37
|
|
38
38
|
<% if versions.count > 5 %>
|
39
|
-
<a href="<%= url("/gems/#{name}") %>" id="more_link">Older versions...</a>
|
39
|
+
<a href="<%= h(url("/gems/#{name}")) %>" id="more_link">Older versions...</a>
|
40
40
|
<% end %>
|
41
41
|
|
42
42
|
<div class="details">
|
43
43
|
<p>
|
44
44
|
<% newest_gem = versions.newest %>
|
45
45
|
<% if spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
46
|
-
<%= spec.description %>
|
46
|
+
<%= h(spec.description) %>
|
47
47
|
<br/>
|
48
48
|
<span class="author">– <%= spec.authors.map do |author|
|
49
|
-
"<a href='#{href(spec.homepage)}'>#{author}</a>"
|
49
|
+
"<a href='#{href(spec.homepage)}'>#{h(author)}</a>"
|
50
50
|
end.join(', ') %></span>
|
51
51
|
<% end %>
|
52
52
|
</p>
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geminabox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Lea
|
8
8
|
- Jack Foy
|
9
9
|
- Rob Nichols
|
10
10
|
- Naotoshi Seo
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2021-05-29 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: sinatra
|
@@ -149,7 +149,7 @@ licenses:
|
|
149
149
|
- MIT-LICENSE
|
150
150
|
metadata:
|
151
151
|
source_code_uri: https://github.com/geminabox/geminabox
|
152
|
-
post_install_message:
|
152
|
+
post_install_message:
|
153
153
|
rdoc_options:
|
154
154
|
- "--main"
|
155
155
|
- README.md
|
@@ -166,9 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
168
|
requirements: []
|
169
|
-
|
170
|
-
|
171
|
-
signing_key:
|
169
|
+
rubygems_version: 3.1.2
|
170
|
+
signing_key:
|
172
171
|
specification_version: 4
|
173
172
|
summary: Really simple rubygem hosting
|
174
173
|
test_files: []
|