startapp 0.1.6

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.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,64 @@
1
+ module RHC::Auth
2
+ class Basic
3
+ def initialize(*args)
4
+ if args[0].is_a?(String) or args.length > 1
5
+ @username, @password = args
6
+ else
7
+ @options = args[0] || Commander::Command::Options.new
8
+ @username = options[:rhlogin]
9
+ @password = options[:password]
10
+ @no_interactive = options[:noprompt]
11
+ end
12
+ @skip_interactive = !@password.nil?
13
+ end
14
+
15
+ def to_request(request)
16
+ request[:user] ||=
17
+ lambda{ username || (request[:lazy_auth] != true && ask_username) || nil }
18
+ request[:password] ||=
19
+ lambda{ password || (username? && request[:lazy_auth] != true && ask_password) || nil }
20
+ request
21
+ end
22
+
23
+ def retry_auth?(response, client)
24
+ if response.status == 401
25
+ credentials_rejected
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ def can_authenticate?
32
+ username? and not (password.nil? and @skip_interactive and @no_interactive)
33
+ end
34
+
35
+ attr_reader :username
36
+
37
+ protected
38
+ include RHC::Helpers
39
+ attr_reader :options, :password
40
+
41
+ def credentials_rejected
42
+ error "Username or password is not correct" if username? && password
43
+ unless @skip_interactive or @no_interactive
44
+ ask_username unless username?
45
+ ask_password
46
+ true
47
+ end
48
+ end
49
+
50
+ def ask_username
51
+ @username = ask("Login to #{openshift_server}: ") unless @no_interactive
52
+ end
53
+ def ask_password
54
+ @password = ask("Password: ") { |q|
55
+ q.echo = '*'
56
+ q.whitespace = :chomp
57
+ } unless @no_interactive
58
+ end
59
+
60
+ def username?
61
+ username.present?
62
+ end
63
+ end
64
+ end
@@ -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, openshift_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 on #{openshift_server}."
78
+ elsif @can_get_token
79
+ info "Please sign in to start a new session to #{openshift_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, openshift_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,5 @@
1
+ module RHC::Auth
2
+ autoload :Basic, 'rhc/auth/basic'
3
+ autoload :Token, 'rhc/auth/token'
4
+ autoload :TokenStore, 'rhc/auth/token_store'
5
+ end
@@ -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 rhc command
3
+ #
4
+ _app()
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
+ <%= "\"app %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 _app app
@@ -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 from.find{ |c| c.url.present? && c.url.downcase == name} || 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#{Regexp.escape(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 RHC 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 $stdout.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, 'app'
31
+ program :description, 'Command line interface for StartApp.'
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,185 @@
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
+ run_help(provided_arguments)
76
+ rescue \
77
+ OptionParser::InvalidOption => e
78
+ RHC::Helpers.error e.message
79
+ 1
80
+ rescue \
81
+ ArgumentError,
82
+ OptionParser::ParseError => e
83
+
84
+ help_bindings = CommandHelpBindings.new(active_command, commands, self)
85
+ usage = RHC::HelpFormatter.new(self).render_command_syntax(help_bindings)
86
+ message = case e
87
+ when OptionParser::AmbiguousOption
88
+ "The option #{e.args.join(' ')} is ambiguous. You will need to specify the entire option."
89
+ else
90
+ e.message
91
+ end
92
+
93
+ RHC::Helpers.error message
94
+ say "#{usage}"
95
+ 1
96
+ rescue RHC::Exception, RHC::Rest::Exception => e
97
+ RHC::Helpers.error e.message
98
+ e.code.nil? ? 128 : [1, (e.code || 1).to_i].max
99
+ end
100
+ else
101
+ run_active_command
102
+ end
103
+ end
104
+
105
+ def provided_arguments
106
+ @args[0, @args.find_index { |arg| arg != '--' and arg.start_with?('-') } || @args.length]
107
+ end
108
+
109
+ def global_option(*args, &block)
110
+ opts = args.pop if Hash === args.last
111
+ super(*args, &block).tap do |options|
112
+ options.last.merge!(opts) if opts
113
+ end
114
+ end
115
+
116
+ def create_default_commands
117
+ command 'help options' do |c|
118
+ c.description = "Display all global options and information about configuration"
119
+ c.when_called do |args, options|
120
+ say help_formatter.render_options self
121
+ 0
122
+ end
123
+ end
124
+ command :help do |c|
125
+ c.syntax = '<command>'
126
+ c.description = 'Display global or <command> help documentation.'
127
+ c.when_called(&method(:run_help))
128
+ end
129
+ end
130
+
131
+ def run_help(args=[], options=nil)
132
+ args.delete_if{ |a| a.start_with? '-' }
133
+ unless args[0] == 'commands'
134
+ variations = (1..args.length).reverse_each.map{ |n| args[0,n].join('-') }
135
+ cmd = variations.find{ |cmd| command_exists?(cmd) }
136
+ end
137
+
138
+ if args.empty?
139
+ say help_formatter.render
140
+ 0
141
+ else
142
+ if cmd.nil?
143
+ matches = (variations || ['']).inject(nil) do |candidates, term|
144
+ term = term.downcase
145
+ keys = commands.keys.map(&:downcase)
146
+ prefix, keys = keys.partition{ |n| n.start_with? term }
147
+ inline, keys = keys.partition{ |n| n.include? term }
148
+ break [term, prefix, inline] unless prefix.empty? && inline.empty?
149
+ end
150
+
151
+ unless matches
152
+ RHC::Helpers.error "The command '#{program :name} #{provided_arguments.join(' ')}' is not recognized.\n"
153
+ say "See '#{program :name} help' for a list of valid commands."
154
+ return 1
155
+ end
156
+
157
+ candidates = (matches[1] + matches[2]).map{ |n| commands[n] }.uniq.sort_by{ |c| c.name }
158
+ if candidates.length == 1
159
+ cmd = candidates.first.name
160
+ else
161
+ RHC::Helpers.pager
162
+ RHC::Helpers.say matches[0] != '' ? "Showing commands matching '#{matches[0]}'" : "Showing all commands"
163
+ candidates.reverse.each do |command|
164
+ RHC::Helpers.paragraph do
165
+ aliases = (commands.map{ |(k,v)| k if command == v }.compact - [command.name]).map{ |s| "'#{s}'"}
166
+ aliases[0] = "(also #{aliases[0]}" if aliases[0]
167
+ aliases[-1] << ')' if aliases[0]
168
+
169
+ RHC::Helpers.header [RHC::Helpers.color(command.name, :cyan), *aliases.join(', ')]
170
+ say command.description || command.summary
171
+ end
172
+ end
173
+ return 1
174
+ end
175
+ end
176
+
177
+ RHC::Helpers.pager
178
+ command = command(cmd)
179
+ help_bindings = CommandHelpBindings.new command, commands, self
180
+ say help_formatter.render_command help_bindings
181
+ 0
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,25 @@
1
+ module RHC::Commands
2
+ class Account < Base
3
+ suppress_wizard
4
+
5
+ summary "Display details about your StartApp 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 #{openshift_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