geminabox-jgraichen 0.12.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +109 -0
- data/lib/geminabox.rb +76 -0
- data/lib/geminabox/disk_cache.rb +73 -0
- data/lib/geminabox/gem_list_merge.rb +51 -0
- data/lib/geminabox/gem_store.rb +99 -0
- data/lib/geminabox/gem_store_error.rb +13 -0
- data/lib/geminabox/gem_version.rb +40 -0
- data/lib/geminabox/gem_version_collection.rb +65 -0
- data/lib/geminabox/hostess.rb +46 -0
- data/lib/geminabox/incoming_gem.rb +70 -0
- data/lib/geminabox/indexer.rb +46 -0
- data/lib/geminabox/proxy.rb +13 -0
- data/lib/geminabox/proxy/copier.rb +29 -0
- data/lib/geminabox/proxy/file_handler.rb +93 -0
- data/lib/geminabox/proxy/hostess.rb +88 -0
- data/lib/geminabox/proxy/splicer.rb +67 -0
- data/lib/geminabox/rubygems_dependency.rb +27 -0
- data/lib/geminabox/server.rb +285 -0
- data/lib/geminabox/version.rb +3 -0
- data/lib/geminabox_client.rb +60 -0
- data/lib/rubygems/commands/inabox_command.rb +91 -0
- data/lib/rubygems_plugin.rb +2 -0
- data/public/favicon.ico +0 -0
- data/public/jquery.js +16 -0
- data/public/master.css +155 -0
- data/public/master.js +5 -0
- data/views/atom.erb +29 -0
- data/views/gem.erb +38 -0
- data/views/index.erb +56 -0
- data/views/layout.erb +16 -0
- data/views/upload.erb +8 -0
- metadata +167 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 00f38a41be22997b62d4341e5d68fc1ae280d437
|
4
|
+
data.tar.gz: 032882e5bbe65a04f23bf6451dce7d0a082cfbce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43ef7e700a853dadcc6b2aac1d47b3edbf8af7db278995c2ebf42dabee01c55e6188db8b8165141215379e5c7ba01b37382586fea88eafe2a78ad7272dcbec3d
|
7
|
+
data.tar.gz: 4c3b246dd5984e805f2dd21e8f798d049e046072c103c6e02377aca9b79fb8af0456f5755f0165ff8781b85f2b47310f5be53676fa6f5d4dae26904f3ad651d7
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Tom Lea, Jack Foy, and Rob Nichols
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Gem in a Box – Really simple rubygem hosting
|
2
|
+
[![Build Status](https://secure.travis-ci.org/geminabox/geminabox.png)](http://travis-ci.org/geminabox/geminabox)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/geminabox.png)](http://badge.fury.io/rb/geminabox)
|
4
|
+
|
5
|
+
Geminabox lets you host your own gems, and push new gems to it just like with rubygems.org.
|
6
|
+
The bundler dependencies API is supported out of the box.
|
7
|
+
Authentication is left up to either the web server, or the Rack stack.
|
8
|
+
For basic auth, try [Rack::Auth](http://rack.rubyforge.org/doc/Rack/Auth/Basic.html).
|
9
|
+
|
10
|
+
![screen shot](http://pics.tomlea.co.uk/bbbba6/geminabox.png)
|
11
|
+
|
12
|
+
## System Requirements
|
13
|
+
|
14
|
+
Tested on Mac OS X 10.8.2
|
15
|
+
Ruby 1.9.3-392
|
16
|
+
|
17
|
+
Tests fail on Ruby 2.0.0-p0
|
18
|
+
|
19
|
+
## Server Setup
|
20
|
+
|
21
|
+
gem install geminabox
|
22
|
+
|
23
|
+
Create a config.ru as follows:
|
24
|
+
|
25
|
+
require "rubygems"
|
26
|
+
require "geminabox"
|
27
|
+
|
28
|
+
Geminabox.data = "/var/geminabox-data" # ... or wherever
|
29
|
+
run Geminabox::Server
|
30
|
+
|
31
|
+
Start your gem server with 'rackup' to run WEBrick or hook up the config.ru as you normally would ([passenger][passenger], [thin][thin], [unicorn][unicorn], whatever floats your boat).
|
32
|
+
|
33
|
+
## Legacy RubyGems index
|
34
|
+
|
35
|
+
RubyGems supports generating indexes for the so called legacy versions (< 1.2), and since it is very rare to use such versions nowadays, it can be disabled, thus improving indexing times for large repositories. If it's safe for your application, you can disable support for these legacy versions by adding the following configuration to your config.ru file:
|
36
|
+
|
37
|
+
Geminabox.build_legacy = false
|
38
|
+
|
39
|
+
## RubyGems Proxy
|
40
|
+
|
41
|
+
Geminabox can be configured to pull gems, it does not currently have, from rubygems.org. To enable this mode you can either:
|
42
|
+
|
43
|
+
Set RUBYGEM_PROXY to true in the environment:
|
44
|
+
|
45
|
+
RUBYGEMS_PROXY=true rackup
|
46
|
+
|
47
|
+
Or in config.ru (before the run command), set:
|
48
|
+
|
49
|
+
Geminabox.rubygems_proxy = true
|
50
|
+
|
51
|
+
## Client Usage
|
52
|
+
|
53
|
+
Since version 0.10, Geminabox supports the standard gemcutter push API:
|
54
|
+
|
55
|
+
gem push pkg/my-awesome-gem-1.0.gem --host HOST
|
56
|
+
|
57
|
+
You can also use the gem plugin:
|
58
|
+
|
59
|
+
gem install geminabox
|
60
|
+
|
61
|
+
gem inabox pkg/my-awesome-gem-1.0.gem
|
62
|
+
|
63
|
+
Configure Gem in a box (interactive prompt to specify where to upload to):
|
64
|
+
|
65
|
+
gem inabox -c
|
66
|
+
|
67
|
+
Change the host to upload to:
|
68
|
+
|
69
|
+
gem inabox -g HOST
|
70
|
+
|
71
|
+
Simples!
|
72
|
+
|
73
|
+
## Command Line Help
|
74
|
+
|
75
|
+
Usage: gem inabox GEM [options]
|
76
|
+
|
77
|
+
Options:
|
78
|
+
-c, --configure Configure GemInABox
|
79
|
+
-g, --host HOST Host to upload to.
|
80
|
+
-o, --overwrite Overwrite Gem.
|
81
|
+
|
82
|
+
|
83
|
+
Common Options:
|
84
|
+
-h, --help Get help on this command
|
85
|
+
-V, --[no-]verbose Set the verbose level of output
|
86
|
+
-q, --quiet Silence commands
|
87
|
+
--config-file FILE Use this config file instead of default
|
88
|
+
--backtrace Show stack backtrace on errors
|
89
|
+
--debug Turn on Ruby debugging
|
90
|
+
|
91
|
+
|
92
|
+
Arguments:
|
93
|
+
GEM built gem to push up
|
94
|
+
|
95
|
+
Summary:
|
96
|
+
Push a gem up to your GemInABox
|
97
|
+
|
98
|
+
Description:
|
99
|
+
Push a gem up to your GemInABox
|
100
|
+
|
101
|
+
## Licence
|
102
|
+
|
103
|
+
Fork it, mod it, choose it, use it, make it better. All under the MIT License.
|
104
|
+
|
105
|
+
[WTFBPPL]: http://tomlea.co.uk/WTFBPPL.txt
|
106
|
+
[sinatra]: http://www.sinatrarb.com/
|
107
|
+
[passenger]: http://www.modrails.com/
|
108
|
+
[thin]: http://code.macournoyer.com/thin/
|
109
|
+
[unicorn]: http://unicorn.bogomips.org/
|
data/lib/geminabox.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'builder'
|
4
|
+
require 'sinatra/base'
|
5
|
+
require 'rubygems/user_interaction'
|
6
|
+
require 'rubygems/indexer'
|
7
|
+
require 'rubygems/package'
|
8
|
+
require 'rss/atom'
|
9
|
+
require 'tempfile'
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
module Geminabox
|
13
|
+
|
14
|
+
require_relative 'geminabox/version'
|
15
|
+
require_relative 'geminabox/proxy'
|
16
|
+
|
17
|
+
def self.geminabox_path(file)
|
18
|
+
File.join File.dirname(__FILE__), 'geminabox', file
|
19
|
+
end
|
20
|
+
|
21
|
+
autoload :Hostess, geminabox_path('hostess')
|
22
|
+
autoload :GemStore, geminabox_path('gem_store')
|
23
|
+
autoload :GemStoreError, geminabox_path('gem_store_error')
|
24
|
+
autoload :RubygemsDependency, geminabox_path('rubygems_dependency')
|
25
|
+
autoload :GemListMerge, geminabox_path('gem_list_merge')
|
26
|
+
autoload :GemVersion, geminabox_path('gem_version')
|
27
|
+
autoload :GemVersionCollection, geminabox_path('gem_version_collection')
|
28
|
+
autoload :Server, geminabox_path('server')
|
29
|
+
autoload :DiskCache, geminabox_path('disk_cache')
|
30
|
+
autoload :IncomingGem, geminabox_path('incoming_gem')
|
31
|
+
|
32
|
+
class << self
|
33
|
+
|
34
|
+
attr_accessor(
|
35
|
+
:data,
|
36
|
+
:public_folder,
|
37
|
+
:build_legacy,
|
38
|
+
:incremental_updates,
|
39
|
+
:views,
|
40
|
+
:allow_replace,
|
41
|
+
:gem_permissions,
|
42
|
+
:allow_delete,
|
43
|
+
:rubygems_proxy
|
44
|
+
)
|
45
|
+
|
46
|
+
def set_defaults(defaults)
|
47
|
+
defaults.each do |method, default|
|
48
|
+
variable = "@#{method}"
|
49
|
+
instance_variable_set(variable, default) unless instance_variable_get(variable)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def settings
|
54
|
+
Server.settings
|
55
|
+
end
|
56
|
+
|
57
|
+
def call(env)
|
58
|
+
Server.call env
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
set_defaults(
|
63
|
+
|
64
|
+
data: File.join(File.dirname(__FILE__), *%w[.. data]),
|
65
|
+
public_folder: File.join(File.dirname(__FILE__), *%w[.. public]),
|
66
|
+
build_legacy: false,
|
67
|
+
incremental_updates: true,
|
68
|
+
views: File.join(File.dirname(__FILE__), *%w[.. views]),
|
69
|
+
allow_replace: false,
|
70
|
+
gem_permissions: 0644,
|
71
|
+
rubygems_proxy: (ENV['RUBYGEMS_PROXY'] == 'true'),
|
72
|
+
allow_delete: true
|
73
|
+
|
74
|
+
)
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
module Geminabox
|
3
|
+
class Geminabox::DiskCache
|
4
|
+
attr_reader :root_path
|
5
|
+
|
6
|
+
def initialize(root_path)
|
7
|
+
@root_path = root_path
|
8
|
+
ensure_dir_exists!
|
9
|
+
end
|
10
|
+
|
11
|
+
def flush_key(key)
|
12
|
+
path = path(key_hash(key))
|
13
|
+
FileUtils.rm_f(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def flush
|
17
|
+
FileUtils.rm_rf(root_path)
|
18
|
+
ensure_dir_exists!
|
19
|
+
end
|
20
|
+
|
21
|
+
def cache(key)
|
22
|
+
key_hash = key_hash(key)
|
23
|
+
read(key_hash) || write(key_hash, yield)
|
24
|
+
end
|
25
|
+
|
26
|
+
def marshal_cache(key)
|
27
|
+
key_hash = key_hash(key)
|
28
|
+
marshal_read(key_hash) || marshal_write(key_hash, yield)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def ensure_dir_exists!
|
34
|
+
FileUtils.mkdir_p(root_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def key_hash(key)
|
38
|
+
Digest::MD5.hexdigest(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
def path(key_hash)
|
42
|
+
File.join(root_path, key_hash)
|
43
|
+
end
|
44
|
+
|
45
|
+
def read(key_hash)
|
46
|
+
read_int(key_hash) { |path| File.read(path) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def marshal_read(key_hash)
|
50
|
+
read_int(key_hash) { |path| Marshal.load(File.open(path)) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def read_int(key_hash)
|
54
|
+
path = path(key_hash)
|
55
|
+
yield(path) if File.exists?(path)
|
56
|
+
end
|
57
|
+
|
58
|
+
def write(key_hash, value)
|
59
|
+
write_int(key_hash) { |f| f << value }
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def marshal_write(key_hash, value)
|
64
|
+
write_int(key_hash) { |f| Marshal.dump(value, f) }
|
65
|
+
value
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_int(key_hash)
|
69
|
+
File.open(path(key_hash), 'wb') { |f| yield(f) }
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Geminabox
|
2
|
+
class GemListMerge
|
3
|
+
attr_accessor :list
|
4
|
+
|
5
|
+
def self.from(*lists)
|
6
|
+
lists.map{|list| new(list)}.inject(:merge)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(list)
|
10
|
+
@list = list
|
11
|
+
end
|
12
|
+
|
13
|
+
def merge(other)
|
14
|
+
combine_hashes(other).values.flatten.sort do |x, y|
|
15
|
+
x.values[ignore_dependencies] <=> y.values[ignore_dependencies]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
list.each do |item|
|
21
|
+
ensure_symbols_as_keys(item)
|
22
|
+
name = item[:name].to_sym
|
23
|
+
collection[name] ||= []
|
24
|
+
collection[name] << item unless collection[name].include?(item)
|
25
|
+
end
|
26
|
+
collection
|
27
|
+
end
|
28
|
+
|
29
|
+
def collection
|
30
|
+
@collection ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def combine_hashes(other)
|
34
|
+
hash.merge(other.hash) do |key, value, other_value|
|
35
|
+
(value + other_value).uniq{|v| v.values[ignore_dependencies]}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ignore_dependencies
|
40
|
+
0..-2
|
41
|
+
end
|
42
|
+
|
43
|
+
def ensure_symbols_as_keys(item)
|
44
|
+
item.keys.each do |key|
|
45
|
+
next if key.kind_of? Symbol
|
46
|
+
item[key.to_sym] = item.delete(key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Geminabox
|
2
|
+
|
3
|
+
class GemStore
|
4
|
+
attr_accessor :gem, :overwrite
|
5
|
+
|
6
|
+
def self.create(gem, overwrite = false)
|
7
|
+
gem_store = new(gem, overwrite)
|
8
|
+
gem_store.save
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(gem, overwrite = false)
|
12
|
+
@gem = gem
|
13
|
+
@overwrite = overwrite && overwrite == 'true'
|
14
|
+
end
|
15
|
+
|
16
|
+
def save
|
17
|
+
ensure_gem_valid
|
18
|
+
prepare_data_folders
|
19
|
+
check_replacement_status
|
20
|
+
write_and_index
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepare_data_folders
|
24
|
+
ensure_existing_data_folder_compatible
|
25
|
+
begin
|
26
|
+
FileUtils.mkdir_p(File.join(Geminabox.data, "gems"))
|
27
|
+
rescue
|
28
|
+
raise GemStoreError.new(
|
29
|
+
500,
|
30
|
+
"Could not create #{File.expand_path(Geminabox.data)}."
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_replacement_status
|
36
|
+
if !overwrite and Geminabox::Server.disallow_replace? and File.exist?(gem.dest_filename)
|
37
|
+
if existing_file_digest != gem.hexdigest
|
38
|
+
raise GemStoreError.new(409, "Updating an existing gem is not permitted.\nYou should either delete the existing version, or change your version number.")
|
39
|
+
else
|
40
|
+
raise GemStoreError.new(200, "Ignoring upload, you uploaded the same thing previously.\nPlease use -o to ovewrite.")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ensure_gem_valid
|
46
|
+
raise GemStoreError.new(400, "Cannot process gem") unless gem.valid?
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def ensure_existing_data_folder_compatible
|
51
|
+
if File.exists? Geminabox.data
|
52
|
+
ensure_data_folder_is_directory
|
53
|
+
ensure_data_folder_is_writable
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def ensure_data_folder_is_directory
|
58
|
+
raise GemStoreError.new(
|
59
|
+
500,
|
60
|
+
"Please ensure #{File.expand_path(Geminabox.data)} is a directory."
|
61
|
+
) unless File.directory? Geminabox.data
|
62
|
+
end
|
63
|
+
|
64
|
+
def ensure_data_folder_is_writable
|
65
|
+
raise GemStoreError.new(
|
66
|
+
500,
|
67
|
+
"Please ensure #{File.expand_path(Geminabox.data)} is writable by the geminabox web server."
|
68
|
+
) unless File.writable? Geminabox.data
|
69
|
+
end
|
70
|
+
|
71
|
+
def existing_file_digest
|
72
|
+
Digest::SHA1.file(gem.dest_filename).hexdigest
|
73
|
+
end
|
74
|
+
|
75
|
+
def write_and_index
|
76
|
+
tmpfile = gem.gem_data
|
77
|
+
atomic_write(gem.dest_filename) do |f|
|
78
|
+
while blk = tmpfile.read(65536)
|
79
|
+
f << blk
|
80
|
+
end
|
81
|
+
end
|
82
|
+
Geminabox::Server.reindex
|
83
|
+
end
|
84
|
+
|
85
|
+
# based on http://as.rubyonrails.org/classes/File.html
|
86
|
+
def atomic_write(file_name)
|
87
|
+
temp_dir = File.join(Geminabox.data, "_temp")
|
88
|
+
FileUtils.mkdir_p(temp_dir)
|
89
|
+
temp_file = Tempfile.new("." + File.basename(file_name), temp_dir)
|
90
|
+
temp_file.binmode
|
91
|
+
yield temp_file
|
92
|
+
temp_file.close
|
93
|
+
File.rename(temp_file.path, file_name)
|
94
|
+
File.chmod(Geminabox::Server.gem_permissions, file_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|