pbox 1.17.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYRIGHT +1 -0
- data/LICENSE +11 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/autocomplete/pbox_bash +1639 -0
- data/bin/pbox +37 -0
- data/conf/protonbox.conf +8 -0
- data/features/assets/deploy.tar.gz +0 -0
- data/features/core_feature.rb +178 -0
- data/features/deployments_feature.rb +127 -0
- data/features/domains_feature.rb +49 -0
- data/features/keys_feature.rb +37 -0
- data/features/members_feature.rb +166 -0
- data/lib/rhc/auth/basic.rb +64 -0
- data/lib/rhc/auth/token.rb +102 -0
- data/lib/rhc/auth/token_store.rb +53 -0
- data/lib/rhc/auth.rb +5 -0
- data/lib/rhc/autocomplete.rb +66 -0
- data/lib/rhc/autocomplete_templates/bash.erb +39 -0
- data/lib/rhc/cartridge_helpers.rb +118 -0
- data/lib/rhc/cli.rb +40 -0
- data/lib/rhc/command_runner.rb +186 -0
- data/lib/rhc/commands/account.rb +25 -0
- data/lib/rhc/commands/alias.rb +124 -0
- data/lib/rhc/commands/app.rb +701 -0
- data/lib/rhc/commands/apps.rb +20 -0
- data/lib/rhc/commands/authorization.rb +96 -0
- data/lib/rhc/commands/base.rb +174 -0
- data/lib/rhc/commands/cartridge.rb +326 -0
- data/lib/rhc/commands/deployment.rb +82 -0
- data/lib/rhc/commands/domain.rb +167 -0
- data/lib/rhc/commands/env.rb +142 -0
- data/lib/rhc/commands/git_clone.rb +29 -0
- data/lib/rhc/commands/logout.rb +51 -0
- data/lib/rhc/commands/member.rb +148 -0
- data/lib/rhc/commands/port_forward.rb +197 -0
- data/lib/rhc/commands/server.rb +40 -0
- data/lib/rhc/commands/setup.rb +60 -0
- data/lib/rhc/commands/snapshot.rb +137 -0
- data/lib/rhc/commands/ssh.rb +51 -0
- data/lib/rhc/commands/sshkey.rb +97 -0
- data/lib/rhc/commands/tail.rb +47 -0
- data/lib/rhc/commands/threaddump.rb +14 -0
- data/lib/rhc/commands.rb +396 -0
- data/lib/rhc/config.rb +320 -0
- data/lib/rhc/context_helper.rb +121 -0
- data/lib/rhc/core_ext.rb +202 -0
- data/lib/rhc/coverage_helper.rb +33 -0
- data/lib/rhc/deployment_helpers.rb +88 -0
- data/lib/rhc/exceptions.rb +232 -0
- data/lib/rhc/git_helpers.rb +91 -0
- data/lib/rhc/help_formatter.rb +55 -0
- data/lib/rhc/helpers.rb +477 -0
- data/lib/rhc/highline_extensions.rb +479 -0
- data/lib/rhc/json.rb +51 -0
- data/lib/rhc/output_helpers.rb +260 -0
- data/lib/rhc/rest/activation.rb +11 -0
- data/lib/rhc/rest/alias.rb +42 -0
- data/lib/rhc/rest/api.rb +87 -0
- data/lib/rhc/rest/application.rb +332 -0
- data/lib/rhc/rest/attributes.rb +36 -0
- data/lib/rhc/rest/authorization.rb +8 -0
- data/lib/rhc/rest/base.rb +79 -0
- data/lib/rhc/rest/cartridge.rb +154 -0
- data/lib/rhc/rest/client.rb +650 -0
- data/lib/rhc/rest/deployment.rb +18 -0
- data/lib/rhc/rest/domain.rb +98 -0
- data/lib/rhc/rest/environment_variable.rb +15 -0
- data/lib/rhc/rest/gear_group.rb +16 -0
- data/lib/rhc/rest/httpclient.rb +145 -0
- data/lib/rhc/rest/key.rb +44 -0
- data/lib/rhc/rest/membership.rb +105 -0
- data/lib/rhc/rest/mock.rb +1024 -0
- data/lib/rhc/rest/user.rb +32 -0
- data/lib/rhc/rest.rb +148 -0
- data/lib/rhc/ssh_helpers.rb +378 -0
- data/lib/rhc/tar_gz.rb +51 -0
- data/lib/rhc/usage_templates/command_help.erb +51 -0
- data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
- data/lib/rhc/usage_templates/help.erb +35 -0
- data/lib/rhc/usage_templates/missing_help.erb +1 -0
- data/lib/rhc/usage_templates/options_help.erb +12 -0
- data/lib/rhc/vendor/okjson.rb +600 -0
- data/lib/rhc/vendor/parseconfig.rb +178 -0
- data/lib/rhc/vendor/sshkey.rb +253 -0
- data/lib/rhc/vendor/zliby.rb +628 -0
- data/lib/rhc/version.rb +5 -0
- data/lib/rhc/wizard.rb +633 -0
- data/lib/rhc.rb +34 -0
- data/spec/coverage_helper.rb +89 -0
- data/spec/direct_execution_helper.rb +338 -0
- data/spec/keys/example.pem +23 -0
- data/spec/keys/example_private.pem +27 -0
- data/spec/keys/server.pem +19 -0
- data/spec/rest_spec_helper.rb +31 -0
- data/spec/rhc/assets/cert.crt +22 -0
- data/spec/rhc/assets/cert_key_rsa +27 -0
- data/spec/rhc/assets/empty.txt +0 -0
- data/spec/rhc/assets/env_vars.txt +7 -0
- data/spec/rhc/assets/env_vars_2.txt +1 -0
- data/spec/rhc/assets/foo.txt +1 -0
- data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
- data/spec/rhc/assets/targz_sample.tar.gz +0 -0
- data/spec/rhc/auth_spec.rb +442 -0
- data/spec/rhc/cli_spec.rb +188 -0
- data/spec/rhc/command_spec.rb +435 -0
- data/spec/rhc/commands/account_spec.rb +42 -0
- data/spec/rhc/commands/alias_spec.rb +333 -0
- data/spec/rhc/commands/app_spec.rb +754 -0
- data/spec/rhc/commands/apps_spec.rb +39 -0
- data/spec/rhc/commands/authorization_spec.rb +145 -0
- data/spec/rhc/commands/cartridge_spec.rb +641 -0
- data/spec/rhc/commands/deployment_spec.rb +286 -0
- data/spec/rhc/commands/domain_spec.rb +383 -0
- data/spec/rhc/commands/env_spec.rb +493 -0
- data/spec/rhc/commands/git_clone_spec.rb +80 -0
- data/spec/rhc/commands/logout_spec.rb +86 -0
- data/spec/rhc/commands/member_spec.rb +228 -0
- data/spec/rhc/commands/port_forward_spec.rb +217 -0
- data/spec/rhc/commands/server_spec.rb +69 -0
- data/spec/rhc/commands/setup_spec.rb +118 -0
- data/spec/rhc/commands/snapshot_spec.rb +179 -0
- data/spec/rhc/commands/ssh_spec.rb +163 -0
- data/spec/rhc/commands/sshkey_spec.rb +188 -0
- data/spec/rhc/commands/tail_spec.rb +81 -0
- data/spec/rhc/commands/threaddump_spec.rb +84 -0
- data/spec/rhc/config_spec.rb +407 -0
- data/spec/rhc/helpers_spec.rb +524 -0
- data/spec/rhc/highline_extensions_spec.rb +314 -0
- data/spec/rhc/json_spec.rb +30 -0
- data/spec/rhc/rest_application_spec.rb +248 -0
- data/spec/rhc/rest_client_spec.rb +752 -0
- data/spec/rhc/rest_spec.rb +740 -0
- data/spec/rhc/targz_spec.rb +55 -0
- data/spec/rhc/wizard_spec.rb +756 -0
- data/spec/spec_helper.rb +575 -0
- data/spec/wizard_spec_helper.rb +330 -0
- metadata +435 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
module RHC::Auth
|
2
|
+
class Token
|
3
|
+
def initialize(opt, auth=nil, store=nil)
|
4
|
+
if opt.is_a?(String)
|
5
|
+
@token = opt
|
6
|
+
else
|
7
|
+
@options = opt || Commander::Command::Options.new
|
8
|
+
@token = options[:token]
|
9
|
+
@no_interactive = options[:noprompt]
|
10
|
+
@allows_tokens = options[:use_authorization_tokens]
|
11
|
+
end
|
12
|
+
@auth = auth
|
13
|
+
@store = store
|
14
|
+
read_token
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_request(request)
|
18
|
+
if token
|
19
|
+
debug "Using token authentication"
|
20
|
+
(request[:headers] ||= {})['authorization'] = "Bearer #{token}"
|
21
|
+
elsif auth and (!@allows_tokens or @can_get_token == false)
|
22
|
+
debug "Bypassing token auth"
|
23
|
+
auth.to_request(request)
|
24
|
+
end
|
25
|
+
request
|
26
|
+
end
|
27
|
+
|
28
|
+
def retry_auth?(response, client)
|
29
|
+
if response.status == 401
|
30
|
+
token_rejected(response, client)
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def username
|
37
|
+
auth && auth.respond_to?(:username) && auth.username || options[:username]
|
38
|
+
end
|
39
|
+
|
40
|
+
def save(token)
|
41
|
+
store.put(username, protonbox_server, token) if store
|
42
|
+
@token = token
|
43
|
+
end
|
44
|
+
|
45
|
+
def can_authenticate?
|
46
|
+
token || auth && auth.can_authenticate?
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
include RHC::Helpers
|
51
|
+
attr_reader :options, :token, :auth, :store
|
52
|
+
|
53
|
+
def token_rejected(response, client)
|
54
|
+
has_token = !!token
|
55
|
+
@token = nil
|
56
|
+
|
57
|
+
unless auth && auth.can_authenticate?
|
58
|
+
if has_token
|
59
|
+
raise RHC::Rest::TokenExpiredOrInvalid, "Your authorization token is expired or invalid."
|
60
|
+
end
|
61
|
+
debug "Cannot authenticate via token or password, exiting"
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
if has_token
|
66
|
+
if cannot_retry?
|
67
|
+
raise RHC::Rest::TokenExpiredOrInvalid, "Your authorization token is expired or invalid."
|
68
|
+
end
|
69
|
+
if not client.supports_sessions?
|
70
|
+
raise RHC::Rest::AuthorizationsNotSupported
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
@can_get_token = client.supports_sessions? && @allows_tokens
|
75
|
+
|
76
|
+
if has_token
|
77
|
+
warn "Your authorization token has expired. Please sign in now to continue."
|
78
|
+
elsif @can_get_token
|
79
|
+
info "Please sign in to start a new session to #{protonbox_server}."
|
80
|
+
end
|
81
|
+
|
82
|
+
return auth.retry_auth?(response, client) unless @can_get_token
|
83
|
+
|
84
|
+
debug "Creating a new authorization token"
|
85
|
+
if auth_token = client.new_session(:auth => auth)
|
86
|
+
@fetch_once = true
|
87
|
+
save(auth_token.token)
|
88
|
+
true
|
89
|
+
else
|
90
|
+
auth.retry_auth?(response, client)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_token
|
95
|
+
@token ||= store.get(username, protonbox_server) if store
|
96
|
+
end
|
97
|
+
|
98
|
+
def cannot_retry?
|
99
|
+
!@fetch_once && @no_interactive
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module RHC::Auth
|
4
|
+
class TokenStore
|
5
|
+
def initialize(dir)
|
6
|
+
@dir = dir
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(login, server)
|
10
|
+
self[key(login,server)]
|
11
|
+
end
|
12
|
+
|
13
|
+
def put(login, server, token)
|
14
|
+
self[key(login,server)] = token
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
Dir[File.join(@dir, "token_*")].
|
19
|
+
each{ |f| File.delete(f) unless File.directory?(f) }.
|
20
|
+
present?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def path(key)
|
25
|
+
File.join(@dir, filename(key))
|
26
|
+
end
|
27
|
+
|
28
|
+
def filename(key)
|
29
|
+
"token_#{Base64.encode64(Digest::MD5.digest(key)).gsub(/[^\w\@]/,'')}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def []=(key, value)
|
33
|
+
file = path(key)
|
34
|
+
FileUtils.mkdir_p File.dirname(file)
|
35
|
+
File.open(file, 'w'){ |f| f.write(value) }
|
36
|
+
File.chmod(0600, file)
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](key)
|
41
|
+
s = IO.read(path(key)).presence
|
42
|
+
s = s.strip.gsub(/[\n\r\t]/,'') if s
|
43
|
+
s
|
44
|
+
rescue Errno::ENOENT
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def key(login, server)
|
49
|
+
"#{login || ''}@#{server}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/rhc/auth.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module RHC
|
2
|
+
class AutoComplete
|
3
|
+
attr_reader :runner
|
4
|
+
|
5
|
+
def initialize(runner=::Commander::Runner.instance, shell='bash')
|
6
|
+
@runner, @shell = runner, shell
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
@s ||= template.result AutoCompleteBindings.new(self).get_binding
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def template
|
16
|
+
@template ||= ERB.new(File.read(File.join(File.dirname(__FILE__), 'autocomplete_templates', "#{@shell}.erb")), nil, '-')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class AutoCompleteBindings
|
21
|
+
attr_reader :commands, :top_level_commands, :global_options
|
22
|
+
|
23
|
+
def initialize(data)
|
24
|
+
@commands = {}
|
25
|
+
@top_level_commands = []
|
26
|
+
|
27
|
+
data.runner.commands.each_pair do |name, cmd|
|
28
|
+
next if cmd.summary.nil?
|
29
|
+
next if cmd.deprecated(name)
|
30
|
+
|
31
|
+
if cmd.root?
|
32
|
+
if cmd.name == name
|
33
|
+
@top_level_commands << name
|
34
|
+
end
|
35
|
+
else
|
36
|
+
@top_level_commands << name if name == cmd.name
|
37
|
+
commands = name.split ' '
|
38
|
+
action = commands.pop
|
39
|
+
id = commands.join(' ')
|
40
|
+
v = @commands[id] || {:actions => [], :switches => []}
|
41
|
+
v[:actions] << action unless id == '' && name != cmd.name
|
42
|
+
@commands[id] = v
|
43
|
+
end
|
44
|
+
|
45
|
+
v = @commands[name.to_s] || {:actions => [], :switches => []}
|
46
|
+
v[:switches].concat(cmd.options.map do |o|
|
47
|
+
if o[:switches]
|
48
|
+
s = o[:switches][-1].split(' ')[0]
|
49
|
+
if m = /--\[no-\](.+)/.match(s)
|
50
|
+
s = ["--#{m[1]}", "--no-#{m[1]}"]
|
51
|
+
else
|
52
|
+
s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end.flatten.compact.sort)
|
56
|
+
@commands[name.to_s] = v
|
57
|
+
end
|
58
|
+
@commands.delete('')
|
59
|
+
@commands = @commands.to_a.sort{ |a,b| a[0] <=> b[0] }
|
60
|
+
|
61
|
+
@top_level_commands.sort!
|
62
|
+
|
63
|
+
@global_options = data.runner.options.map{ |o| o[:switches][-1].split(' ')[0] }.sort
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# This is the bash auto completion script for the pbox command
|
3
|
+
#
|
4
|
+
_pbox()
|
5
|
+
{
|
6
|
+
local cur opts prev
|
7
|
+
COMPREPLY=()
|
8
|
+
cur="${COMP_WORDS[COMP_CWORD]}"
|
9
|
+
if [ $COMP_CWORD -eq 1 ]; then
|
10
|
+
if [[ "$cur" == -* ]]; then
|
11
|
+
opts=<%= "\"%s\"" % global_options.join(' ') %>
|
12
|
+
elif [ -z $cur ]; then
|
13
|
+
opts=<%= "\"%s\"" % top_level_commands.join(' ') %>
|
14
|
+
else
|
15
|
+
opts=<%= "\"%s\"" % commands.map{ |c| c.first }.delete_if{ |s| s.include? ' ' }.sort.join(' ') %>
|
16
|
+
fi
|
17
|
+
else
|
18
|
+
prev="${COMP_WORDS[@]:0:COMP_CWORD}"
|
19
|
+
SAVE_IFS=$IFS
|
20
|
+
IFS=" "
|
21
|
+
case "${prev[*]}" in
|
22
|
+
<%- for name, data in commands %>
|
23
|
+
<%= "\"pbox %s\")" % name %>
|
24
|
+
if [[ "$cur" == -* ]]; then
|
25
|
+
opts=<%= "\"%s\"" % data[:switches].join(" ") %>
|
26
|
+
else
|
27
|
+
opts=<%= "\"%s\"" % data[:actions].join(" ") %>
|
28
|
+
fi
|
29
|
+
;;
|
30
|
+
<%- end %>
|
31
|
+
esac
|
32
|
+
IFS=$SAVE_IFS
|
33
|
+
fi
|
34
|
+
|
35
|
+
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
36
|
+
return 0
|
37
|
+
}
|
38
|
+
|
39
|
+
complete -o default -F _pbox pbox
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module RHC
|
2
|
+
module CartridgeHelpers
|
3
|
+
|
4
|
+
protected
|
5
|
+
def check_cartridges(names, opts={}, &block)
|
6
|
+
cartridge_names = Array(names).map{ |s| s.strip if s && s.length > 0 }.compact
|
7
|
+
from = opts[:from] || all_cartridges
|
8
|
+
|
9
|
+
cartridge_names.map do |name|
|
10
|
+
next use_cart(RHC::Rest::Cartridge.for_url(name), name) if name =~ %r(\Ahttps?://)i
|
11
|
+
|
12
|
+
name = name.downcase
|
13
|
+
from.find{ |c| c.name.downcase == name } ||
|
14
|
+
begin
|
15
|
+
carts = from.select{ |c| match_cart(c, name) }
|
16
|
+
if carts.empty?
|
17
|
+
paragraph { list_cartridges(from) }
|
18
|
+
raise RHC::CartridgeNotFoundException, "There are no cartridges that match '#{name}'."
|
19
|
+
elsif carts.length == 1
|
20
|
+
use_cart(carts.first, name)
|
21
|
+
else
|
22
|
+
carts.sort!.instance_variable_set(:@for, name)
|
23
|
+
carts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end.tap do |carts|
|
27
|
+
yield carts if block_given?
|
28
|
+
end.each do |carts|
|
29
|
+
if carts.is_a? Array
|
30
|
+
name = carts.instance_variable_get(:@for)
|
31
|
+
paragraph { list_cartridges(carts) }
|
32
|
+
raise RHC::MultipleCartridgesException, "There are multiple cartridges matching '#{name}'. Please provide the short name of the correct cart."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def use_cart(cart, for_cartridge_name)
|
38
|
+
if cart.name.blank? and cart.custom?
|
39
|
+
info "The cartridge '#{cart.url}' will be downloaded and installed"
|
40
|
+
else
|
41
|
+
info "Using #{cart.name}#{cart.display_name ? " (#{cart.display_name})" : ''} for '#{for_cartridge_name}'"
|
42
|
+
end
|
43
|
+
cart
|
44
|
+
end
|
45
|
+
|
46
|
+
def match_cart(cart, search)
|
47
|
+
search = search.to_s.downcase.gsub(/[_\-\s]/,' ')
|
48
|
+
[
|
49
|
+
cart.name,
|
50
|
+
(cart.tags || []).join(' '),
|
51
|
+
].compact.any?{ |s| s.present? && s.downcase.gsub(/[_\-\s]/,' ').include?(search) } ||
|
52
|
+
search.length > 2 && [
|
53
|
+
cart.description
|
54
|
+
].compact.any?{ |s| s.present? && !s.downcase.match(/\b#{search}\b/).nil? }
|
55
|
+
end
|
56
|
+
|
57
|
+
def web_carts_only
|
58
|
+
lambda{ |cart|
|
59
|
+
next cart unless cart.is_a? Array
|
60
|
+
name = cart.instance_variable_get(:@for)
|
61
|
+
matching = cart.select{ |c| not c.only_in_existing? }
|
62
|
+
if matching.size == 1
|
63
|
+
use_cart(matching.first, name)
|
64
|
+
else
|
65
|
+
matching.instance_variable_set(:@for, name)
|
66
|
+
matching
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def other_carts_only
|
72
|
+
lambda{ |cart|
|
73
|
+
next cart unless cart.is_a? Array
|
74
|
+
name = cart.instance_variable_get(:@for)
|
75
|
+
matching = cart.select{ |c| not c.only_in_new? }
|
76
|
+
if matching.size == 1
|
77
|
+
use_cart(matching.first, name)
|
78
|
+
else
|
79
|
+
matching.instance_variable_set(:@for, name)
|
80
|
+
matching
|
81
|
+
end
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def standalone_cartridges
|
86
|
+
@standalone_cartridges ||= all_cartridges.select{ |c| c.type == 'standalone' }
|
87
|
+
end
|
88
|
+
|
89
|
+
def not_standalone_cartridges
|
90
|
+
@not_standalone_cartridges ||= all_cartridges.select{ |c| c.type != 'standalone' }
|
91
|
+
end
|
92
|
+
|
93
|
+
def all_cartridges
|
94
|
+
@all_cartridges = rest_client.cartridges
|
95
|
+
end
|
96
|
+
|
97
|
+
def list_cartridges(cartridges)
|
98
|
+
carts = cartridges.map{ |c| [c.name, c.display_name || ''] }.sort{ |a,b| a[1].downcase <=> b[1].downcase }
|
99
|
+
carts.unshift ['==========', '=========']
|
100
|
+
carts.unshift ['Short Name', 'Full name']
|
101
|
+
say table(carts)
|
102
|
+
end
|
103
|
+
|
104
|
+
def filter_jenkins_cartridges(tag)
|
105
|
+
cartridges = all_cartridges.select { |c| (c.tags || []).include?(tag) && c.name =~ /\Ajenkins/i }.sort
|
106
|
+
raise RHC::JenkinsNotInstalledOnServer if cartridges.empty?
|
107
|
+
cartridges
|
108
|
+
end
|
109
|
+
|
110
|
+
def jenkins_cartridges
|
111
|
+
@jenkins_cartridges ||= filter_jenkins_cartridges('ci')
|
112
|
+
end
|
113
|
+
|
114
|
+
def jenkins_client_cartridges
|
115
|
+
@jenkins_client_cartridges ||= filter_jenkins_cartridges('ci_builder')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/rhc/cli.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rhc'
|
2
|
+
require 'rhc/commands'
|
3
|
+
|
4
|
+
module RHC
|
5
|
+
#
|
6
|
+
# Run and execute a command line session with the PBOX tools.
|
7
|
+
#
|
8
|
+
# You can invoke the CLI with:
|
9
|
+
# bundle exec ruby -e 'require "rhc/cli"; RHC::CLI.start(ARGV);' -- <arguments>
|
10
|
+
#
|
11
|
+
# from the gem directory.
|
12
|
+
#
|
13
|
+
module CLI
|
14
|
+
extend Commander::Delegates
|
15
|
+
|
16
|
+
def self.set_terminal
|
17
|
+
$terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first rescue 80 if $stdin.tty?
|
18
|
+
$terminal.wrap_at = nil if $terminal.wrap_at == 0
|
19
|
+
#$terminal.page_at = :auto if $stdin.tty? and $stdout.tty?
|
20
|
+
# FIXME: ANSI terminals are not default on windows but we may just be
|
21
|
+
# hitting a bug in highline if windows does support another method.
|
22
|
+
# This is a safe fix for now but needs more research.
|
23
|
+
HighLine::use_color = false if RHC::Helpers.windows? or not $stdout.tty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.start(args)
|
27
|
+
runner = RHC::CommandRunner.new(args)
|
28
|
+
Commander::Runner.instance_variable_set :@singleton, runner
|
29
|
+
|
30
|
+
program :name, 'pbox'
|
31
|
+
program :description, 'Command line interface for ProtonBox.'
|
32
|
+
program :version, RHC::VERSION::STRING
|
33
|
+
program :help_formatter, RHC::HelpFormatter
|
34
|
+
program :int_message, " Interrupted\n"
|
35
|
+
|
36
|
+
RHC::Commands.load.to_commander
|
37
|
+
run! || 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
module RHC
|
2
|
+
class CommandRunner < Commander::Runner
|
3
|
+
# regex fix from git - match on word boundries
|
4
|
+
def valid_command_names_from *args
|
5
|
+
arg_string = args.delete_if { |value| value =~ /^-/ }.join ' '
|
6
|
+
commands.keys.find_all { |name| name if /^#{name}\b/.match arg_string }
|
7
|
+
end
|
8
|
+
|
9
|
+
if Commander::VERSION == '4.0.3'
|
10
|
+
#:nocov:
|
11
|
+
def program(*args)
|
12
|
+
Array(super).first
|
13
|
+
end
|
14
|
+
#:nocov:
|
15
|
+
end
|
16
|
+
|
17
|
+
def options_parse_trace
|
18
|
+
if @args.include?("--trace")
|
19
|
+
@args.delete "--trace"
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def options_parse_debug
|
26
|
+
if @args.include?("-d") or @args.include?("--debug")
|
27
|
+
@args.delete "-d"
|
28
|
+
@args.delete "--debug"
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def options_parse_version
|
35
|
+
if @args.include? "--version"
|
36
|
+
say version
|
37
|
+
exit 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
HELP_OPTIONS = ['--help', '-h']
|
42
|
+
|
43
|
+
def options_parse_help
|
44
|
+
if (@args & HELP_OPTIONS).present?
|
45
|
+
args = (@args -= HELP_OPTIONS)
|
46
|
+
args.shift if args.first == 'help' && !command_exists?(args.join(' '))
|
47
|
+
exit run_help(args)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# override so we can do our own error handling
|
52
|
+
def run!
|
53
|
+
trace = false
|
54
|
+
require_program :version, :description
|
55
|
+
|
56
|
+
global_option('-h', '--help', 'Help on any command', :hide => true)
|
57
|
+
global_option('--version', 'Display version information', :hide => true)
|
58
|
+
|
59
|
+
# special case --debug so all commands can output relevant info on it
|
60
|
+
$terminal.debug = options_parse_debug
|
61
|
+
|
62
|
+
# special case --trace because we need to use it in the runner
|
63
|
+
trace = options_parse_trace
|
64
|
+
|
65
|
+
# special case --version so it is processed before an invalid command
|
66
|
+
options_parse_version
|
67
|
+
|
68
|
+
# help is a special branch prior to command execution
|
69
|
+
options_parse_help
|
70
|
+
|
71
|
+
unless trace
|
72
|
+
begin
|
73
|
+
run_active_command
|
74
|
+
rescue InvalidCommandError => e
|
75
|
+
return RHC::Wizard.new.run unless RHC::Wizard.has_configuration? || provided_arguments.present?
|
76
|
+
run_help(provided_arguments)
|
77
|
+
rescue \
|
78
|
+
OptionParser::InvalidOption => e
|
79
|
+
RHC::Helpers.error e.message
|
80
|
+
1
|
81
|
+
rescue \
|
82
|
+
ArgumentError,
|
83
|
+
OptionParser::ParseError => e
|
84
|
+
|
85
|
+
help_bindings = CommandHelpBindings.new(active_command, commands, self)
|
86
|
+
usage = RHC::HelpFormatter.new(self).render_command_syntax(help_bindings)
|
87
|
+
message = case e
|
88
|
+
when OptionParser::AmbiguousOption
|
89
|
+
"The option #{e.args.join(' ')} is ambiguous. You will need to specify the entire option."
|
90
|
+
else
|
91
|
+
e.message
|
92
|
+
end
|
93
|
+
|
94
|
+
RHC::Helpers.error message
|
95
|
+
say "#{usage}"
|
96
|
+
1
|
97
|
+
rescue RHC::Exception, RHC::Rest::Exception => e
|
98
|
+
RHC::Helpers.error e.message
|
99
|
+
e.code.nil? ? 128 : [1, (e.code || 1).to_i].max
|
100
|
+
end
|
101
|
+
else
|
102
|
+
run_active_command
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def provided_arguments
|
107
|
+
@args[0, @args.find_index { |arg| arg != '--' and arg.start_with?('-') } || @args.length]
|
108
|
+
end
|
109
|
+
|
110
|
+
def global_option(*args, &block)
|
111
|
+
opts = args.pop if Hash === args.last
|
112
|
+
super(*args, &block).tap do |options|
|
113
|
+
options.last.merge!(opts) if opts
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_default_commands
|
118
|
+
command 'help options' do |c|
|
119
|
+
c.description = "Display all global options and information about configuration"
|
120
|
+
c.when_called do |args, options|
|
121
|
+
say help_formatter.render_options self
|
122
|
+
0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
command :help do |c|
|
126
|
+
c.syntax = '<command>'
|
127
|
+
c.description = 'Display global or <command> help documentation.'
|
128
|
+
c.when_called(&method(:run_help))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def run_help(args=[], options=nil)
|
133
|
+
args.delete_if{ |a| a.start_with? '-' }
|
134
|
+
unless args[0] == 'commands'
|
135
|
+
variations = (1..args.length).reverse_each.map{ |n| args[0,n].join('-') }
|
136
|
+
cmd = variations.find{ |cmd| command_exists?(cmd) }
|
137
|
+
end
|
138
|
+
|
139
|
+
if args.empty?
|
140
|
+
say help_formatter.render
|
141
|
+
0
|
142
|
+
else
|
143
|
+
if cmd.nil?
|
144
|
+
matches = (variations || ['']).inject(nil) do |candidates, term|
|
145
|
+
term = term.downcase
|
146
|
+
keys = commands.keys.map(&:downcase)
|
147
|
+
prefix, keys = keys.partition{ |n| n.start_with? term }
|
148
|
+
inline, keys = keys.partition{ |n| n.include? term }
|
149
|
+
break [term, prefix, inline] unless prefix.empty? && inline.empty?
|
150
|
+
end
|
151
|
+
|
152
|
+
unless matches
|
153
|
+
RHC::Helpers.error "The command '#{program :name} #{provided_arguments.join(' ')}' is not recognized.\n"
|
154
|
+
say "See '#{program :name} help' for a list of valid commands."
|
155
|
+
return 1
|
156
|
+
end
|
157
|
+
|
158
|
+
candidates = (matches[1] + matches[2]).map{ |n| commands[n] }.uniq.sort_by{ |c| c.name }
|
159
|
+
if candidates.length == 1
|
160
|
+
cmd = candidates.first.name
|
161
|
+
else
|
162
|
+
RHC::Helpers.pager
|
163
|
+
RHC::Helpers.say matches[0] != '' ? "Showing commands matching '#{matches[0]}'" : "Showing all commands"
|
164
|
+
candidates.reverse.each do |command|
|
165
|
+
RHC::Helpers.paragraph do
|
166
|
+
aliases = (commands.map{ |(k,v)| k if command == v }.compact - [command.name]).map{ |s| "'#{s}'"}
|
167
|
+
aliases[0] = "(also #{aliases[0]}" if aliases[0]
|
168
|
+
aliases[-1] << ')' if aliases[0]
|
169
|
+
|
170
|
+
RHC::Helpers.header [RHC::Helpers.color(command.name, :cyan), *aliases.join(', ')]
|
171
|
+
say command.description || command.summary
|
172
|
+
end
|
173
|
+
end
|
174
|
+
return 1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
RHC::Helpers.pager
|
179
|
+
command = command(cmd)
|
180
|
+
help_bindings = CommandHelpBindings.new command, commands, self
|
181
|
+
say help_formatter.render_command help_bindings
|
182
|
+
0
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RHC::Commands
|
2
|
+
class Account < Base
|
3
|
+
suppress_wizard
|
4
|
+
|
5
|
+
summary "Display details about your ProtonBox account"
|
6
|
+
description <<-DESC
|
7
|
+
Shows who you are logged in to the server as and the capabilities
|
8
|
+
available to you on this server.
|
9
|
+
|
10
|
+
To access more details about your account please visit the website.
|
11
|
+
DESC
|
12
|
+
def run
|
13
|
+
user = rest_client.user
|
14
|
+
|
15
|
+
say format_table \
|
16
|
+
["Login #{user.login} on #{protonbox_server}"],
|
17
|
+
get_properties(user, :id, :plan_id, :consumed_gears, :max_gears, :max_domains).
|
18
|
+
concat(get_properties(user.capabilities, :gear_sizes)).
|
19
|
+
push(['SSL Certificates:', user.capabilities.private_ssl_certificates ? 'yes' : 'no']),
|
20
|
+
:delete => true
|
21
|
+
|
22
|
+
0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|