gemstash 1.0.0.pre.1-java
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 +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +139 -0
- data/Rakefile +35 -0
- data/bin/console +14 -0
- data/bin/gemstash +3 -0
- data/bin/setup +5 -0
- data/docs/config.md +136 -0
- data/docs/debug.md +24 -0
- data/docs/deploy.md +30 -0
- data/docs/mirror.md +30 -0
- data/docs/multiple_sources.md +68 -0
- data/docs/private_gems.md +140 -0
- data/docs/reference.md +308 -0
- data/exe/gemstash +3 -0
- data/gemstash.gemspec +47 -0
- data/gemstash.png +0 -0
- data/lib/gemstash.rb +26 -0
- data/lib/gemstash/authorization.rb +87 -0
- data/lib/gemstash/cache.rb +79 -0
- data/lib/gemstash/cli.rb +71 -0
- data/lib/gemstash/cli/authorize.rb +69 -0
- data/lib/gemstash/cli/base.rb +46 -0
- data/lib/gemstash/cli/setup.rb +173 -0
- data/lib/gemstash/cli/start.rb +52 -0
- data/lib/gemstash/cli/status.rb +21 -0
- data/lib/gemstash/cli/stop.rb +21 -0
- data/lib/gemstash/config.ru +13 -0
- data/lib/gemstash/configuration.rb +41 -0
- data/lib/gemstash/db.rb +15 -0
- data/lib/gemstash/db/authorization.rb +20 -0
- data/lib/gemstash/db/dependency.rb +50 -0
- data/lib/gemstash/db/rubygem.rb +14 -0
- data/lib/gemstash/db/version.rb +51 -0
- data/lib/gemstash/dependencies.rb +93 -0
- data/lib/gemstash/env.rb +150 -0
- data/lib/gemstash/gem_fetcher.rb +50 -0
- data/lib/gemstash/gem_pusher.rb +125 -0
- data/lib/gemstash/gem_source.rb +37 -0
- data/lib/gemstash/gem_source/dependency_caching.rb +40 -0
- data/lib/gemstash/gem_source/private_source.rb +139 -0
- data/lib/gemstash/gem_source/rack_middleware.rb +22 -0
- data/lib/gemstash/gem_source/upstream_source.rb +183 -0
- data/lib/gemstash/gem_unyanker.rb +61 -0
- data/lib/gemstash/gem_yanker.rb +61 -0
- data/lib/gemstash/http_client.rb +77 -0
- data/lib/gemstash/logging.rb +93 -0
- data/lib/gemstash/migrations/01_gem_dependencies.rb +41 -0
- data/lib/gemstash/migrations/02_authorizations.rb +12 -0
- data/lib/gemstash/puma.rb +6 -0
- data/lib/gemstash/rack_env_rewriter.rb +66 -0
- data/lib/gemstash/specs_builder.rb +93 -0
- data/lib/gemstash/storage.rb +207 -0
- data/lib/gemstash/upstream.rb +65 -0
- data/lib/gemstash/version.rb +4 -0
- data/lib/gemstash/web.rb +97 -0
- metadata +304 -0
data/exe/gemstash
ADDED
data/gemstash.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "gemstash/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gemstash"
|
8
|
+
spec.version = Gemstash::VERSION
|
9
|
+
spec.authors = ["Andre Arko"]
|
10
|
+
spec.email = ["andre@arko.net"]
|
11
|
+
spec.platform = "java" if RUBY_PLATFORM == "java"
|
12
|
+
|
13
|
+
spec.summary = "A place to stash gems you'll need"
|
14
|
+
spec.description = "Gemstash acts as a local RubyGems server, caching \
|
15
|
+
copies of gems from RubyGems.org automatically, and eventually letting \
|
16
|
+
you push your own private gems as well."
|
17
|
+
spec.homepage = "https://github.com/bundler/gemstash"
|
18
|
+
spec.license = "MIT"
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject {|f|
|
21
|
+
f.match(%r{^(test|spec|features)/})
|
22
|
+
}
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_runtime_dependency "dalli", "~> 2.7"
|
28
|
+
spec.add_runtime_dependency "lru_redux", "~> 1.1"
|
29
|
+
spec.add_runtime_dependency "puma", "~> 2.14"
|
30
|
+
spec.add_runtime_dependency "sequel", "~> 4.26"
|
31
|
+
spec.add_runtime_dependency "sinatra", "~> 1.4"
|
32
|
+
spec.add_runtime_dependency "thor", "~> 0.19"
|
33
|
+
spec.add_runtime_dependency "faraday", "~> 0.9"
|
34
|
+
spec.add_runtime_dependency "faraday_middleware", "~> 0.10"
|
35
|
+
|
36
|
+
if RUBY_PLATFORM == "java"
|
37
|
+
spec.add_runtime_dependency "jdbc-sqlite3", "~> 3.8"
|
38
|
+
else
|
39
|
+
spec.add_runtime_dependency "sqlite3", "~> 1.3"
|
40
|
+
end
|
41
|
+
|
42
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
43
|
+
spec.add_development_dependency "rack-test", "~> 0.6"
|
44
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
45
|
+
spec.add_development_dependency "rspec", "~> 3.3"
|
46
|
+
spec.add_development_dependency "rubocop", "~> 0.34"
|
47
|
+
end
|
data/gemstash.png
ADDED
Binary file
|
data/lib/gemstash.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#:nodoc:
|
2
|
+
module Gemstash
|
3
|
+
autoload :Authorization, "gemstash/authorization"
|
4
|
+
autoload :DB, "gemstash/db"
|
5
|
+
autoload :Cache, "gemstash/cache"
|
6
|
+
autoload :CLI, "gemstash/cli"
|
7
|
+
autoload :Configuration, "gemstash/configuration"
|
8
|
+
autoload :Dependencies, "gemstash/dependencies"
|
9
|
+
autoload :Env, "gemstash/env"
|
10
|
+
autoload :GemFetcher, "gemstash/gem_fetcher"
|
11
|
+
autoload :GemPusher, "gemstash/gem_pusher"
|
12
|
+
autoload :GemSource, "gemstash/gem_source"
|
13
|
+
autoload :GemUnyanker, "gemstash/gem_unyanker"
|
14
|
+
autoload :GemYanker, "gemstash/gem_yanker"
|
15
|
+
autoload :HTTPClient, "gemstash/http_client"
|
16
|
+
autoload :Logging, "gemstash/logging"
|
17
|
+
autoload :LruReduxClient, "gemstash/cache"
|
18
|
+
autoload :NotAuthorizedError, "gemstash/authorization"
|
19
|
+
autoload :RackEnvRewriter, "gemstash/rack_env_rewriter"
|
20
|
+
autoload :SpecsBuilder, "gemstash/specs_builder"
|
21
|
+
autoload :Storage, "gemstash/storage"
|
22
|
+
autoload :Upstream, "gemstash/upstream"
|
23
|
+
autoload :Web, "gemstash/web"
|
24
|
+
autoload :WebError, "gemstash/http_client"
|
25
|
+
autoload :VERSION, "gemstash/version"
|
26
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module Gemstash
|
4
|
+
# An action was not authorized and should cause the server to send a 401.
|
5
|
+
class NotAuthorizedError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Authorization mechanism to manipulate private gems.
|
9
|
+
class Authorization
|
10
|
+
extend Gemstash::Env::Helper
|
11
|
+
extend Gemstash::Logging
|
12
|
+
VALID_PERMISSIONS = %w(push yank unyank).freeze
|
13
|
+
|
14
|
+
def self.authorize(auth_key, permissions)
|
15
|
+
raise "Authorization key is required!" if auth_key.to_s.strip.empty?
|
16
|
+
raise "Permissions are required!" if permissions.to_s.empty?
|
17
|
+
|
18
|
+
unless permissions == "all"
|
19
|
+
permissions.each do |permission|
|
20
|
+
unless VALID_PERMISSIONS.include?(permission)
|
21
|
+
raise "Invalid permission '#{permission}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
permissions = permissions.join(",")
|
26
|
+
end
|
27
|
+
|
28
|
+
Gemstash::DB::Authorization.insert_or_update(auth_key, permissions)
|
29
|
+
gemstash_env.cache.invalidate_authorization(auth_key)
|
30
|
+
log.info "Authorization '#{auth_key}' updated with access to '#{permissions}'"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.remove(auth_key)
|
34
|
+
record = Gemstash::DB::Authorization[auth_key: auth_key]
|
35
|
+
return unless record
|
36
|
+
record.destroy
|
37
|
+
gemstash_env.cache.invalidate_authorization(auth_key)
|
38
|
+
log.info "Authorization '#{auth_key}' with access to '#{record.permissions}' removed"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.check(auth_key, permission)
|
42
|
+
raise NotAuthorizedError, "Authorization key required" if auth_key.to_s.strip.empty?
|
43
|
+
auth = self[auth_key]
|
44
|
+
raise NotAuthorizedError, "Authorization key is invalid" unless auth
|
45
|
+
raise NotAuthorizedError, "Authorization key doesn't have #{permission} access" unless auth.can?(permission)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.[](auth_key)
|
49
|
+
cached_auth = gemstash_env.cache.authorization(auth_key)
|
50
|
+
return cached_auth if cached_auth
|
51
|
+
record = Gemstash::DB::Authorization[auth_key: auth_key]
|
52
|
+
|
53
|
+
if record
|
54
|
+
auth = new(record)
|
55
|
+
gemstash_env.cache.set_authorization(record.auth_key, auth)
|
56
|
+
auth
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(record)
|
61
|
+
@auth_key = record.auth_key
|
62
|
+
@all = record.permissions == "all"
|
63
|
+
@permissions = Set.new(record.permissions.split(","))
|
64
|
+
end
|
65
|
+
|
66
|
+
def can?(permission)
|
67
|
+
raise "Invalid permission '#{permission}'" unless VALID_PERMISSIONS.include?(permission)
|
68
|
+
all? || @permissions.include?(permission)
|
69
|
+
end
|
70
|
+
|
71
|
+
def all?
|
72
|
+
@all
|
73
|
+
end
|
74
|
+
|
75
|
+
def push?
|
76
|
+
can?("push")
|
77
|
+
end
|
78
|
+
|
79
|
+
def yank?
|
80
|
+
can?("yank")
|
81
|
+
end
|
82
|
+
|
83
|
+
def unyank?
|
84
|
+
can?("unyank")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "lru_redux"
|
2
|
+
require "forwardable"
|
3
|
+
|
4
|
+
module Gemstash
|
5
|
+
# Cache object which knows about what things are cached and what keys to use
|
6
|
+
# for them. Under the hood is either a Memcached client via the dalli gem, or
|
7
|
+
# an in memory client via the lru_redux gem.
|
8
|
+
class Cache
|
9
|
+
EXPIRY = 30 * 60
|
10
|
+
extend Forwardable
|
11
|
+
def_delegators :@client, :flush
|
12
|
+
|
13
|
+
def initialize(client)
|
14
|
+
@client = client
|
15
|
+
end
|
16
|
+
|
17
|
+
def authorization(auth_key)
|
18
|
+
@client.get("auths/#{auth_key}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_authorization(auth_key, value)
|
22
|
+
@client.set("auths/#{auth_key}", value, EXPIRY)
|
23
|
+
end
|
24
|
+
|
25
|
+
def invalidate_authorization(auth_key)
|
26
|
+
@client.delete("auths/#{auth_key}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def dependencies(scope, gems)
|
30
|
+
key_prefix = "deps/v1/#{scope}/"
|
31
|
+
keys = gems.map {|g| "#{key_prefix}#{g}" }
|
32
|
+
|
33
|
+
@client.get_multi(keys) do |key, value|
|
34
|
+
yield(key.sub(key_prefix, ""), value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_dependency(scope, gem, value)
|
39
|
+
@client.set("deps/v1/#{scope}/#{gem}", value, EXPIRY)
|
40
|
+
end
|
41
|
+
|
42
|
+
def invalidate_gem(scope, gem)
|
43
|
+
@client.delete("deps/v1/#{scope}/#{gem}")
|
44
|
+
Gemstash::SpecsBuilder.invalidate_stored if scope == "private"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Wrapper around the lru_redux gem to behave like a dalli Memcached client.
|
49
|
+
class LruReduxClient
|
50
|
+
MAX_SIZE = 500
|
51
|
+
EXPIRY = Gemstash::Cache::EXPIRY
|
52
|
+
extend Forwardable
|
53
|
+
def_delegators :@cache, :delete
|
54
|
+
def_delegator :@cache, :[], :get
|
55
|
+
def_delegator :@cache, :clear, :flush
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@cache = LruRedux::TTL::ThreadSafeCache.new MAX_SIZE, EXPIRY
|
59
|
+
end
|
60
|
+
|
61
|
+
def alive!
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_multi(keys)
|
66
|
+
keys.each do |key|
|
67
|
+
found = true
|
68
|
+
# Atomic fetch... don't rely on nil meaning missing
|
69
|
+
value = @cache.fetch(key) { found = false }
|
70
|
+
next unless found
|
71
|
+
yield(key, value)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def set(key, value, expiry)
|
76
|
+
@cache[key] = value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/gemstash/cli.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "gemstash"
|
2
|
+
require "thor"
|
3
|
+
require "thor/error"
|
4
|
+
|
5
|
+
module Gemstash
|
6
|
+
# Base Command Line Interface class.
|
7
|
+
class CLI < Thor
|
8
|
+
autoload :Authorize, "gemstash/cli/authorize"
|
9
|
+
autoload :Base, "gemstash/cli/base"
|
10
|
+
autoload :Setup, "gemstash/cli/setup"
|
11
|
+
autoload :Start, "gemstash/cli/start"
|
12
|
+
autoload :Status, "gemstash/cli/status"
|
13
|
+
autoload :Stop, "gemstash/cli/stop"
|
14
|
+
|
15
|
+
# Thor::Error for the CLI, which colors the message red.
|
16
|
+
class Error < Thor::Error
|
17
|
+
def initialize(cli, message)
|
18
|
+
super(cli.set_color(message, :red))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.exit_on_failure?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "authorize [PERMISSIONS...]", "Add authorizations to push/yank/unyank private gems"
|
27
|
+
method_option :remove, :type => :boolean, :default => false, :desc =>
|
28
|
+
"Remove an authorization key"
|
29
|
+
method_option :config_file, :type => :string, :desc =>
|
30
|
+
"Config file to save to"
|
31
|
+
method_option :key, :type => :string, :desc =>
|
32
|
+
"Authorization key to create/update/delete (optional unless deleting)"
|
33
|
+
def authorize(*args)
|
34
|
+
Gemstash::CLI::Authorize.new(self, *args).run
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "setup", "Checks for dependencies and does initial setup"
|
38
|
+
method_option :redo, :type => :boolean, :default => false, :desc =>
|
39
|
+
"Redo configuration"
|
40
|
+
method_option :debug, :type => :boolean, :default => false, :desc =>
|
41
|
+
"Show detailed errors"
|
42
|
+
method_option :config_file, :type => :string, :desc =>
|
43
|
+
"Config file to save to"
|
44
|
+
def setup
|
45
|
+
Gemstash::CLI::Setup.new(self).run
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "start", "Starts your gemstash server"
|
49
|
+
method_option :daemonize, :type => :boolean, :default => true, :desc =>
|
50
|
+
"Daemonize the server"
|
51
|
+
method_option :config_file, :type => :string, :desc =>
|
52
|
+
"Config file to load when starting"
|
53
|
+
def start
|
54
|
+
Gemstash::CLI::Start.new(self).run
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "status", "Check the status of your gemstash server"
|
58
|
+
method_option :config_file, :type => :string, :desc =>
|
59
|
+
"Config file to load when checking the status"
|
60
|
+
def status
|
61
|
+
Gemstash::CLI::Status.new(self).run
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "stop", "Stops your gemstash server"
|
65
|
+
method_option :config_file, :type => :string, :desc =>
|
66
|
+
"Config file to load when stopping"
|
67
|
+
def stop
|
68
|
+
Gemstash::CLI::Stop.new(self).run
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "gemstash"
|
2
|
+
require "securerandom"
|
3
|
+
|
4
|
+
module Gemstash
|
5
|
+
class CLI
|
6
|
+
# This implements the command line authorize task to authorize users:
|
7
|
+
# $ gemstash authorize authorized-key
|
8
|
+
class Authorize < Gemstash::CLI::Base
|
9
|
+
def run
|
10
|
+
prepare
|
11
|
+
setup_logging
|
12
|
+
|
13
|
+
if @cli.options[:remove]
|
14
|
+
remove_authorization
|
15
|
+
else
|
16
|
+
save_authorization
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def setup_logging
|
23
|
+
Gemstash::Logging.setup_logger(gemstash_env.base_file("server.log"))
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_authorization
|
27
|
+
raise Gemstash::CLI::Error.new(@cli, "To remove individual permissions, you do not need --remove
|
28
|
+
Instead just authorize with the new set of permissions") unless @args.empty?
|
29
|
+
Gemstash::Authorization.remove(auth_key(false))
|
30
|
+
end
|
31
|
+
|
32
|
+
def save_authorization
|
33
|
+
if @args.include?("all")
|
34
|
+
raise Gemstash::CLI::Error.new(@cli, "Don't specify permissions to authorize for all")
|
35
|
+
end
|
36
|
+
|
37
|
+
@args.each do |arg|
|
38
|
+
unless Gemstash::Authorization::VALID_PERMISSIONS.include?(arg)
|
39
|
+
valid = Gemstash::Authorization::VALID_PERMISSIONS.join(", ")
|
40
|
+
raise Gemstash::CLI::Error.new(@cli, "Invalid permission '#{arg}'\nValid permissions include: #{valid}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Gemstash::Authorization.authorize(auth_key, permissions)
|
45
|
+
end
|
46
|
+
|
47
|
+
def auth_key(allow_generate = true)
|
48
|
+
if @cli.options[:key]
|
49
|
+
@cli.options[:key]
|
50
|
+
elsif allow_generate
|
51
|
+
key = SecureRandom.hex(16)
|
52
|
+
key = SecureRandom.hex(16) while Gemstash::Authorization[key]
|
53
|
+
@cli.say "Your new key is: #{key}"
|
54
|
+
key
|
55
|
+
else
|
56
|
+
raise Gemstash::CLI::Error.new(@cli, "The --key option is required to remove an authorization key")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def permissions
|
61
|
+
if @args.empty?
|
62
|
+
"all"
|
63
|
+
else
|
64
|
+
@args
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "gemstash"
|
2
|
+
|
3
|
+
module Gemstash
|
4
|
+
class CLI
|
5
|
+
# Base class for common functionality for CLI tasks.
|
6
|
+
class Base
|
7
|
+
include Gemstash::Env::Helper
|
8
|
+
|
9
|
+
def initialize(cli, *args)
|
10
|
+
Gemstash::Env.current = Gemstash::Env.new
|
11
|
+
@cli = cli
|
12
|
+
@args = args
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def prepare
|
18
|
+
check_rubygems_version
|
19
|
+
store_config
|
20
|
+
check_gemstash_version
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_rubygems_version
|
24
|
+
@cli.say(@cli.set_color("Rubygems version is too old, " \
|
25
|
+
"please update rubygems by running: " \
|
26
|
+
"gem update --system", :red)) unless
|
27
|
+
Gem::Requirement.new(">= 2.4").satisfied_by?(Gem::Version.new(Gem::VERSION))
|
28
|
+
end
|
29
|
+
|
30
|
+
def store_config
|
31
|
+
config = Gemstash::Configuration.new(file: @cli.options[:config_file])
|
32
|
+
gemstash_env.config = config
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_gemstash_version
|
36
|
+
version = Gem::Version.new(Gemstash::Storage.metadata[:gemstash_version])
|
37
|
+
return if Gem::Requirement.new("<= #{Gemstash::VERSION}").satisfied_by?(Gem::Version.new(version))
|
38
|
+
raise Gemstash::CLI::Error.new(@cli, "Gemstash version is too old")
|
39
|
+
end
|
40
|
+
|
41
|
+
def pidfile_args
|
42
|
+
["--pidfile", gemstash_env.base_file("puma.pid")]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require "gemstash"
|
2
|
+
require "fileutils"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Gemstash
|
6
|
+
class CLI
|
7
|
+
# This implements the command line setup task:
|
8
|
+
# $ gemstash setup
|
9
|
+
class Setup < Gemstash::CLI::Base
|
10
|
+
def initialize(cli)
|
11
|
+
super
|
12
|
+
@config = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
if setup? && !@cli.options[:redo]
|
17
|
+
@cli.say @cli.set_color("Everything is already setup!", :green)
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
check_rubygems_version
|
22
|
+
ask_storage
|
23
|
+
ask_cache
|
24
|
+
ask_database
|
25
|
+
check_cache
|
26
|
+
check_storage
|
27
|
+
check_database
|
28
|
+
store_config
|
29
|
+
save_metadata
|
30
|
+
@cli.say @cli.set_color("You are all setup!", :green)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def config_file
|
36
|
+
@cli.options[:config_file] || Gemstash::Configuration::DEFAULT_FILE
|
37
|
+
end
|
38
|
+
|
39
|
+
def setup?
|
40
|
+
File.exist?(config_file)
|
41
|
+
end
|
42
|
+
|
43
|
+
def say_current_config(option, label)
|
44
|
+
return if gemstash_env.config.default?(option)
|
45
|
+
@cli.say "#{label}: #{gemstash_env.config[option]}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def ask_storage
|
49
|
+
say_current_config(:base_path, "Current base path")
|
50
|
+
path = @cli.ask "Where should files go? [~/.gemstash]", path: true
|
51
|
+
path = Gemstash::Configuration::DEFAULTS[:base_path] if path.empty?
|
52
|
+
@config[:base_path] = File.expand_path(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def ask_cache
|
56
|
+
say_current_config(:cache_type, "Current cache")
|
57
|
+
options = %w(memory memcached)
|
58
|
+
cache = nil
|
59
|
+
|
60
|
+
until cache
|
61
|
+
cache = @cli.ask "Cache with what? [MEMORY, memcached]"
|
62
|
+
cache = cache.downcase
|
63
|
+
cache = "memory" if cache.empty?
|
64
|
+
cache = nil unless options.include?(cache)
|
65
|
+
end
|
66
|
+
|
67
|
+
@config[:cache_type] = cache
|
68
|
+
ask_memcached_details if cache == "memcached"
|
69
|
+
end
|
70
|
+
|
71
|
+
def ask_memcached_details
|
72
|
+
say_current_config(:memcached_servers, "Current Memcached servers")
|
73
|
+
servers = @cli.ask "What is the comma separated Memcached servers? [localhost:11211]"
|
74
|
+
servers = "localhost:11211" if servers.empty?
|
75
|
+
@config[:memcached_servers] = servers
|
76
|
+
end
|
77
|
+
|
78
|
+
def ask_database
|
79
|
+
say_current_config(:db_adapter, "Current database adapter")
|
80
|
+
options = %w(sqlite3 postgres)
|
81
|
+
database = nil
|
82
|
+
|
83
|
+
until database
|
84
|
+
database = @cli.ask "What database adapter? [SQLITE3, postgres]"
|
85
|
+
database = database.downcase
|
86
|
+
database = "sqlite3" if database.empty?
|
87
|
+
database = nil unless options.include?(database)
|
88
|
+
end
|
89
|
+
|
90
|
+
@config[:db_adapter] = database
|
91
|
+
ask_postgres_details if database == "postgres"
|
92
|
+
end
|
93
|
+
|
94
|
+
def ask_postgres_details
|
95
|
+
say_current_config(:db_url, "Current database url")
|
96
|
+
|
97
|
+
if RUBY_PLATFORM == "java"
|
98
|
+
default_value = "jdbc:postgres:///gemstash"
|
99
|
+
else
|
100
|
+
default_value = "postgres:///gemstash"
|
101
|
+
end
|
102
|
+
|
103
|
+
url = @cli.ask "Where is the database? [#{default_value}]"
|
104
|
+
url = default_value if url.empty?
|
105
|
+
@config[:db_url] = url
|
106
|
+
end
|
107
|
+
|
108
|
+
def check_cache
|
109
|
+
@cli.say "Checking that the cache is available"
|
110
|
+
with_new_config { gemstash_env.cache_client.alive! }
|
111
|
+
rescue => e
|
112
|
+
say_error "Cache error", e
|
113
|
+
raise Gemstash::CLI::Error.new(@cli, "The cache is not available")
|
114
|
+
end
|
115
|
+
|
116
|
+
def check_database
|
117
|
+
@cli.say "Checking that the database is available"
|
118
|
+
with_new_config { gemstash_env.db.test_connection }
|
119
|
+
rescue => e
|
120
|
+
say_error "Database error", e
|
121
|
+
raise Gemstash::CLI::Error.new(@cli, "The database is not available")
|
122
|
+
end
|
123
|
+
|
124
|
+
def check_storage
|
125
|
+
with_new_config do
|
126
|
+
dir = gemstash_env.config[:base_path]
|
127
|
+
|
128
|
+
if Dir.exist?(dir)
|
129
|
+
# Do metadata check without using Gemstash::Storage.metadata because
|
130
|
+
# we don't want to store metadata just yet
|
131
|
+
metadata_file = gemstash_env.base_file("metadata.yml")
|
132
|
+
break unless File.exist?(metadata_file)
|
133
|
+
version = Gem::Version.new(YAML.load_file(metadata_file)[:gemstash_version])
|
134
|
+
break if Gem::Requirement.new("<= #{Gemstash::VERSION}").satisfied_by?(Gem::Version.new(version))
|
135
|
+
raise Gemstash::CLI::Error.new(@cli, "The base path already exists with a newer version of Gemstash")
|
136
|
+
else
|
137
|
+
@cli.say "Creating the file storage path '#{dir}'"
|
138
|
+
FileUtils.mkpath(dir)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def store_config
|
144
|
+
config_dir = File.dirname(config_file)
|
145
|
+
FileUtils.mkpath(config_dir) unless Dir.exist?(config_dir)
|
146
|
+
File.write(config_file, YAML.dump(@config))
|
147
|
+
end
|
148
|
+
|
149
|
+
def save_metadata
|
150
|
+
with_new_config do
|
151
|
+
# Touch metadata to ensure it gets written
|
152
|
+
Gemstash::Storage.metadata
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def say_error(title, error)
|
157
|
+
return unless @cli.options[:debug]
|
158
|
+
@cli.say @cli.set_color("#{title}: #{error}", :red)
|
159
|
+
|
160
|
+
error.backtrace.each do |line|
|
161
|
+
@cli.say @cli.set_color(" #{line}", :red)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def with_new_config
|
166
|
+
gemstash_env.config = Gemstash::Configuration.new(config: @config)
|
167
|
+
yield
|
168
|
+
ensure
|
169
|
+
gemstash_env.reset
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|