geminabox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geminabox might be problematic. Click here for more details.
- data/README.markdown +29 -0
- data/lib/geminabox.rb +76 -0
- data/lib/hostess.rb +42 -0
- data/public/master.css +71 -0
- data/views/index.erb +14 -0
- data/views/layout.erb +15 -0
- data/views/upload.erb +4 -0
- metadata +81 -0
data/README.markdown
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Gem in a Box
|
2
|
+
|
3
|
+
![screen shot](http://i50.tinypic.com/2yknxnr.png)
|
4
|
+
|
5
|
+
## Really simple rubygem hosting
|
6
|
+
|
7
|
+
Gem in a box is a simple [sinatra][sinatra] app to allow you to host your own own in-house gems.
|
8
|
+
|
9
|
+
It has no security, or authentication so you should handle this yourself.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
gem install geminabox
|
14
|
+
|
15
|
+
Create a config.ru as follows:
|
16
|
+
|
17
|
+
require "rubygems"
|
18
|
+
require "geminabox"
|
19
|
+
|
20
|
+
Geminabox.data = "/var/geminabox-data" # …or wherever
|
21
|
+
run Geminabox
|
22
|
+
|
23
|
+
And finally, hook up the config.ru as you normally would ([passenger][passenger], [thin][thin], [unicorn][unicorn], whatever floats you boat).
|
24
|
+
|
25
|
+
|
26
|
+
[sinatra]: http://www.sinatrarb.com/
|
27
|
+
[passenger]: http://www.modrails.com/
|
28
|
+
[thin]: http://code.macournoyer.com/thin/
|
29
|
+
[unicorn]: http://unicorn.bogomips.org/
|
data/lib/geminabox.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "builder"
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'rubygems'
|
4
|
+
require "rubygems/indexer"
|
5
|
+
|
6
|
+
require 'hostess'
|
7
|
+
|
8
|
+
class Geminabox < Sinatra::Base
|
9
|
+
enable :static, :methodoverride
|
10
|
+
|
11
|
+
set :public, File.join(File.dirname(__FILE__), *%w[.. public])
|
12
|
+
set :data, File.join(File.dirname(__FILE__), *%w[.. data])
|
13
|
+
set :views, File.join(File.dirname(__FILE__), *%w[.. views])
|
14
|
+
use Hostess
|
15
|
+
|
16
|
+
|
17
|
+
get '/' do
|
18
|
+
begin
|
19
|
+
@gems = Marshal.load(Gem.gunzip(Gem.read_binary( File.join(options.data, "specs.#{Gem.marshal_version}.gz")) ))
|
20
|
+
rescue
|
21
|
+
@gems = []
|
22
|
+
end
|
23
|
+
|
24
|
+
erb :index
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/upload' do
|
28
|
+
erb :upload
|
29
|
+
end
|
30
|
+
|
31
|
+
delete '/gems/*.gem' do
|
32
|
+
File.delete file_path if File.exists? file_path
|
33
|
+
reindex
|
34
|
+
redirect "/"
|
35
|
+
end
|
36
|
+
|
37
|
+
post '/upload' do
|
38
|
+
unless params[:file] && (tmpfile = params[:file][:tempfile]) && (name = params[:file][:filename])
|
39
|
+
@error = "No file selected"
|
40
|
+
return erb(:upload)
|
41
|
+
end
|
42
|
+
|
43
|
+
Dir.mkdir(File.join(options.data, "gems")) unless File.directory? File.join(options.data, "gems")
|
44
|
+
|
45
|
+
File.open(File.join(options.data, "gems", File.basename(name)), "w") do |f|
|
46
|
+
while blk = tmpfile.read(65536)
|
47
|
+
f << blk
|
48
|
+
end
|
49
|
+
end
|
50
|
+
reindex
|
51
|
+
redirect "/"
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def reindex
|
56
|
+
Gem::Indexer.new(options.data).generate_index
|
57
|
+
end
|
58
|
+
|
59
|
+
def file_path
|
60
|
+
File.expand_path(File.join(options.data, *request.path_info))
|
61
|
+
end
|
62
|
+
|
63
|
+
helpers do
|
64
|
+
def url_for(path)
|
65
|
+
url = request.scheme + "://"
|
66
|
+
url << request.host
|
67
|
+
|
68
|
+
if request.scheme == "https" && request.port != 443 ||
|
69
|
+
request.scheme == "http" && request.port != 80
|
70
|
+
url << ":#{request.port}"
|
71
|
+
end
|
72
|
+
|
73
|
+
url << path
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/hostess.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
class Hostess < Sinatra::Base
|
4
|
+
def serve
|
5
|
+
send_file(File.expand_path(File.join(Geminabox.data, *request.path_info)))
|
6
|
+
end
|
7
|
+
|
8
|
+
%w[/specs.4.8.gz
|
9
|
+
/latest_specs.4.8.gz
|
10
|
+
/prerelease_specs.4.8.gz
|
11
|
+
].each do |index|
|
12
|
+
get index do
|
13
|
+
content_type('application/x-gzip')
|
14
|
+
serve
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
%w[/quick/Marshal.4.8/*.gemspec.rz
|
19
|
+
/yaml.Z
|
20
|
+
/Marshal.4.8.Z
|
21
|
+
].each do |deflated_index|
|
22
|
+
get deflated_index do
|
23
|
+
content_type('application/x-deflate')
|
24
|
+
serve
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
%w[/yaml
|
29
|
+
/Marshal.4.8
|
30
|
+
/specs.4.8
|
31
|
+
/latest_specs.4.8
|
32
|
+
/prerelease_specs.4.8
|
33
|
+
].each do |old_index|
|
34
|
+
get old_index do
|
35
|
+
serve
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
get "/gems/*.gem" do
|
40
|
+
serve
|
41
|
+
end
|
42
|
+
end
|
data/public/master.css
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
body {
|
2
|
+
background: #a00;
|
3
|
+
color: #444;
|
4
|
+
font-size: 1.2em;
|
5
|
+
font-family: sans-serif;
|
6
|
+
margin: 0;
|
7
|
+
}
|
8
|
+
|
9
|
+
a {
|
10
|
+
text-decoration: none;
|
11
|
+
color: #00a;
|
12
|
+
}
|
13
|
+
|
14
|
+
a:hover {
|
15
|
+
color: #00f;
|
16
|
+
}
|
17
|
+
|
18
|
+
code {
|
19
|
+
font-size: 0.7em;
|
20
|
+
}
|
21
|
+
|
22
|
+
#content {
|
23
|
+
background: #fff;
|
24
|
+
width: 600px;
|
25
|
+
position: absolute;
|
26
|
+
left: 50%;
|
27
|
+
margin-left: -300px;
|
28
|
+
margin-top: 2em;
|
29
|
+
padding: 1em;
|
30
|
+
border: 1px solid #000;
|
31
|
+
box-shadow: 0 0 3em #fff; -moz-box-shadow: 0 0 3em #fff; -webkit-box-shadow: 0 0 3em #fff;
|
32
|
+
border-radius: 1em; -moz-border-radius: 1em; -webkit-border-radius: 1em;
|
33
|
+
text-align: center;
|
34
|
+
}
|
35
|
+
|
36
|
+
#content h1 {
|
37
|
+
margin: 0;
|
38
|
+
color: #a00;
|
39
|
+
text-shadow: #444 1px 1px 3px;
|
40
|
+
}
|
41
|
+
|
42
|
+
ul.gemlist {
|
43
|
+
list-style: none;
|
44
|
+
margin: 2em 0;
|
45
|
+
padding: 0;
|
46
|
+
}
|
47
|
+
|
48
|
+
ul.gemlist li {
|
49
|
+
margin: 1em;
|
50
|
+
background: #eee;
|
51
|
+
border: 1px solid #444;
|
52
|
+
padding: .4em;
|
53
|
+
border-radius: .5em; -moz-border-radius: .5em; -webkit-border-radius: .5em;
|
54
|
+
position: relative;
|
55
|
+
}
|
56
|
+
|
57
|
+
ul.gemlist li strong {
|
58
|
+
display: block;
|
59
|
+
font-size: 1.2em;
|
60
|
+
}
|
61
|
+
|
62
|
+
ul.gemlist li .delete-form {
|
63
|
+
position: absolute;
|
64
|
+
top: 0;
|
65
|
+
right: 0;
|
66
|
+
display: none;
|
67
|
+
}
|
68
|
+
|
69
|
+
ul.gemlist li:hover .delete-form {
|
70
|
+
display: block;
|
71
|
+
}
|
data/views/index.erb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
<ul class="gemlist">
|
2
|
+
<% @gems.each do |name, version| %>
|
3
|
+
<li>
|
4
|
+
<strong><%= name %> (<%= version %>)</strong>
|
5
|
+
<code>gem install <%= name %> -v "<%= version %>"</code>
|
6
|
+
<form class="delete-form" method="post" action="/gems/<%= name %>-<%= version %>.gem">
|
7
|
+
<input type="hidden" name="_method" value="DELETE" />
|
8
|
+
<input type="submit" value="delete" />
|
9
|
+
</form>
|
10
|
+
</li>
|
11
|
+
<% end %>
|
12
|
+
</ul>
|
13
|
+
|
14
|
+
<a href="upload">Upload Another Gem</a>
|
data/views/layout.erb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Gem in a Box</title>
|
4
|
+
<link rel="stylesheet" href="/master.css" type="text/css" media="screen" charset="utf-8">
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<div id="content">
|
8
|
+
<h1>Gem in a Box</h1>
|
9
|
+
<p>
|
10
|
+
<code>gem sources -a <%= url_for "/" %></code>
|
11
|
+
</p>
|
12
|
+
<%= yield %>
|
13
|
+
</div>
|
14
|
+
</body>
|
15
|
+
</html>
|
data/views/upload.erb
ADDED
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geminabox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Lea
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-07 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: builder
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: contrib@tomlea.co.uk
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.markdown
|
43
|
+
files:
|
44
|
+
- README.markdown
|
45
|
+
- lib/geminabox.rb
|
46
|
+
- lib/hostess.rb
|
47
|
+
- public/master.css
|
48
|
+
- views/index.erb
|
49
|
+
- views/layout.erb
|
50
|
+
- views/upload.erb
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://tomlea.co.uk
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --main
|
58
|
+
- README.markdown
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.3.5
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Really simple rubygem hosting
|
80
|
+
test_files: []
|
81
|
+
|