geminabox 3.1.1 → 4.0.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.
- checksums.yaml +4 -4
- data/README.md +149 -58
- data/lib/geminabox/compact_index_api.rb +77 -0
- data/lib/geminabox/compact_indexer.rb +280 -0
- data/lib/geminabox/gem_version.rb +8 -0
- data/lib/geminabox/gem_version_collection.rb +12 -0
- data/lib/geminabox/hostess.rb +5 -5
- data/lib/geminabox/incoming_gem.rb +1 -5
- data/lib/geminabox/server.rb +66 -56
- data/lib/geminabox/version.rb +1 -1
- data/lib/geminabox.rb +28 -24
- data/public/master.css +377 -107
- data/public/master.js +133 -10
- data/views/_version_row.erb +16 -0
- data/views/gem.erb +14 -27
- data/views/index.erb +43 -48
- data/views/layout.erb +16 -0
- data/views/upload.erb +3 -5
- metadata +34 -11
- data/lib/geminabox/gem_list_merge.rb +0 -40
- data/lib/geminabox/proxy/copier.rb +0 -37
- data/lib/geminabox/proxy/file_handler.rb +0 -102
- data/lib/geminabox/proxy/hostess.rb +0 -85
- data/lib/geminabox/proxy/splicer.rb +0 -85
- data/lib/geminabox/proxy.rb +0 -14
- data/lib/geminabox/rubygems_dependency.rb +0 -32
data/views/gem.erb
CHANGED
|
@@ -1,40 +1,27 @@
|
|
|
1
|
-
<p>
|
|
2
|
-
<a href="/">Back to Gem Index</a>
|
|
1
|
+
<p class="back-link">
|
|
2
|
+
<a href="<%= url("/") %>">Back to Gem Index</a>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<ul class="gemlist">
|
|
6
6
|
<% @gem.by_name do |name, versions| %>
|
|
7
|
-
<li class="gem-
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<%
|
|
13
|
-
|
|
7
|
+
<li class="gem-card">
|
|
8
|
+
<div class="card-header">
|
|
9
|
+
<h2><%= h(name) %> (<%= h(versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}") %>)</h2>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="card-body">
|
|
12
|
+
<% versions.each.reverse_each do |version| %>
|
|
13
|
+
<%= erb :_version_row, layout: false, locals: { version: version } %>
|
|
14
14
|
<% end %>
|
|
15
|
-
|
|
16
|
-
<div class="delete-form">
|
|
17
|
-
<a class="download" href="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">download</a>
|
|
18
|
-
<% if @allow_delete %>
|
|
19
|
-
<form method="post" action="<%= h(url("/gems/#{version.gemfile_name}.gem")) %>">
|
|
20
|
-
<input type="hidden" name="_method" value="DELETE" />
|
|
21
|
-
<button type="submit">delete</button>
|
|
22
|
-
</form>
|
|
23
|
-
<% end %>
|
|
24
|
-
</div>
|
|
25
|
-
<% end %>
|
|
15
|
+
</div>
|
|
26
16
|
|
|
27
|
-
<div class="
|
|
28
|
-
<p>
|
|
17
|
+
<div class="card-footer">
|
|
29
18
|
<% newest_gem = versions.newest %>
|
|
30
19
|
<% if spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
<span class="author">– <%= spec.authors.map do |author|
|
|
20
|
+
<p><%= h(spec.description) %></p>
|
|
21
|
+
<p class="author">– <%= spec.authors.map do |author|
|
|
34
22
|
"<a href='#{href(spec.homepage)}'>#{h(author)}</a>"
|
|
35
|
-
end.join(', ') %></
|
|
23
|
+
end.join(', ') %></p>
|
|
36
24
|
<% end %>
|
|
37
|
-
</p>
|
|
38
25
|
</div>
|
|
39
26
|
|
|
40
27
|
</li>
|
data/views/index.erb
CHANGED
|
@@ -1,55 +1,52 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
<div class="intro">
|
|
2
|
+
<p class="hint">Add this server to your Gemfile, then paste gem lines from below into the block</p>
|
|
3
|
+
<code class="command snippet">source "<%= h(url("/")) %>" do
|
|
4
|
+
gem "..."
|
|
5
|
+
end</code>
|
|
6
|
+
<p class="hint">If you needed credentials to get to this page</p>
|
|
7
|
+
<code class="command">bundle config set --global <%= h(URI(url("/")).host) %> username:password</code>
|
|
8
|
+
<p class="hint">Without Bundler</p>
|
|
9
|
+
<code class="command">gem install GEMNAME --source <%= h(url("/")) %></code>
|
|
10
|
+
<% if @allow_upload %>
|
|
11
|
+
<p class="hint">and then ...</p>
|
|
12
|
+
<code class="command">gem install geminabox<br />gem inabox [gemfile]</code>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
11
15
|
|
|
12
16
|
<% if @gems.any? %>
|
|
13
|
-
<% if @allow_upload %><a href="<%= url("/upload") %>">Upload Another Gem</a><% end %>
|
|
17
|
+
<% if @allow_upload %><p class="upload-link"><a href="<%= url("/upload") %>">Upload Another Gem</a></p><% end %>
|
|
14
18
|
|
|
15
|
-
<
|
|
19
|
+
<nav id="alpha_index">
|
|
20
|
+
<% ("a".."z").each do |i| %>
|
|
21
|
+
<% if @index_gems.include?(i) %><a href="#jump_<%= i %>"><%= i %></a><% else %><span><%= i %></span><% end %>
|
|
22
|
+
<% end %>
|
|
23
|
+
</nav>
|
|
16
24
|
|
|
17
25
|
<ul class="gemlist">
|
|
18
26
|
|
|
19
27
|
<% @gems.by_name do |name, versions| %>
|
|
20
|
-
<li <%= %{id="jump_#{name[0..0].downcase}"} if @index_gems.delete(name[0..0].downcase) %> class="gem-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<div class="details">
|
|
43
|
-
<p>
|
|
44
|
-
<% newest_gem = versions.newest %>
|
|
45
|
-
<% if spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
|
46
|
-
<%= h(spec.description) %>
|
|
47
|
-
<br/>
|
|
48
|
-
<span class="author">– <%= spec.authors.map do |author|
|
|
49
|
-
"<a href='#{href(spec.homepage)}'>#{h(author)}</a>"
|
|
50
|
-
end.join(', ') %></span>
|
|
51
|
-
<% end %>
|
|
52
|
-
</p>
|
|
28
|
+
<li <%= %{id="jump_#{name[0..0].downcase}"} if @index_gems.delete(name[0..0].downcase) %> class="gem-card">
|
|
29
|
+
<div class="card-header" id="gem_<%= h(name) %>">
|
|
30
|
+
<h2><%= h(name) %> (<%= h(versions.count == 1 ? versions.first.number : "#{versions.oldest.number} - #{versions.newest.number}") %>)<a class="permalink" href="#gem_<%= h(name) %>" title="Permalink to <%= h(name) %>" aria-label="Permalink to <%= h(name) %>"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 17H7A5 5 0 0 1 7 7h2"></path><path d="M15 7h2a5 5 0 1 1 0 10h-2"></path><line x1="8" y1="12" x2="16" y2="12"></line></svg></a></h2>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="card-body">
|
|
33
|
+
<% versions.each.reverse_each.first(5).each do |version| %>
|
|
34
|
+
<%= erb :_version_row, layout: false, locals: { version: version } %>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<% if versions.count > 5 %>
|
|
38
|
+
<div class="more-link"><a href="<%= h(url("/gems/#{name}")) %>">Older versions...</a></div>
|
|
39
|
+
<% end %>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="card-footer">
|
|
43
|
+
<% newest_gem = versions.newest %>
|
|
44
|
+
<% if spec = spec_for(name, newest_gem.number, newest_gem.platform) %>
|
|
45
|
+
<p><%= h(spec.description) %></p>
|
|
46
|
+
<p class="author">– <%= spec.authors.map do |author|
|
|
47
|
+
"<a href='#{href(spec.homepage)}'>#{h(author)}</a>"
|
|
48
|
+
end.join(', ') %></p>
|
|
49
|
+
<% end %>
|
|
53
50
|
</div>
|
|
54
51
|
|
|
55
52
|
</li>
|
|
@@ -57,6 +54,4 @@
|
|
|
57
54
|
</ul>
|
|
58
55
|
<% end %>
|
|
59
56
|
|
|
60
|
-
<% if @allow_upload %><a href="<%= url("/upload") %>">Upload Another Gem</a><% end %>
|
|
61
|
-
|
|
62
|
-
<script type="text/javascript" src="<%= url "/master.js", false %>"></script>
|
|
57
|
+
<% if @allow_upload %><p class="upload-link"><a href="<%= url("/upload") %>">Upload Another Gem</a></p><% end %>
|
data/views/layout.erb
CHANGED
|
@@ -10,5 +10,21 @@
|
|
|
10
10
|
<h1>Gem in a Box</h1>
|
|
11
11
|
<%= yield %>
|
|
12
12
|
</div>
|
|
13
|
+
<% if @allow_delete %>
|
|
14
|
+
<dialog id="delete-confirm">
|
|
15
|
+
<div class="delete-confirm-body">
|
|
16
|
+
<div class="accent"></div>
|
|
17
|
+
<div>
|
|
18
|
+
<h3></h3>
|
|
19
|
+
<p></p>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="delete-confirm-actions">
|
|
23
|
+
<button type="button" class="cancel">Cancel</button>
|
|
24
|
+
<button type="button" class="danger">Delete this version</button>
|
|
25
|
+
</div>
|
|
26
|
+
</dialog>
|
|
27
|
+
<% end %>
|
|
28
|
+
<script type="text/javascript" src="<%= url "/master.js", false %>"></script>
|
|
13
29
|
</body>
|
|
14
30
|
</html>
|
data/views/upload.erb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
<p>
|
|
2
|
-
<small>Choose a gem file to upload ...</small>
|
|
3
|
-
</p>
|
|
1
|
+
<p class="hint">Choose a gem file to upload ...</p>
|
|
4
2
|
<%= @error %>
|
|
5
|
-
<form method="POST" enctype="multipart/form-data">
|
|
3
|
+
<form method="POST" enctype="multipart/form-data" class="upload-form">
|
|
6
4
|
<input type="file" name="file">
|
|
7
5
|
<input type="submit" value="Upload">
|
|
8
|
-
</form>
|
|
6
|
+
</form>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: geminabox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom Lea
|
|
@@ -103,6 +103,20 @@ dependencies:
|
|
|
103
103
|
- - ">="
|
|
104
104
|
- !ruby/object:Gem::Version
|
|
105
105
|
version: '0'
|
|
106
|
+
- !ruby/object:Gem::Dependency
|
|
107
|
+
name: compact_index
|
|
108
|
+
requirement: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - "~>"
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0.15'
|
|
113
|
+
type: :runtime
|
|
114
|
+
prerelease: false
|
|
115
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - "~>"
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '0.15'
|
|
106
120
|
- !ruby/object:Gem::Dependency
|
|
107
121
|
name: rubygems-generate_index
|
|
108
122
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -117,8 +131,22 @@ dependencies:
|
|
|
117
131
|
- - "~>"
|
|
118
132
|
- !ruby/object:Gem::Version
|
|
119
133
|
version: '1.1'
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
- !ruby/object:Gem::Dependency
|
|
135
|
+
name: rss
|
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
|
137
|
+
requirements:
|
|
138
|
+
- - "~>"
|
|
139
|
+
- !ruby/object:Gem::Version
|
|
140
|
+
version: '0.3'
|
|
141
|
+
type: :runtime
|
|
142
|
+
prerelease: false
|
|
143
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
144
|
+
requirements:
|
|
145
|
+
- - "~>"
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: '0.3'
|
|
148
|
+
description: A private gem hosting app, with client side gem push style functionality.
|
|
149
|
+
Web UI is provided.
|
|
122
150
|
email:
|
|
123
151
|
- contrib@tomlea.co.uk
|
|
124
152
|
- jack@foys.net
|
|
@@ -133,8 +161,9 @@ files:
|
|
|
133
161
|
- MIT-LICENSE
|
|
134
162
|
- README.md
|
|
135
163
|
- lib/geminabox.rb
|
|
164
|
+
- lib/geminabox/compact_index_api.rb
|
|
165
|
+
- lib/geminabox/compact_indexer.rb
|
|
136
166
|
- lib/geminabox/disk_cache.rb
|
|
137
|
-
- lib/geminabox/gem_list_merge.rb
|
|
138
167
|
- lib/geminabox/gem_store.rb
|
|
139
168
|
- lib/geminabox/gem_store_error.rb
|
|
140
169
|
- lib/geminabox/gem_version.rb
|
|
@@ -146,12 +175,6 @@ files:
|
|
|
146
175
|
- lib/geminabox/http_adapter_config_error.rb
|
|
147
176
|
- lib/geminabox/incoming_gem.rb
|
|
148
177
|
- lib/geminabox/indexer.rb
|
|
149
|
-
- lib/geminabox/proxy.rb
|
|
150
|
-
- lib/geminabox/proxy/copier.rb
|
|
151
|
-
- lib/geminabox/proxy/file_handler.rb
|
|
152
|
-
- lib/geminabox/proxy/hostess.rb
|
|
153
|
-
- lib/geminabox/proxy/splicer.rb
|
|
154
|
-
- lib/geminabox/rubygems_dependency.rb
|
|
155
178
|
- lib/geminabox/server.rb
|
|
156
179
|
- lib/geminabox/version.rb
|
|
157
180
|
- lib/geminabox_client.rb
|
|
@@ -160,6 +183,7 @@ files:
|
|
|
160
183
|
- public/favicon.ico
|
|
161
184
|
- public/master.css
|
|
162
185
|
- public/master.js
|
|
186
|
+
- views/_version_row.erb
|
|
163
187
|
- views/atom.erb
|
|
164
188
|
- views/gem.erb
|
|
165
189
|
- views/index.erb
|
|
@@ -170,7 +194,6 @@ licenses:
|
|
|
170
194
|
- MIT
|
|
171
195
|
metadata:
|
|
172
196
|
homepage_uri: https://github.com/geminabox/geminabox
|
|
173
|
-
source_code_uri: https://github.com/geminabox/geminabox
|
|
174
197
|
changelog_uri: https://github.com/geminabox/geminabox/releases
|
|
175
198
|
rdoc_options:
|
|
176
199
|
- "--main"
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "set"
|
|
4
|
-
|
|
5
|
-
module Geminabox
|
|
6
|
-
module GemListMerge
|
|
7
|
-
def self.merge(local_gem_list, remote_gem_list, strategy:)
|
|
8
|
-
strategy_for(strategy).merge(local_gem_list, remote_gem_list)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.strategy_for(strategy)
|
|
12
|
-
case strategy
|
|
13
|
-
when :local_gems_take_precedence_over_remote_gems
|
|
14
|
-
LocalGemsTakePrecedenceOverRemoteGems
|
|
15
|
-
when :combine_local_and_remote_gem_versions
|
|
16
|
-
CombineLocalAndRemoteGemVersions
|
|
17
|
-
else
|
|
18
|
-
raise ArgumentError, "Merge strategy must be :local_gems_take_precedence_over_remote_gems (default) or :combine_local_and_remote_gem_versions"
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
module LocalGemsTakePrecedenceOverRemoteGems
|
|
23
|
-
def self.merge(local_gem_list, remote_gem_list)
|
|
24
|
-
names = Set.new(local_gem_list.map { |gem| gem[:name] })
|
|
25
|
-
local_gem_list + remote_gem_list.reject { |gem| names.include? gem[:name] }
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
module CombineLocalAndRemoteGemVersions
|
|
30
|
-
IGNORE_DEPENDENCIES = 0..-2
|
|
31
|
-
|
|
32
|
-
def self.merge(local_gem_list, remote_gem_list)
|
|
33
|
-
merged = local_gem_list + remote_gem_list
|
|
34
|
-
merged.uniq! {|val| val.values[IGNORE_DEPENDENCIES] }
|
|
35
|
-
merged.sort_by! {|x| x.values[IGNORE_DEPENDENCIES] }
|
|
36
|
-
merged
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
module Geminabox
|
|
5
|
-
module Proxy
|
|
6
|
-
class Copier < FileHandler
|
|
7
|
-
|
|
8
|
-
def self.copy(file_name)
|
|
9
|
-
copier = new(file_name)
|
|
10
|
-
copier.get_file
|
|
11
|
-
copier
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def get_file
|
|
15
|
-
return true if proxy_file_exists?
|
|
16
|
-
return copy_local if local_file_exists?
|
|
17
|
-
get_remote
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def copy_local
|
|
21
|
-
FileUtils.cp local_path, proxy_path
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def get_remote
|
|
25
|
-
begin
|
|
26
|
-
if rc = remote_content
|
|
27
|
-
File.open(proxy_path, 'wb'){|f| f.write(rc) }
|
|
28
|
-
end
|
|
29
|
-
rescue
|
|
30
|
-
File.unlink(proxy_path) if File.exist?(proxy_path)
|
|
31
|
-
raise $!
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Geminabox
|
|
4
|
-
module Proxy
|
|
5
|
-
class FileHandler
|
|
6
|
-
|
|
7
|
-
attr_reader :file_name
|
|
8
|
-
|
|
9
|
-
def initialize(file_name)
|
|
10
|
-
@file_name = file_name
|
|
11
|
-
# file_name comes from the request path; both paths get mkdir_p and writes.
|
|
12
|
-
root = File.expand_path(root_path) + File::SEPARATOR
|
|
13
|
-
unless local_path.start_with?(root) && proxy_path.start_with?(root)
|
|
14
|
-
raise ArgumentError, "#{file_name} resolves outside #{root_path}"
|
|
15
|
-
end
|
|
16
|
-
ensure_destination_exists
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def local_path
|
|
20
|
-
File.expand_path(file_name, root_path)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def root_path
|
|
24
|
-
Geminabox.data
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def local_file_exists?
|
|
28
|
-
file_exists? local_path
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def proxy_file_exists?
|
|
32
|
-
file_exists? proxy_path
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def proxy_path
|
|
36
|
-
File.expand_path(file_name, proxy_folder_path)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def file_exists?(path)
|
|
40
|
-
File.exist? path
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def proxy_folder_path
|
|
44
|
-
File.join(root_path, proxy_folder_name)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def proxy_folder_name
|
|
48
|
-
'proxy'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def remote_content
|
|
52
|
-
Geminabox.http_adapter.get_content(remote_url)
|
|
53
|
-
rescue
|
|
54
|
-
return nil if Geminabox.allow_remote_failure
|
|
55
|
-
raise GemStoreError.new(500, "Unable to get content from #{remote_url}")
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def remote_url
|
|
59
|
-
URI.join(Geminabox.ruby_gems_url, file_name)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def local_content
|
|
63
|
-
File.binread(local_path)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
private
|
|
67
|
-
def encoding
|
|
68
|
-
"UTF-8"
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def ensure_destination_exists
|
|
72
|
-
create_local_folder unless local_folder_exists?
|
|
73
|
-
create_proxy_folder unless proxy_folder_exists?
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def proxy_file_folder
|
|
77
|
-
File.dirname proxy_path
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def proxy_folder_exists?
|
|
81
|
-
Dir.exist?(proxy_file_folder)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def create_proxy_folder
|
|
85
|
-
FileUtils.mkdir_p(proxy_file_folder)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def local_file_folder
|
|
89
|
-
File.dirname local_path
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def local_folder_exists?
|
|
93
|
-
Dir.exist?(local_file_folder)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def create_local_folder
|
|
97
|
-
FileUtils.mkdir_p(local_file_folder)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'sinatra/base'
|
|
4
|
-
require 'net/http'
|
|
5
|
-
|
|
6
|
-
module Geminabox
|
|
7
|
-
module Proxy
|
|
8
|
-
class Hostess < Sinatra::Base
|
|
9
|
-
set :host_authorization, { permitted_hosts: [] }
|
|
10
|
-
|
|
11
|
-
attr_accessor :file_handler
|
|
12
|
-
def serve
|
|
13
|
-
headers["Cache-Control"] = 'no-transform'
|
|
14
|
-
if file_handler
|
|
15
|
-
send_file file_handler.proxy_path
|
|
16
|
-
else
|
|
17
|
-
send_file(data_path, :type => response['Content-Type'])
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
%w[specs.4.8.gz
|
|
22
|
-
latest_specs.4.8.gz
|
|
23
|
-
prerelease_specs.4.8.gz
|
|
24
|
-
].each do |index|
|
|
25
|
-
get "/#{index}" do
|
|
26
|
-
splice_file index
|
|
27
|
-
content_type 'application/x-gzip'
|
|
28
|
-
serve
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
get '/quick/Marshal.4.8/*.gemspec.rz' do
|
|
33
|
-
copy_file request.path_info[1..]
|
|
34
|
-
content_type('application/x-deflate')
|
|
35
|
-
serve
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
%w[specs.4.8
|
|
39
|
-
latest_specs.4.8
|
|
40
|
-
prerelease_specs.4.8
|
|
41
|
-
].each do |index|
|
|
42
|
-
get "/#{index}" do
|
|
43
|
-
splice_file index
|
|
44
|
-
serve
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
get "/gems/*.gem" do
|
|
49
|
-
get_from_rubygems_if_not_local
|
|
50
|
-
serve
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private
|
|
54
|
-
def get_from_rubygems_if_not_local
|
|
55
|
-
|
|
56
|
-
unless File.exist?(data_path)
|
|
57
|
-
ruby_gems_url = Geminabox.ruby_gems_url
|
|
58
|
-
path = File.join(ruby_gems_url, *request.path_info)
|
|
59
|
-
content = Geminabox.http_adapter.get_content(path)
|
|
60
|
-
GemStore.create(IncomingGem.new(StringIO.new(content)))
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def splice_file(file_name)
|
|
66
|
-
self.file_handler = Splicer.make(file_name)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def copy_file(file_name)
|
|
70
|
-
self.file_handler = Copier.copy(file_name)
|
|
71
|
-
rescue ArgumentError
|
|
72
|
-
halt 404
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Rack::Protection normally strips ".." first; this holds without it.
|
|
76
|
-
def data_path
|
|
77
|
-
path = File.expand_path(File.join(Geminabox.data, *request.path_info))
|
|
78
|
-
halt 404 unless path.start_with?(File.expand_path(Geminabox.data) + File::SEPARATOR)
|
|
79
|
-
path
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'tempfile'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
require 'rubygems/util'
|
|
6
|
-
|
|
7
|
-
module Geminabox
|
|
8
|
-
module Proxy
|
|
9
|
-
class Splicer < FileHandler
|
|
10
|
-
|
|
11
|
-
def self.make(file_name)
|
|
12
|
-
splicer = new(file_name)
|
|
13
|
-
splicer.create
|
|
14
|
-
splicer
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def create
|
|
18
|
-
if data = new_content
|
|
19
|
-
f = Tempfile.create('geminabox')
|
|
20
|
-
f.binmode
|
|
21
|
-
begin
|
|
22
|
-
f.write(data)
|
|
23
|
-
ensure
|
|
24
|
-
f.close rescue nil
|
|
25
|
-
end
|
|
26
|
-
FileUtils.mv f.path, splice_path
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def new_content
|
|
31
|
-
if local_file_exists?
|
|
32
|
-
merge_content
|
|
33
|
-
else
|
|
34
|
-
remote_content
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def splice_path
|
|
39
|
-
proxy_path
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def splice_folder_path
|
|
43
|
-
proxy_folder_path
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def splice_file_exists?
|
|
47
|
-
file_exists? splice_path
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def merge_content
|
|
51
|
-
if gzip?
|
|
52
|
-
merge_gziped_content
|
|
53
|
-
else
|
|
54
|
-
merge_text_content
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def gzip?
|
|
59
|
-
/\.gz$/ =~ file_name
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
def merge_gziped_content
|
|
64
|
-
if rc = remote_content
|
|
65
|
-
package(unpackage(local_content) | unpackage(rc))
|
|
66
|
-
else
|
|
67
|
-
local_content
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def unpackage(content)
|
|
72
|
-
Marshal.load(Gem::Util.gunzip(content))
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def package(content)
|
|
76
|
-
Gem::Util.gzip(Marshal.dump(content))
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def merge_text_content
|
|
80
|
-
local_content.to_s + remote_content.to_s
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
data/lib/geminabox/proxy.rb
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Geminabox
|
|
4
|
-
module Proxy
|
|
5
|
-
def self.proxy_path(file)
|
|
6
|
-
File.join File.dirname(__FILE__), 'proxy', file
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
autoload :Hostess, proxy_path('hostess')
|
|
10
|
-
autoload :FileHandler, proxy_path('file_handler')
|
|
11
|
-
autoload :Splicer, proxy_path('splicer')
|
|
12
|
-
autoload :Copier, proxy_path('copier')
|
|
13
|
-
end
|
|
14
|
-
end
|