pbox 1.17.2

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +40 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/pbox_bash +1639 -0
  7. data/bin/pbox +37 -0
  8. data/conf/protonbox.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +178 -0
  11. data/features/deployments_feature.rb +127 -0
  12. data/features/domains_feature.rb +49 -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 +186 -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 +701 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +96 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +326 -0
  31. data/lib/rhc/commands/deployment.rb +82 -0
  32. data/lib/rhc/commands/domain.rb +167 -0
  33. data/lib/rhc/commands/env.rb +142 -0
  34. data/lib/rhc/commands/git_clone.rb +29 -0
  35. data/lib/rhc/commands/logout.rb +51 -0
  36. data/lib/rhc/commands/member.rb +148 -0
  37. data/lib/rhc/commands/port_forward.rb +197 -0
  38. data/lib/rhc/commands/server.rb +40 -0
  39. data/lib/rhc/commands/setup.rb +60 -0
  40. data/lib/rhc/commands/snapshot.rb +137 -0
  41. data/lib/rhc/commands/ssh.rb +51 -0
  42. data/lib/rhc/commands/sshkey.rb +97 -0
  43. data/lib/rhc/commands/tail.rb +47 -0
  44. data/lib/rhc/commands/threaddump.rb +14 -0
  45. data/lib/rhc/commands.rb +396 -0
  46. data/lib/rhc/config.rb +320 -0
  47. data/lib/rhc/context_helper.rb +121 -0
  48. data/lib/rhc/core_ext.rb +202 -0
  49. data/lib/rhc/coverage_helper.rb +33 -0
  50. data/lib/rhc/deployment_helpers.rb +88 -0
  51. data/lib/rhc/exceptions.rb +232 -0
  52. data/lib/rhc/git_helpers.rb +91 -0
  53. data/lib/rhc/help_formatter.rb +55 -0
  54. data/lib/rhc/helpers.rb +477 -0
  55. data/lib/rhc/highline_extensions.rb +479 -0
  56. data/lib/rhc/json.rb +51 -0
  57. data/lib/rhc/output_helpers.rb +260 -0
  58. data/lib/rhc/rest/activation.rb +11 -0
  59. data/lib/rhc/rest/alias.rb +42 -0
  60. data/lib/rhc/rest/api.rb +87 -0
  61. data/lib/rhc/rest/application.rb +332 -0
  62. data/lib/rhc/rest/attributes.rb +36 -0
  63. data/lib/rhc/rest/authorization.rb +8 -0
  64. data/lib/rhc/rest/base.rb +79 -0
  65. data/lib/rhc/rest/cartridge.rb +154 -0
  66. data/lib/rhc/rest/client.rb +650 -0
  67. data/lib/rhc/rest/deployment.rb +18 -0
  68. data/lib/rhc/rest/domain.rb +98 -0
  69. data/lib/rhc/rest/environment_variable.rb +15 -0
  70. data/lib/rhc/rest/gear_group.rb +16 -0
  71. data/lib/rhc/rest/httpclient.rb +145 -0
  72. data/lib/rhc/rest/key.rb +44 -0
  73. data/lib/rhc/rest/membership.rb +105 -0
  74. data/lib/rhc/rest/mock.rb +1024 -0
  75. data/lib/rhc/rest/user.rb +32 -0
  76. data/lib/rhc/rest.rb +148 -0
  77. data/lib/rhc/ssh_helpers.rb +378 -0
  78. data/lib/rhc/tar_gz.rb +51 -0
  79. data/lib/rhc/usage_templates/command_help.erb +51 -0
  80. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  81. data/lib/rhc/usage_templates/help.erb +35 -0
  82. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  83. data/lib/rhc/usage_templates/options_help.erb +12 -0
  84. data/lib/rhc/vendor/okjson.rb +600 -0
  85. data/lib/rhc/vendor/parseconfig.rb +178 -0
  86. data/lib/rhc/vendor/sshkey.rb +253 -0
  87. data/lib/rhc/vendor/zliby.rb +628 -0
  88. data/lib/rhc/version.rb +5 -0
  89. data/lib/rhc/wizard.rb +633 -0
  90. data/lib/rhc.rb +34 -0
  91. data/spec/coverage_helper.rb +89 -0
  92. data/spec/direct_execution_helper.rb +338 -0
  93. data/spec/keys/example.pem +23 -0
  94. data/spec/keys/example_private.pem +27 -0
  95. data/spec/keys/server.pem +19 -0
  96. data/spec/rest_spec_helper.rb +31 -0
  97. data/spec/rhc/assets/cert.crt +22 -0
  98. data/spec/rhc/assets/cert_key_rsa +27 -0
  99. data/spec/rhc/assets/empty.txt +0 -0
  100. data/spec/rhc/assets/env_vars.txt +7 -0
  101. data/spec/rhc/assets/env_vars_2.txt +1 -0
  102. data/spec/rhc/assets/foo.txt +1 -0
  103. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  104. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  105. data/spec/rhc/auth_spec.rb +442 -0
  106. data/spec/rhc/cli_spec.rb +188 -0
  107. data/spec/rhc/command_spec.rb +435 -0
  108. data/spec/rhc/commands/account_spec.rb +42 -0
  109. data/spec/rhc/commands/alias_spec.rb +333 -0
  110. data/spec/rhc/commands/app_spec.rb +754 -0
  111. data/spec/rhc/commands/apps_spec.rb +39 -0
  112. data/spec/rhc/commands/authorization_spec.rb +145 -0
  113. data/spec/rhc/commands/cartridge_spec.rb +641 -0
  114. data/spec/rhc/commands/deployment_spec.rb +286 -0
  115. data/spec/rhc/commands/domain_spec.rb +383 -0
  116. data/spec/rhc/commands/env_spec.rb +493 -0
  117. data/spec/rhc/commands/git_clone_spec.rb +80 -0
  118. data/spec/rhc/commands/logout_spec.rb +86 -0
  119. data/spec/rhc/commands/member_spec.rb +228 -0
  120. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  121. data/spec/rhc/commands/server_spec.rb +69 -0
  122. data/spec/rhc/commands/setup_spec.rb +118 -0
  123. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  124. data/spec/rhc/commands/ssh_spec.rb +163 -0
  125. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  126. data/spec/rhc/commands/tail_spec.rb +81 -0
  127. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  128. data/spec/rhc/config_spec.rb +407 -0
  129. data/spec/rhc/helpers_spec.rb +524 -0
  130. data/spec/rhc/highline_extensions_spec.rb +314 -0
  131. data/spec/rhc/json_spec.rb +30 -0
  132. data/spec/rhc/rest_application_spec.rb +248 -0
  133. data/spec/rhc/rest_client_spec.rb +752 -0
  134. data/spec/rhc/rest_spec.rb +740 -0
  135. data/spec/rhc/targz_spec.rb +55 -0
  136. data/spec/rhc/wizard_spec.rb +756 -0
  137. data/spec/spec_helper.rb +575 -0
  138. data/spec/wizard_spec_helper.rb +330 -0
  139. metadata +435 -0
