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,481 @@
1
+ require 'commander/user_interaction'
2
+ require 'rhc/version'
3
+ require 'rhc/config'
4
+ require 'rhc/output_helpers'
5
+ require 'rbconfig'
6
+
7
+ require 'resolv'
8
+
9
+ OptionParser.accept(URI) {|s,| URI.parse(s) if s}
10
+
11
+ module RHC
12
+
13
+ module Helpers
14
+ private
15
+ def self.global_option(*args, &block)
16
+ RHC::Commands.global_option *args, &block
17
+ end
18
+ end
19
+
20
+ module Helpers
21
+
22
+ # helpers always have Commander UI available
23
+ include Commander::UI
24
+ include Commander::UI::AskForClass
25
+ include RHC::OutputHelpers
26
+
27
+ extend self
28
+
29
+ def decode_json(s)
30
+ RHC::Vendor::OkJson.decode(s)
31
+ end
32
+
33
+ def system_path(path)
34
+ return path.gsub(File::SEPARATOR, File::ALT_SEPARATOR) if File.const_defined?('ALT_SEPARATOR') and File::ALT_SEPARATOR.present?
35
+ path
36
+ end
37
+
38
+ PREFIX = %W(TB GB MB KB B).freeze
39
+
40
+ def human_size( s )
41
+ return "unknown" unless s
42
+ s = s.to_f
43
+ i = PREFIX.length - 1
44
+ while s > 500 && i > 0
45
+ i -= 1
46
+ s /= 1000
47
+ end
48
+ ((s > 9 || s.modulo(1) < 0.1 ? '%d' : '%.1f') % s) + ' ' + PREFIX[i]
49
+ end
50
+
51
+ def date(s)
52
+ return nil unless s.present?
53
+ now = Date.today
54
+ d = datetime_rfc3339(s).to_time
55
+ if now.year == d.year
56
+ return d.strftime('%l:%M %p').strip if now.yday == d.yday
57
+ d.strftime('%b %d %l:%M %p')
58
+ else
59
+ d.strftime('%b %d, %Y %l:%M %p')
60
+ end
61
+ rescue ArgumentError
62
+ "Unknown date"
63
+ end
64
+
65
+ def distance_of_time_in_words(from_time, to_time = 0)
66
+ from_time = from_time.to_time if from_time.respond_to?(:to_time)
67
+ to_time = to_time.to_time if to_time.respond_to?(:to_time)
68
+ distance_in_minutes = (((to_time - from_time).abs)/60).round
69
+ distance_in_seconds = ((to_time - from_time).abs).round
70
+
71
+ case distance_in_minutes
72
+ when 0..1
73
+ return distance_in_minutes == 0 ?
74
+ "less than 1 minute" :
75
+ "#{distance_in_minutes} minute"
76
+
77
+ when 2..44 then "#{distance_in_minutes} minutes"
78
+ when 45..89 then "about 1 hour"
79
+ when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
80
+ when 1440..2519 then "about 1 day"
81
+ when 2520..43199 then "#{(distance_in_minutes.to_f / 1440.0).round} days"
82
+ when 43200..86399 then "about 1 month"
83
+ else
84
+ "about #{(distance_in_minutes.to_f / 43200.0).round} months"
85
+ end
86
+ end
87
+
88
+ def datetime_rfc3339(s)
89
+ DateTime.strptime(s, '%Y-%m-%dT%H:%M:%S%z')
90
+ # Replace with d = DateTime.rfc3339(s)
91
+ end
92
+
93
+ #
94
+ # Web related requests
95
+ #
96
+
97
+ def user_agent
98
+ "app/#{RHC::VERSION::STRING} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})#{" (API #{RHC::Rest::Client::CLIENT_API_VERSIONS})"}"
99
+ end
100
+
101
+ #
102
+ # Global config
103
+ #
104
+
105
+ global_option '-l', '--rhlogin LOGIN', "StartApp login"
106
+ global_option '-p', '--password PASSWORD', "StartApp password"
107
+ global_option '--token TOKEN', "An authorization token for accessing your account."
108
+
109
+ global_option '-d', '--debug', "Turn on debugging", :hide => true
110
+
111
+ global_option '--server NAME', String, 'An StartApp server hostname (default: broker.startapp.bg)'
112
+ global_option '-k', '--insecure', "Allow insecure SSL connections. Potential security risk.", :hide => true
113
+
114
+ global_option '--limit INTEGER', Integer, "Maximum number of simultaneous operations to execute.", :hide => true
115
+ global_option '--raw', "Do not format the output from the requested operations.", :hide => true
116
+ global_option '--always-prefix', "Include the gear prefix on all output from the server.", :hide => true
117
+
118
+ OptionParser.accept(SSLVersion = Class.new){ |s| OpenSSL::SSL::SSLContext::METHODS.find{ |m| m.to_s.downcase == s.downcase } or raise OptionParser::InvalidOption.new(nil, "The provided SSL version '#{s}' is not valid. Supported values: #{OpenSSL::SSL::SSLContext::METHODS.map(&:to_s).map(&:downcase).join(', ')}") }
119
+ global_option '--ssl-version VERSION', SSLVersion, "The version of SSL to use", :hide => true do |value|
120
+ raise RHC::Exception, "You are using an older version of the httpclient gem which prevents the use of --ssl-version. Please run 'gem update httpclient' to install a newer version (2.2.6 or newer)." unless HTTPClient::SSLConfig.method_defined? :ssl_version
121
+ end
122
+ global_option '--ssl-ca-file FILE', "An SSL certificate CA file (may contain multiple certs)", :hide => true do |value|
123
+ debug certificate_file(value)
124
+ end
125
+ global_option '--ssl-client-cert-file FILE', "An SSL x509 client certificate file", :hide => true do |value|
126
+ debug certificate_file(value)
127
+ end
128
+
129
+ global_option('--timeout SECONDS', Integer, 'The timeout for operations') do |value|
130
+ raise RHC::Exception, "Timeout must be a positive integer" unless value > 0
131
+ end
132
+ global_option '--noprompt', "Suppress all interactive operations command", :hide => true do
133
+ $terminal.page_at = nil
134
+ end
135
+ global_option '--config FILE', "Path of a different config file (default: #{system_path("~/.startapp/express.conf")})", :hide => true
136
+ global_option '--clean', "Ignore any saved configuration options", :hide => true
137
+ global_option '--mock', "Run in mock mode", :hide => true do
138
+ #:nocov:
139
+ require 'rhc/rest/mock'
140
+ RHC::Rest::Mock.start
141
+ #:nocov:
142
+ end
143
+
144
+ ROLES = {'view' => 'viewer', 'edit' => 'editor', 'admin' => 'administrator'}
145
+ OptionParser.accept(Role = Class.new) do |s|
146
+ s.downcase!
147
+ (ROLES.has_key?(s) && s) or
148
+ raise OptionParser::InvalidOption.new(nil, "The provided role '#{s}' is not valid. Supported values: #{ROLES.keys.join(', ')}")
149
+ end
150
+
151
+ def role_name(s)
152
+ ROLES[s.downcase]
153
+ end
154
+
155
+ def openshift_server
156
+ to_host((options.server rescue nil) || ENV['LIBRA_SERVER'] || "broker.startapp.bg")
157
+ end
158
+ def openshift_online_server?
159
+ openshift_server =~ /broker.startapp.bg$/i
160
+ end
161
+ def openshift_url
162
+ "https://#{openshift_server}"
163
+ end
164
+
165
+ def to_host(s)
166
+ s =~ %r(^http(?:s)?://) ? URI(s).host : s
167
+ end
168
+ def to_uri(s)
169
+ begin
170
+ URI(s =~ %r(^http(?:s)?://) ? s : "https://#{s}")
171
+ rescue URI::InvalidURIError
172
+ raise RHC::InvalidURIException.new(s)
173
+ end
174
+ end
175
+
176
+ def ssh_string(ssh_url)
177
+ return nil if ssh_url.blank?
178
+ uri = URI.parse(ssh_url)
179
+ "#{uri.user}@#{uri.host}"
180
+ rescue => e
181
+ RHC::Helpers.debug_error(e)
182
+ ssh_url
183
+ end
184
+
185
+ def ssh_string_parts(ssh_url)
186
+ uri = URI.parse(ssh_url)
187
+ [uri.host, uri.user]
188
+ end
189
+
190
+ def openshift_rest_endpoint
191
+ uri = to_uri((options.server rescue nil) || ENV['LIBRA_SERVER'] || "broker.startapp.bg")
192
+ uri.path = '/broker/rest/api' if uri.path.blank? || uri.path == '/'
193
+ uri
194
+ end
195
+
196
+ def token_for_user
197
+ options.token or (token_store.get(options.rhlogin, options.server) if options.rhlogin && options.use_authorization_tokens)
198
+ end
199
+
200
+ def client_from_options(opts)
201
+ RHC::Rest::Client.new({
202
+ :url => openshift_rest_endpoint.to_s,
203
+ :debug => options.debug,
204
+ :timeout => options.timeout,
205
+ :warn => BOUND_WARNING,
206
+ }.merge!(ssl_options).merge!(opts))
207
+ end
208
+
209
+ def ssl_options
210
+ {
211
+ :ssl_version => options.ssl_version,
212
+ :client_cert => certificate_file(options.ssl_client_cert),
213
+ :ca_file => options.ssl_ca_file && File.expand_path(options.ssl_ca_file),
214
+ :verify_mode => options.insecure ? OpenSSL::SSL::VERIFY_NONE : nil,
215
+ }.delete_if{ |k,v| v.nil? }
216
+ end
217
+
218
+ def certificate_file(file)
219
+ file && OpenSSL::X509::Certificate.new(IO.read(File.expand_path(file)))
220
+ rescue => e
221
+ debug e
222
+ raise OptionParser::InvalidOption.new(nil, "The certificate '#{file}' cannot be loaded: #{e.message} (#{e.class})")
223
+ end
224
+
225
+
226
+ #
227
+ # Output helpers
228
+ #
229
+
230
+ def interactive?
231
+ $stdin.tty? and $stdout.tty? and not options.noprompt
232
+ end
233
+
234
+ def debug(*args)
235
+ $terminal.debug(*args)
236
+ end
237
+ def debug_error(*args)
238
+ $terminal.debug_error(*args)
239
+ end
240
+ def debug?
241
+ $terminal.debug?
242
+ end
243
+
244
+ def exec(cmd)
245
+ output = Kernel.send(:`, cmd)
246
+ [$?.exitstatus, output]
247
+ end
248
+
249
+ def disable_deprecated?
250
+ ENV['DISABLE_DEPRECATED'] == '1'
251
+ end
252
+
253
+ def deprecated_command(correct, short=false)
254
+ deprecated("This command is deprecated. Please use '#{correct}' instead.", short)
255
+ end
256
+
257
+ def deprecated(msg,short = false)
258
+ raise DeprecatedError.new(msg % ['an error','a warning',0]) if disable_deprecated?
259
+ warn "Warning: #{msg}\n" % ['a warning','an error',1]
260
+ end
261
+
262
+ #
263
+ # By default, agree should take a single character in interactive
264
+ #
265
+ def agree(*args, &block)
266
+ #args.push(interactive?.presence) if args.length == 1
267
+ block = lambda do |q|
268
+ q.validate = /\A(?:y|yes|n|no)\Z/i
269
+ end unless block_given?
270
+ super *args, &block
271
+ end
272
+
273
+ def confirm_action(question)
274
+ return if options.confirm
275
+ return if !options.noprompt && paragraph{ agree "#{question} (yes|no): " }
276
+ raise RHC::ConfirmationError
277
+ end
278
+
279
+ def success(msg, *args)
280
+ say color(msg, :green), *args
281
+ end
282
+
283
+ def info(msg, *args)
284
+ say color(msg, :cyan), *args
285
+ end
286
+
287
+ def warn(msg, *args)
288
+ say color(msg, :yellow), *args
289
+ end
290
+
291
+ def error(msg, *args)
292
+ say color(msg, :red), *args
293
+ end
294
+
295
+ # OVERRIDE: Replaces default commander behavior
296
+ def color(item, *args)
297
+ if item.is_a? Array
298
+ item.map{ |i| $terminal.color(i, *args) }
299
+ else
300
+ $terminal.color(item, *args)
301
+ end
302
+ end
303
+
304
+ [:pager, :indent, :paragraph, :section, :header, :table, :table_args].each do |sym|
305
+ define_method(sym) do |*args, &block|
306
+ $terminal.send(sym, *args, &block)
307
+ end
308
+ end
309
+
310
+ def pluralize(count, s)
311
+ count == 1 ? "#{count} #{s}" : "#{count} #{s}s"
312
+ end
313
+
314
+ # This will format table headings for a consistent look and feel
315
+ # If a heading isn't explicitly defined, it will attempt to look up the parts
316
+ # If those aren't found, it will capitalize the string
317
+ def table_heading(value)
318
+ # Set the default proc to look up undefined values
319
+ headings = Hash.new do |hash,key|
320
+ items = key.to_s.split('_')
321
+ # Look up each piece individually
322
+ hash[key] = items.length > 1 ?
323
+ # Recusively look up the heading for the parts
324
+ items.map{|x| headings[x.to_sym]}.join(' ') :
325
+ # Capitalize if this part isn't defined
326
+ items.first.capitalize
327
+ end
328
+
329
+ # Predefined headings (or parts of headings)
330
+ headings.merge!({
331
+ :creation_time => "Created",
332
+ :expires_in_seconds => "Expires In",
333
+ :uuid => "ID",
334
+ :id => 'ID',
335
+ :current_scale => "Current",
336
+ :scales_from => "Minimum",
337
+ :scales_to => "Maximum",
338
+ :gear_sizes => "Allowed Gear Sizes",
339
+ :consumed_gears => "Gears Used",
340
+ :max_gears => "Gears Allowed",
341
+ :max_domains => "Domains Allowed",
342
+ :compact_members => "Members",
343
+ :gear_info => "Gears",
344
+ :plan_id => "Plan",
345
+ :url => "URL",
346
+ :ssh_string => "SSH",
347
+ :connection_info => "Connection URL",
348
+ :gear_profile => "Gear Size",
349
+ :visible_to_ssh? => 'Available',
350
+ :downloaded_cartridge_url => 'From',
351
+ :auto_deploy => 'Deployment',
352
+ :sha1 => 'SHA1',
353
+ :ref => 'Git Reference'
354
+ })
355
+
356
+ headings[value]
357
+ end
358
+
359
+ class StringTee < StringIO
360
+ attr_reader :tee
361
+ def initialize(other)
362
+ @tee = other
363
+ super()
364
+ end
365
+ def <<(buf)
366
+ tee << buf
367
+ super
368
+ end
369
+ end
370
+
371
+ ##
372
+ # results
373
+ #
374
+ # highline helper which creates a paragraph with a header
375
+ # to distinguish the final results of a command from other output
376
+ #
377
+ def results(&block)
378
+ section(:top => 1, :bottom => 0) do
379
+ say "RESULT:"
380
+ yield
381
+ end
382
+ end
383
+
384
+ # Platform helpers
385
+ def jruby? ; RUBY_PLATFORM =~ /java/i end
386
+ def windows? ; RUBY_PLATFORM =~ /win(32|dows|ce)|djgpp|(ms|cyg|bcc)win|mingw32/i end
387
+ def unix? ; !jruby? && !windows? end
388
+ def mac? ; RbConfig::CONFIG['host_os'] =~ /^darwin/ end
389
+
390
+ #
391
+ # Check if host exists
392
+ #
393
+ def host_exists?(host)
394
+ # :nocov:
395
+ # Patch for BZ840938 to support Ruby 1.8 on machines without /etc/resolv.conf
396
+ dns = Resolv::DNS.new((Resolv::DNS::Config.default_config_hash || {}))
397
+ resources = dns.getresources(host, Resolv::DNS::Resource::IN::A)
398
+ debug("Checking for #{host} from Resolv::DNS: #{resources.inspect}") if debug?
399
+ resources.present?
400
+ # :nocov:
401
+ end
402
+
403
+ def hosts_file_contains?(host)
404
+ with_tolerant_encoding do
405
+ begin
406
+ resolver = Resolv::Hosts.new
407
+ result = resolver.getaddress host
408
+ debug("Checking for #{host} from Resolv::Hosts: #{result.inspect}") if debug?
409
+ result
410
+ rescue => e
411
+ debug "Error while resolving with Resolv::Hosts: #{e.message}(#{e.class})\n #{e.backtrace.join("\n ")}"
412
+ end
413
+ end
414
+ end
415
+
416
+ def with_tolerant_encoding(&block)
417
+ # :nocov:
418
+ if RUBY_VERSION.to_f >= 1.9
419
+ orig_default_internal = Encoding.default_internal
420
+ Encoding.default_internal = 'ISO-8859-1'
421
+ else
422
+ orig_default_kcode = $KCODE
423
+ $KCODE = 'N'
424
+ end
425
+ yield
426
+ ensure
427
+ if RUBY_VERSION.to_f >= 1.9
428
+ Encoding.default_internal = orig_default_internal
429
+ else
430
+ $KCODE = orig_default_kcode
431
+ end
432
+ # :nocov:
433
+ end
434
+
435
+ # Run a command and export its output to the user. Output is not capturable
436
+ # on all platforms.
437
+ def run_with_tee(cmd)
438
+ status, stdout, stderr = nil
439
+
440
+ if windows?
441
+ #:nocov: TODO: Test block
442
+ system(cmd)
443
+ status = $?.exitstatus
444
+ #:nocov:
445
+ else
446
+ stdout, stderr = [$stdout, $stderr].map{ |t| StringTee.new(t) }
447
+ status = Open4.spawn(cmd, 'stdout' => stdout, 'stderr' => stderr, 'quiet' => true)
448
+ stdout, stderr = [stdout, stderr].map(&:string)
449
+ end
450
+
451
+ [status, stdout, stderr]
452
+ end
453
+
454
+ def env_var_regex_pattern
455
+ /^([a-zA-Z_][\w]*)=(.*)$/
456
+ end
457
+
458
+ def collect_env_vars(items)
459
+ return nil if items.blank?
460
+
461
+ env_vars = []
462
+
463
+ Array(items).each do |item|
464
+ if match = item.match(env_var_regex_pattern)
465
+ name, value = match.captures
466
+ env_vars << RHC::Rest::EnvironmentVariable.new({ :name => name, :value => value })
467
+ elsif File.file? item
468
+ File.readlines(item).each do |line|
469
+ if match = line.match(env_var_regex_pattern)
470
+ name, value = match.captures
471
+ env_vars << RHC::Rest::EnvironmentVariable.new({ :name => name, :value => value })
472
+ end
473
+ end
474
+ end
475
+ end
476
+ env_vars
477
+ end
478
+
479
+ BOUND_WARNING = self.method(:warn).to_proc
480
+ end
481
+ end