@@ -0,0 +1,396 @@
1
+ require 'commander'
2
+ require 'commander/command'
3
+
4
+ ## monkey patch option parsing to also parse global options all at once
5
+ # to avoid conflicts and side effects of similar short switches
6
+ module Commander
7
+ class Command
8
+ attr_accessor :default_action, :root, :info
9
+ def default_action?
10
+ default_action.present?
11
+ end
12
+ def root?
13
+ root.present?
14
+ end
15
+
16
+ alias_method :option_old, :option
17
+ def option(*args, &block)
18
+ opts = args.pop if Hash === args.last
19
+ option_old(*args, &block).tap do |options|
20
+ options.last.merge!(opts) if opts
21
+ end
22
+ end
23
+
24
+ #
25
+ # Force proxy_option_struct to default to nil for values,
26
+ # backported for Commander 4.0.3
27
+ #
28
+ def proxy_option_struct
29
+ proxy_options.inject Options.new do |options, (option, value)|
30
+ # options that are present will evaluate to true
31
+ value = true if value.nil?
32
+ # if multiple values were specified for this option, collect it as an
33
+ # array. on 'fill_arguments' we will decide between stick with the array
34
+ # (if :type => :list) or just take the last value from array.
35
+ # not part of the backported method.
36
+ if proxy_options.select{ |item| item[0] == option }.length > 1
37
+ if options[option]
38
+ options[option] << value
39
+ else
40
+ options.__send__ :"#{option}=", [value]
41
+ end
42
+ else
43
+ options.__send__ :"#{option}=", value
44
+ end
45
+ options
46
+ end
47
+ end
48
+
49
+ def deprecated(as_alias=nil)
50
+ return false unless info
51
+ return info[:deprecated] if info[:deprecated]
52
+ return false unless info[:aliases]
53
+ info[:aliases].select{ |a| ['-',' '].map{ |s| Array(a[:action]).join(s) }.include?(as_alias) }.map{ |a| a[:deprecated] }.first if as_alias
54
+ end
55
+
56
+ def parse_options_and_call_procs *args
57
+ runner = Commander::Runner.instance
58
+ opts = OptionParser.new
59
+
60
+ # add global options
61
+ runner.options.each do |option|
62
+ opts.on(*option[:args], &runner.global_option_proc(option[:switches], &option[:proc]))
63
+ end
64
+
65
+ # add command options
66
+ @options.each do |option|
67
+ opts.on(*option[:args], &option[:proc])
68
+ opts
69
+ end
70
+
71
+ # Separate option lists with '--'
72
+ remaining = args.split('--').map{ |a| opts.parse!(a) }.inject([]) do |arr, h|
73
+ arr << '--'
74
+ arr.concat(h)
75
+ end
76
+ remaining.shift
77
+
78
+ _, config_path = proxy_options.find{ |arg| arg[0] == :config }
79
+ clean, _ = proxy_options.find{ |arg| arg[0] == :clean }
80
+
81
+ begin
82
+ @config = RHC::Config.new
83
+ @config.use_config(config_path) if config_path
84
+ $terminal.debug("Using config file #{@config.config_path}")
85
+
86
+ unless clean
87
+ @config.to_options.each_pair do |key, value|
88
+ next if proxy_options.detect{ |arr| arr[0] == key }
89
+ if sw = opts.send(:search, :long, key.to_s.gsub(/_/, '-'))
90
+ _, cb, val = sw.send(:conv_arg, nil, value) {|*exc| raise(*exc) }
91
+ cb.call(val) if cb
92
+ else
93
+ proxy_options << [key, value]
94
+ end
95
+ end
96
+ end
97
+ rescue ArgumentError => e
98
+ n = OptionParser::InvalidOption.new(e.message)
99
+ n.reason = "The configuration file #{@config.path} contains an invalid setting"
100
+ n.set_backtrace(e.backtrace)
101
+ raise n
102
+ rescue OptionParser::ParseError => e
103
+ e.reason = "The configuration file #{@config.path} contains an invalid setting"
104
+ raise
105
+ end
106
+ remaining
107
+ end
108
+ end
109
+ end
110
+
111
+ #
112
+ # Allow Command::Options to lazily evaluate procs and lambdas
113
+ #
114
+ module Commander
115
+ class Command
116
+ remove_const(:Options)
117
+ class Options
118
+ def initialize(init=nil)
119
+ @defaults = {}
120
+ @table = {}
121
+ default(init) if init
122
+ end
123
+ def respond_to?(meth)
124
+ super || meth.to_s =~ /^\w+(=)?$/
125
+ end
126
+ def method_missing meth, *args, &block
127
+ if meth.to_s =~ /^\w+=$/
128
+ raise ArgumentError, "Options does not support #{meth} without a single argument" if args.length != 1
129
+ self[meth.to_s.chop] = args.first
130
+ elsif meth.to_s =~ /^\w+$/
131
+ if !@table.has_key?(meth) && !@defaults.has_key?(meth)
132
+ begin; return super; rescue NoMethodError; nil; end
133
+ end
134
+ raise ArgumentError, "Options does not support #{meth} with arguments" if args.length != 0
135
+ self[meth]
136
+ else
137
+ super
138
+ end
139
+ end
140
+ def respond_to_missing?(meth, private_method = false)
141
+ meth.to_s =~ /^\w+(=)?$/
142
+ end
143
+ def []=(meth, value)
144
+ @table[meth.to_sym] = value
145
+ end
146
+ def [](meth)
147
+ k = meth.to_sym
148
+ value = @table.has_key?(k) ? @table[k] : @defaults[k]
149
+ value = value.call if value.is_a? Proc
150
+ value
151
+ end
152
+ def __explicit__
153
+ @table
154
+ end
155
+ def ==(other)
156
+ @table == other.instance_variable_get(:@table)
157
+ end
158
+ def default defaults = {}
159
+ @defaults.merge!(__to_hash__(defaults))
160
+ end
161
+ def __replace__(options)
162
+ @table = __to_hash__(options)
163
+ end
164
+ def __hash__
165
+ @defaults.merge(@table)
166
+ end
167
+ def __to_hash__(obj)
168
+ Options === obj ? obj.__hash__ : obj
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ module RHC
175
+ module Commands
176
+ autoload :Base, 'rhc/commands/base'
177
+
178
+ def self.load
179
+ Dir[File.join(File.dirname(__FILE__), "commands", "*.rb")].each do |file|
180
+ require file
181
+ end
182
+ self
183
+ end
184
+ def self.add(opts)
185
+ commands[opts[:name]] = opts
186
+ end
187
+ def self.global_option(*args, &block)
188
+ global_options << [args.freeze, block]
189
+ end
190
+
191
+ def self.deprecated!
192
+ instance = Commander::Runner.instance
193
+ command_name = instance.command_name_from_args
194
+ command = instance.active_command
195
+
196
+ if new_cmd = command.deprecated(command_name)
197
+ new_cmd = "pbox #{command.name}" if new_cmd == true
198
+ RHC::Helpers.deprecated_command new_cmd
199
+ end
200
+ end
201
+
202
+ def self.needs_configuration!(cmd, options, config)
203
+ if not (cmd.class.suppress_wizard? or
204
+ options.noprompt or
205
+ options.help or
206
+ config.has_local_config? or
207
+ config.has_opts_config?)
208
+
209
+ $stderr.puts RHC::Helpers.color("You have not yet configured the ProtonBox client tools. Please run 'pbox setup'.", :yellow)
210
+ end
211
+ end
212
+
213
+ def self.to_commander(instance=Commander::Runner.instance)
214
+ global_options.each do |args, block|
215
+ args = args.dup
216
+ opts = (args.pop if Hash === args.last) || {}
217
+ option = instance.global_option(*args, &block).last
218
+ option.merge!(opts)
219
+ end
220
+ commands.each_pair do |name, opts|
221
+ name = Array(name)
222
+ names = [name.reverse.join('-'), name.join(' ')] if name.length > 1
223
+ name = name.join('-')
224
+
225
+ instance.command name do |c|
226
+ c.description = opts[:description]
227
+ c.summary = opts[:summary]
228
+ c.syntax = opts[:syntax]
229
+ c.default_action = opts[:default]
230
+
231
+ c.info = opts
232
+
233
+ (options_metadata = Array(opts[:options])).each do |o|
234
+ option_data = [o[:switches], o[:type], o[:description], o.slice(:optional, :default, :hide, :covered_by)].compact.flatten(1)
235
+ c.option *option_data
236
+ o[:arg] = Commander::Runner.switch_to_sym(Array(o[:switches]).last)
237
+ end
238
+
239
+ (args_metadata = Array(opts[:args])).each do |meta|
240
+ switches = meta[:switches]
241
+ unless switches.blank?
242
+ switches = switches.dup
243
+ switches << meta[:description]
244
+ switches << meta.slice(:optional, :default, :hide, :covered_by, :allow_nil)
245
+ c.option *switches
246
+ end
247
+ end
248
+
249
+ Array(opts[:aliases]).each do |a|
250
+ action = Array(a[:action])
251
+ [' ', '-'].each do |s|
252
+ cmd = action.join(s)
253
+ instance.alias_command cmd, name
254
+ end
255
+ end
256
+
257
+ if names
258
+ names.each{ |alt| instance.alias_command alt, name }
259
+ else
260
+ c.root = true
261
+ end
262
+
263
+ c.when_called do |args, options|
264
+ deprecated!
265
+
266
+ config = c.instance_variable_get(:@config)
267
+
268
+ cmd = opts[:class].new
269
+ cmd.options = options
270
+ cmd.config = config
271
+
272
+ args = fill_arguments(cmd, options, args_metadata, options_metadata, args)
273
+ needs_configuration!(cmd, options, config)
274
+
275
+ return execute(cmd, :help, args) unless opts[:method]
276
+ execute(cmd, opts[:method], args)
277
+ end
278
+ end
279
+ end
280
+ self
281
+ end
282
+
283
+ protected
284
+ def self.execute(cmd, method, args)
285
+ cmd.send(method, *args)
286
+ end
287
+
288
+ def self.fill_arguments(cmd, options, args, opts, arguments)
289
+ # process defaults
290
+ defaults = {}
291
+ covers = {}
292
+ (opts + args).each do |option_meta|
293
+ arg = option_meta[:option_symbol] || option_meta[:name] || option_meta[:arg] or next
294
+ if arg && option_meta[:type] != :list && options[arg].is_a?(Array)
295
+ options[arg] = options[arg].last
296
+ end
297
+ Array(option_meta[:covered_by]).each{ |sym| (covers[sym] ||= []) << arg }
298
+
299
+ case v = option_meta[:default]
300
+ when Symbol
301
+ cmd.send(v, defaults, arg)
302
+ when Proc
303
+ v.call(defaults, arg)
304
+ when nil
305
+ else
306
+ defaults[arg] = v
307
+ end
308
+ end
309
+ options.default(defaults)
310
+
311
+ # process required options
312
+ opts.each do |option_meta|
313
+ raise ArgumentError.new("Missing required option '#{option_meta[:arg]}'.") if option_meta[:required] && options[option_meta[:arg]].nil?
314
+ end
315
+
316
+ slots = Array.new(args.count)
317
+ available = arguments.dup
318
+
319
+ args.each_with_index do |arg, i|
320
+ value = argument_to_slot(options, available, arg)
321
+
322
+ if value.nil?
323
+ if arg[:allow_nil] != true && !arg[:optional]
324
+ raise ArgumentError, "Missing required argument '#{arg[:name]}'."
325
+ end
326
+ end
327
+
328
+ slots[i] = value
329
+ end
330
+
331
+ raise ArgumentError, "Too many arguments passed in: #{available.reverse.join(" ")}" unless available.empty?
332
+
333
+ # reset covered arguments
334
+ options.__explicit__.keys.each do |k|
335
+ if covered = covers[k]
336
+ covered.each do |sym|
337
+ raise ArgumentError, "The options '#{sym}' and '#{k}' cannot both be provided" unless options.__explicit__[sym].nil?
338
+ options[sym] = nil
339
+ end
340
+ end
341
+ end
342
+
343
+ slots
344
+ end
345
+
346
+ def self.argument_to_slot(options, available, arg)
347
+ if Array(arg[:covered_by]).any?{ |k| !options.__explicit__[k].nil? }
348
+ return nil
349
+ end
350
+
351
+ option = arg[:option_symbol]
352
+ value = options.__explicit__[option] if option
353
+ if value.nil?
354
+ value =
355
+ if arg[:type] == :list
356
+ take_leading_list(available)
357
+ else
358
+ v = available.shift
359
+ if v == '--'
360
+ v = nil
361
+ else
362
+ available.shift if available.first == '--'
363
+ end
364
+ v
365
+ end
366
+ end
367
+
368
+ value = options[option] if option && (value.nil? || (value.is_a?(Array) && value.blank?))
369
+ if arg[:type] == :list
370
+ value = Array(value)
371
+ end
372
+ options[option] = value if option && !value.nil?
373
+
374
+ value
375
+ end
376
+
377
+ def self.take_leading_list(available)
378
+ if i = available.index('--')
379
+ left = available.shift(i)
380
+ available.shift
381
+ left
382
+ else
383
+ left = available.dup
384
+ available.clear
385
+ left
386
+ end
387
+ end
388
+
389
+ def self.commands
390
+ @commands ||= {}
391
+ end
392
+ def self.global_options
393
+ @options ||= []
394
+ end
395
+ end
396
+ end
data/lib/rhc/config.rb ADDED
@@ -0,0 +1,320 @@
1
+ require 'rhc/vendor/parseconfig'
2
+ require 'rhc/core_ext'
3
+
4
+ module RHC
5
+
6
+ module ConfigEnv
7
+ def conf_name
8
+ "#{ENV['PROTONBOX_CONFIG'].presence || 'protonbox'}.conf"
9
+ end
10
+ def home_conf_dir
11
+ File.join(home_dir, '.protonbox')
12
+ end
13
+ def local_config_path
14
+ File.join(home_conf_dir, conf_name)
15
+ end
16
+ def ssh_dir
17
+ File.join(home_dir, '.ssh')
18
+ end
19
+ def ssh_priv_key_file_path
20
+ File.join(ssh_dir, 'id_rsa')
21
+ end
22
+ def ssh_pub_key_file_path
23
+ File.join(ssh_dir, 'id_rsa.pub')
24
+ end
25
+ end
26
+
27
+ #
28
+ # Responsible for encapsulating the loading and retrieval of ProtonBox
29
+ # configuration files and converting them to commandline option
30
+ # equivalents. It also provides the converse option - converting a set
31
+ # of commandline options back into a config file.
32
+ #
33
+ # In general, the values stored in the config should be identical (require
34
+ # little or no type conversion) to their option form. As new global
35
+ # options are added, only this class should have to change to persist that
36
+ # option.
37
+ #
38
+ # During normal use, a new Config object should load the appropriate
39
+ # settings and those settings should be converted into commandline option
40
+ # defaults.
41
+ #
42
+ # TODO: Encapsulate config writing to the home location
43
+ # TODO: Allow the config object to initialized with a path
44
+ # TODO: Remove deprecated methods, remove extra sources.
45
+ #
46
+ class Config
47
+ include ConfigEnv
48
+
49
+ # Option name [config_key type comment_string_for_config]
50
+ # if nil, == key nil == string won't be written to file if nil
51
+ OPTIONS = {
52
+ :server => ['protonbox_server', nil, 'The ProtonBox server to connect to'],
53
+ :pblogin => ['default_pblogin', nil, 'Your ProtonBox username'],
54
+ :password => nil,
55
+ :use_authorization_tokens =>
56
+ [nil, :boolean, 'If true, the server will attempt to create and use authorization tokens to connect to the server'],
57
+ :timeout => [nil, :integer, 'The default timeout for network operations'],
58
+ :insecure => [nil, :boolean, "If true, certificate errors will be ignored.\nWARNING: This may allow others to eavesdrop on your communication with ProtonBox."],
59
+ :ssl_version => [nil, nil, 'The SSL protocol version to use when connecting to this server'],
60
+ :ssl_client_cert_file => [nil, :path_to_file, 'A client certificate file for use with your server'],
61
+ :ssl_ca_file => [nil, :path_to_file, 'A file containing CA one or more certificates'],
62
+ }
63
+
64
+ def self.options_to_config(options)
65
+ OPTIONS.inject([]) do |arr, (name, opts)|
66
+ opts ||= []
67
+ next arr unless opts[2]
68
+ value = options[name]
69
+ arr.concat(opts[2].each_line.to_a.map(&:strip).map{ |s| "# #{s}" })
70
+ arr << "#{value.nil? ? '#' : ''}#{opts[0] || name}=#{self.type_to_config(opts[1], value)}"
71
+ arr << ""
72
+ arr
73
+ end.join("\n")
74
+ end
75
+
76
+ def self.type_to_config(type, value)
77
+ case type
78
+ when :integer, :boolean
79
+ value.nil? ? "<#{type}>" : value
80
+ else
81
+ value.nil? ? "<#{type || 'string'}>" : value
82
+ end
83
+ end
84
+
85
+ # DEPRECATED - will be removed when old commands are gone
86
+ def self.default
87
+ @default ||= RHC::Config.new
88
+ end
89
+
90
+ # DEPRECATED - will be removed when old commands are gone
91
+ def self.method_missing(method, *args, &block)
92
+ if default.respond_to?(method)
93
+ default.send(method, *args, &block)
94
+ else
95
+ raise NoMethodError, method
96
+ end
97
+ end
98
+
99
+ # DEPRECATED - will be removed when old commands are gone
100
+ def self.initialize
101
+ @default = nil
102
+ default
103
+ end
104
+
105
+ # DEPRECATED - will be removed when old commands are gone
106
+ def initialize
107
+ set_defaults
108
+ end
109
+
110
+ # DEPRECATED - will be removed when old commands are gone
111
+ def read_config_files
112
+ load_config_files
113
+ end
114
+
115
+ # DEPRECATED - will be removed when old commands are gone
116
+ def set_defaults
117
+ @defaults = RHC::Vendor::ParseConfig.new()
118
+ @opts = RHC::Vendor::ParseConfig.new() # option switches that override config file
119
+
120
+ @env_config = RHC::Vendor::ParseConfig.new()
121
+ @global_config = nil
122
+ @local_config = nil
123
+ @opts_config = nil # config file passed in the options
124
+
125
+ @default_proxy = nil
126
+
127
+ @defaults.add('protonbox_server', 'api.protonbox.com')
128
+ @env_config.add('protonbox_server', ENV['PROTONBOX_SERVER']) if ENV['PROTONBOX_SERVER']
129
+
130
+ @opts_config_path = nil
131
+ end
132
+
133
+ def to_options
134
+ OPTIONS.inject({}) do |h, (name, opts)|
135
+ opts = Array(opts)
136
+ value = self[opts[0] || name.to_s]
137
+ if value
138
+ value = case opts[1]
139
+ when :integer
140
+ Integer(value)
141
+ when :boolean
142
+ !!(value =~ /^\s*(y|yes|1|t|true)\s*$/i)
143
+ else
144
+ value unless value.blank?
145
+ end
146
+ h[name] = value unless value.nil?
147
+ end
148
+ h
149
+ end
150
+ end
151
+
152
+ def save!(options)
153
+ File.open(path, 'w'){ |f| f.puts self.class.options_to_config(options) }
154
+ @opts, @opts_config, @local_config, @global_config = nil
155
+ load_config_files
156
+ self
157
+ end
158
+
159
+ def [](key)
160
+ lazy_init
161
+
162
+ # evaluate in cascading order
163
+ configs = [@opts, @opts_config, @env_config, @local_config, @global_config, @defaults]
164
+ result = nil
165
+ configs.each do |conf|
166
+ result = conf[key] if !conf.nil?
167
+ break if !result.nil?
168
+ end
169
+
170
+ result
171
+ end
172
+
173
+ # DEPRECATED - will be removed when old commands are gone
174
+ def get_value(key)
175
+ self[key]
176
+ end
177
+
178
+ # DEPRECATED - underlying value and command option needs to be migrated to login
179
+ def username
180
+ self['default_pblogin']
181
+ end
182
+
183
+ # DEPRECATED - will be removed when old commands are gone
184
+ def set_local_config(conf_path, must_exist=true)
185
+ conf_path = File.expand_path(conf_path)
186
+ @config_path = conf_path if @opts_config_path.nil?
187
+ @local_config = RHC::Vendor::ParseConfig.new(conf_path)
188
+ rescue Errno::EACCES => e
189
+ raise Errno::EACCES.new "Could not open config file: #{e.message}" if must_exist
190
+ end
191
+
192
+ # DEPRECATED - needs to be renamed to something cleaner
193
+ def set_opts_config(conf_path)
194
+ @opts_config_path = File.expand_path(conf_path)
195
+ @config_path = @opts_config_path
196
+ @opts_config = RHC::Vendor::ParseConfig.new(@opts_config_path) if File.exists?(@opts_config_path)
197
+ rescue Errno::EACCES => e
198
+ raise Errno::EACCES.new "Could not open config file: #{e.message}"
199
+ end
200
+
201
+ def use_config(path)
202
+ path = File.expand_path(path)
203
+ set_opts_config(path)
204
+ rescue => e
205
+ raise ArgumentError, "Unable to read configuration file: #{e.message}", $!.backtrace
206
+ end
207
+
208
+ # DEPRECATED - will be removed when old commands are gone
209
+ def check_cpath(opts)
210
+ unless opts["config"].nil?
211
+ opts_config_path = File.expand_path(opts["config"])
212
+ if !File.readable?(opts_config_path)
213
+ raise Errno::EACCES.new "Could not open config file: #{@opts_config_path}"
214
+ else
215
+ set_opts_config(opts_config_path)
216
+ end
217
+ end
218
+ end
219
+
220
+ # DEPRECATED - may be made private
221
+ def global_config_path
222
+ linux_cfg = '/etc/protonbox/' + conf_name
223
+ File.exists?(linux_cfg) ? linux_cfg : File.join(File.expand_path(File.dirname(__FILE__) + "/../../conf"), conf_name)
224
+ end
225
+
226
+ def has_global_config?
227
+ lazy_init
228
+ !@global_config.nil?
229
+ end
230
+
231
+ def has_local_config?
232
+ lazy_init
233
+ !@local_config.nil?
234
+ end
235
+
236
+ def has_opts_config?
237
+ !@opts_config.nil?
238
+ end
239
+
240
+ # DEPRECATED - should be moved to Helpers
241
+ def should_run_ssh_wizard?
242
+ not File.exists? ssh_priv_key_file_path
243
+ end
244
+
245
+ ##
246
+ # config_path
247
+ #
248
+ # authoritive configuration path
249
+ # this is used to determine where config options should be written to
250
+ # when a script modifies the config such as in rhc setup
251
+ def config_path
252
+ @config_path ||= local_config_path
253
+ end
254
+ def path
255
+ config_path
256
+ end
257
+
258
+ def home_dir
259
+ RHC::Config.home_dir
260
+ end
261
+
262
+ def home_conf_path
263
+ home_conf_dir
264
+ end
265
+
266
+ # DEPRECATED - will be removed when old commands are gone
267
+ def default_pblogin
268
+ get_value('default_pblogin')
269
+ end
270
+
271
+ # DEPRECATED - will be removed when old commands are gone
272
+ def default_proxy
273
+ @default_proxy ||= (
274
+ proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
275
+ if proxy
276
+ if proxy !~ /^(\w+):\/\// then
277
+ proxy = "http://#{proxy}"
278
+ end
279
+ ENV['http_proxy'] = proxy
280
+ proxy_uri = URI.parse(ENV['http_proxy'])
281
+ Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
282
+ else
283
+ Net::HTTP
284
+ end
285
+ )
286
+ end
287
+
288
+ # DEPRECATED - will be removed when old commands are gone
289
+ def using_proxy?
290
+ default_proxy.instance_variable_get(:@is_proxy_class) || false
291
+ end
292
+
293
+ # DEPRECATED - will be removed when old commands are gone
294
+ def proxy_vars
295
+ Hash[[:address,:user,:pass,:port].map do |x|
296
+ [x,default_proxy.instance_variable_get("@proxy_#{x}")]
297
+ end]
298
+ end
299
+
300
+ private
301
+ # Allow mocking of the home dir
302
+ def self.home_dir
303
+ File.expand_path('~')
304
+ end
305
+
306
+ def load_config_files
307
+ @global_config = RHC::Vendor::ParseConfig.new(global_config_path) if File.exists?(global_config_path)
308
+ @local_config = RHC::Vendor::ParseConfig.new(File.expand_path(local_config_path)) if File.exists?(local_config_path)
309
+ rescue Errno::EACCES => e
310
+ raise Errno::EACCES.new("Could not open config file: #{e.message}")
311
+ end
312
+
313
+ def lazy_init
314
+ unless @loaded
315
+ load_config_files
316
+ @loaded = true
317
+ end
318
+ end
319
+ end
320
+ end