Module: RHC::Helpers

Extended by:
Helpers
Includes:
Commander::UI, Commander::UI::AskForClass, OutputHelpers
Included in:
Auth::Basic, Auth::Token, CommandHelpBindings, Commands::Base, Commands::ForwardingSpec, Helpers, Rest::Api, Rest::Client, RunnerHelpBindings, Wizard
Defined in:
lib/rhc/helpers.rb,
lib/rhc/helpers.rb

Defined Under Namespace

Classes: StringTee

Constant Summary collapse

PREFIX =
%W(TB GB MB KB B).freeze
ROLES =
{'view' => 'viewer', 'edit' => 'editor', 'admin' => 'administrator'}
BOUND_WARNING =
self.method(:warn).to_proc

Instance Method Summary collapse

Methods included from OutputHelpers

#default_display_env_var, #display_app, #display_app_configurations, #display_authorization, #display_cart, #display_cart_storage_info, #display_cart_storage_list, #display_deployment, #display_deployment_list, #display_domain, #display_env_var_list, #display_key, #display_team, #format_cart_gears, #format_cart_header, #format_gear_info, #format_key_header, #format_scaling_info, #format_usage_message

Instance Method Details

#agree(*args, &block) ⇒ Object

By default, agree should take a single character in interactive



265
266
267
268
269
270
271
# File 'lib/rhc/helpers.rb', line 265

def agree(*args, &block)
  #args.push(interactive?.presence) if args.length == 1
  block = lambda do |q|
    q.validate = /\A(?:y|yes|n|no)\Z/i
  end unless block_given?
  super *args, &block
end

#certificate_file(file) ⇒ Object



218
219
220
221
222
223
# File 'lib/rhc/helpers.rb', line 218

def certificate_file(file)
  file && OpenSSL::X509::Certificate.new(IO.read(File.expand_path(file)))
rescue => e
  debug e
  raise OptionParser::InvalidOption.new(nil, "The certificate '#{file}' cannot be loaded: #{e.message} (#{e.class})")
end

#client_from_options(opts) ⇒ Object



200
201
202
203
204
205
206
207
# File 'lib/rhc/helpers.rb', line 200

def client_from_options(opts)
  RHC::Rest::Client.new({
      :url => openshift_rest_endpoint.to_s,
      :debug => options.debug,
      :timeout => options.timeout,
      :warn => BOUND_WARNING,
    }.merge!(ssl_options).merge!(opts))
end

#collect_env_vars(items) ⇒ Object



458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/rhc/helpers.rb', line 458

def collect_env_vars(items)
  return nil if items.blank?

  env_vars = []

  Array(items).each do |item|
    if match = item.match(env_var_regex_pattern)
      name, value = match.captures
      env_vars << RHC::Rest::EnvironmentVariable.new({ :name => name, :value => value })
    elsif File.file? item
      File.readlines(item).each do |line|
        if match = line.match(env_var_regex_pattern)
          name, value = match.captures
          env_vars << RHC::Rest::EnvironmentVariable.new({ :name => name, :value => value })
        end
      end
    end
  end
  env_vars
end

#color(item, *args) ⇒ Object

OVERRIDE: Replaces default commander behavior



296
297
298
299
300
301
302
# File 'lib/rhc/helpers.rb', line 296

def color(item, *args)
  if item.is_a? Array
    item.map{ |i| $terminal.color(i, *args) }
  else
    $terminal.color(item, *args)
  end
end

#confirm_action(question) ⇒ Object



273
274
275
276
277
# File 'lib/rhc/helpers.rb', line 273

def confirm_action(question)
  return if options.confirm
  return if !options.noprompt && paragraph{ agree "#{question} (yes|no): " }
  raise RHC::ConfirmationError
end

#date(s) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rhc/helpers.rb', line 51

def date(s)
  return nil unless s.present?
  now = Date.today
  d = datetime_rfc3339(s).to_time
  if now.year == d.year
    return d.strftime('%l:%M %p').strip if now.yday == d.yday
    d.strftime('%b %d %l:%M %p')
  else
    d.strftime('%b %d, %Y %l:%M %p')
  end
rescue ArgumentError
  "Unknown date"
end

#datetime_rfc3339(s) ⇒ Object



88
89
90
91
# File 'lib/rhc/helpers.rb', line 88

def datetime_rfc3339(s)
  DateTime.strptime(s, '%Y-%m-%dT%H:%M:%S%z')
  # Replace with d = DateTime.rfc3339(s)
end

#debug(*args) ⇒ Object



234
235
236
# File 'lib/rhc/helpers.rb', line 234

def debug(*args)
  $terminal.debug(*args)
end

#debug?Boolean

Returns:

  • (Boolean)


240
241
242
# File 'lib/rhc/helpers.rb', line 240

def debug?
  $terminal.debug?
end

#debug_error(*args) ⇒ Object



237
238
239
# File 'lib/rhc/helpers.rb', line 237

def debug_error(*args)
  $terminal.debug_error(*args)
end

#decode_json(s) ⇒ Object



29
30
31
# File 'lib/rhc/helpers.rb', line 29

def decode_json(s)
  RHC::Vendor::OkJson.decode(s)
end

#deprecated(msg, short = false) ⇒ Object

Raises:



257
258
259
260
# File 'lib/rhc/helpers.rb', line 257

def deprecated(msg,short = false)
  raise DeprecatedError.new(msg % ['an error','a warning',0]) if disable_deprecated?
  warn "Warning: #{msg}\n" % ['a warning','an error',1]
end

#deprecated_command(correct, short = false) ⇒ Object



253
254
255
# File 'lib/rhc/helpers.rb', line 253

def deprecated_command(correct, short=false)
  deprecated("This command is deprecated. Please use '#{correct}' instead.", short)
end

#disable_deprecated?Boolean

Returns:

  • (Boolean)


249
250
251
# File 'lib/rhc/helpers.rb', line 249

def disable_deprecated?
  ENV['DISABLE_DEPRECATED'] == '1'
end

#distance_of_time_in_words(from_time, to_time = 0) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rhc/helpers.rb', line 65

def distance_of_time_in_words(from_time, to_time = 0)
  from_time = from_time.to_time if from_time.respond_to?(:to_time)
  to_time = to_time.to_time if to_time.respond_to?(:to_time)
  distance_in_minutes = (((to_time - from_time).abs)/60).round
  distance_in_seconds = ((to_time - from_time).abs).round

  case distance_in_minutes
    when 0..1
      return distance_in_minutes == 0 ?
             "less than 1 minute" :
             "#{distance_in_minutes} minute"

    when 2..44           then "#{distance_in_minutes} minutes"
    when 45..89          then "about 1 hour"
    when 90..1439        then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
    when 1440..2519      then "about 1 day"
    when 2520..43199     then "#{(distance_in_minutes.to_f / 1440.0).round} days"
    when 43200..86399    then "about 1 month"
    else
      "about #{(distance_in_minutes.to_f / 43200.0).round} months"
  end
end

#env_var_regex_patternObject



454
455
456
# File 'lib/rhc/helpers.rb', line 454

def env_var_regex_pattern
  /^([a-zA-Z_][\w]*)=(.*)$/
end

#error(msg, *args) ⇒ Object



291
292
293
# File 'lib/rhc/helpers.rb', line 291

def error(msg, *args)
  say color(msg, :red), *args
end

#exec(cmd) ⇒ Object



244
245
246
247
# File 'lib/rhc/helpers.rb', line 244

def exec(cmd)
  output = Kernel.send(:`, cmd)
  [$?.exitstatus, output]
end

#host_exists?(host) ⇒ Boolean

Check if host exists

Returns:

  • (Boolean)


393
394
395
396
397
398
399
400
401
# File 'lib/rhc/helpers.rb', line 393

def host_exists?(host)
  # :nocov:
  # Patch for BZ840938 to support Ruby 1.8 on machines without /etc/resolv.conf
  dns = Resolv::DNS.new((Resolv::DNS::Config.default_config_hash || {}))
  resources = dns.getresources(host, Resolv::DNS::Resource::IN::A)
  debug("Checking for #{host} from Resolv::DNS: #{resources.inspect}") if debug?
  resources.present?
  # :nocov:
end

#hosts_file_contains?(host) ⇒ Boolean

Returns:

  • (Boolean)


403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/rhc/helpers.rb', line 403

def hosts_file_contains?(host)
  with_tolerant_encoding do
    begin
      resolver = Resolv::Hosts.new
      result = resolver.getaddress host
      debug("Checking for #{host} from Resolv::Hosts: #{result.inspect}") if debug?
      result
    rescue => e
      debug "Error while resolving with Resolv::Hosts: #{e.message}(#{e.class})\n  #{e.backtrace.join("\n  ")}"
    end
  end
end

#human_size(s) ⇒ Object



40
41
42
43
44
45
46
47
48
49
# File 'lib/rhc/helpers.rb', line 40

def human_size( s )
  return "unknown" unless s
  s = s.to_f
  i = PREFIX.length - 1
  while s > 500 && i > 0
    i -= 1
    s /= 1000
  end
  ((s > 9 || s.modulo(1) < 0.1 ? '%d' : '%.1f') % s) + ' ' + PREFIX[i]
end

#info(msg, *args) ⇒ Object



283
284
285
# File 'lib/rhc/helpers.rb', line 283

def info(msg, *args)
  say color(msg, :cyan), *args
end

#interactive?Boolean

Output helpers

Returns:

  • (Boolean)


230
231
232
# File 'lib/rhc/helpers.rb', line 230

def interactive?
  $stdin.tty? and $stdout.tty? and not options.noprompt
end

#jruby?Boolean

Platform helpers

Returns:

  • (Boolean)


385
# File 'lib/rhc/helpers.rb', line 385

def jruby? ; RUBY_PLATFORM =~ /java/i end

#mac?Boolean

Returns:

  • (Boolean)


388
# File 'lib/rhc/helpers.rb', line 388

def mac? ; RbConfig::CONFIG['host_os'] =~ /^darwin/ end

#openshift_online_server?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/rhc/helpers.rb', line 158

def openshift_online_server?
  openshift_server =~ /api.startappcloud.com$/i
end

#openshift_rest_endpointObject



190
191
192
193
194
# File 'lib/rhc/helpers.rb', line 190

def openshift_rest_endpoint
  uri = to_uri((options.server rescue nil) || ENV['LIBRA_SERVER'] || "api.startappcloud.com")
  uri.path = '/broker/rest/api' if uri.path.blank? || uri.path == '/'
  uri
end

#openshift_serverObject



155
156
157
# File 'lib/rhc/helpers.rb', line 155

def openshift_server
  to_host((options.server rescue nil) || ENV['LIBRA_SERVER'] || "api.startappcloud.com")
end

#openshift_urlObject



161
162
163
# File 'lib/rhc/helpers.rb', line 161

def openshift_url
  "https://#{openshift_server}"
end

#pluralize(count, s) ⇒ Object



310
311
312
# File 'lib/rhc/helpers.rb', line 310

def pluralize(count, s)
  count == 1 ? "#{count} #{s}" : "#{count} #{s}s"
end

#results(&block) ⇒ Object

results

highline helper which creates a paragraph with a header to distinguish the final results of a command from other output



377
378
379
380
381
382
# File 'lib/rhc/helpers.rb', line 377

def results(&block)
  section(:top => 1, :bottom => 0) do
    say "RESULT:"
    yield
  end
end

#role_name(s) ⇒ Object



151
152
153
# File 'lib/rhc/helpers.rb', line 151

def role_name(s)
  ROLES[s.downcase]
end

#run_with_tee(cmd) ⇒ Object

Run a command and export its output to the user. Output is not capturable on all platforms.



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/rhc/helpers.rb', line 437

def run_with_tee(cmd)
  status, stdout, stderr = nil

  if windows? || jruby?
    #:nocov: TODO: Test block
    system(cmd)
    status = $?.exitstatus
    #:nocov:
  else
    stdout, stderr = [$stdout, $stderr].map{ |t| StringTee.new(t) }
    status = Open4.spawn(cmd, 'stdout' => stdout, 'stderr' => stderr, 'quiet' => true)
    stdout, stderr = [stdout, stderr].map(&:string)
  end

  [status, stdout, stderr]
end

#ssh_string(ssh_url) ⇒ Object



176
177
178
179
180
181
182
183
# File 'lib/rhc/helpers.rb', line 176

def ssh_string(ssh_url)
  return nil if ssh_url.blank?
  uri = URI.parse(ssh_url)
  "#{uri.user}@#{uri.host}"
rescue => e
  RHC::Helpers.debug_error(e)
  ssh_url
end

#ssh_string_parts(ssh_url) ⇒ Object



185
186
187
188
# File 'lib/rhc/helpers.rb', line 185

def ssh_string_parts(ssh_url)
  uri = URI.parse(ssh_url)
  [uri.host, uri.user]
end

#ssl_optionsObject



209
210
211
212
213
214
215
216
# File 'lib/rhc/helpers.rb', line 209

def ssl_options
  {
    :ssl_version => options.ssl_version,
    :client_cert => certificate_file(options.ssl_client_cert),
    :ca_file => options.ssl_ca_file && File.expand_path(options.ssl_ca_file),
    :verify_mode => options.insecure ? OpenSSL::SSL::VERIFY_NONE : nil,
  }.delete_if{ |k,v| v.nil? }
end

#success(msg, *args) ⇒ Object



279
280
281
# File 'lib/rhc/helpers.rb', line 279

def success(msg, *args)
  say color(msg, :green), *args
end

#system_path(path) ⇒ Object



33
34
35
36
# File 'lib/rhc/helpers.rb', line 33

def system_path(path)
  return path.gsub(File::SEPARATOR, File::ALT_SEPARATOR) if File.const_defined?('ALT_SEPARATOR') and File::ALT_SEPARATOR.present?
  path
end

#table_heading(value) ⇒ Object

This will format table headings for a consistent look and feel

If a heading isn't explicitly defined, it will attempt to look up the parts
If those aren't found, it will capitalize the string


317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/rhc/helpers.rb', line 317

def table_heading(value)
  # Set the default proc to look up undefined values
  headings = Hash.new do |hash,key|
    items = key.to_s.split('_')
    # Look up each piece individually
    hash[key] = items.length > 1 ?
      # Recusively look up the heading for the parts
      items.map{|x| headings[x.to_sym]}.join(' ') :
      # Capitalize if this part isn't defined
      items.first.capitalize
  end

  # Predefined headings (or parts of headings)
  headings.merge!({
    :creation_time  => "Created",
    :expires_in_seconds => "Expires In",
    :uuid            => "ID",
    :id              => 'ID',
    :current_scale   => "Current",
    :scales_from     => "Minimum",
    :scales_to       => "Maximum",
    :gear_sizes      => "Allowed Gear Sizes",
    :consumed_gears  => "Gears Used",
    :max_gears       => "Gears Allowed",
    :max_domains     => "Domains Allowed",
    :compact_members => "Members",
    :gear_info       => "Gears",
    :plan_id         => "Plan",
    :url             => "URL",
    :ssh_string      => "SSH",
    :connection_info => "Connection URL",
    :gear_profile    => "Gear Size",
    :visible_to_ssh? => 'Available',
    :downloaded_cartridge_url => 'From',
    :auto_deploy     => 'Deployment',
    :sha1            => 'SHA1',
    :ref             => 'Git Reference'
  })

  headings[value]
end

#to_host(s) ⇒ Object



165
166
167
# File 'lib/rhc/helpers.rb', line 165

def to_host(s)
  s =~ %r(^http(?:s)?://) ? URI(s).host : s
end

#to_uri(s) ⇒ Object



168
169
170
171
172
173
174
# File 'lib/rhc/helpers.rb', line 168

def to_uri(s)
  begin
    URI(s =~ %r(^http(?:s)?://) ? s : "https://#{s}")
  rescue URI::InvalidURIError
    raise RHC::InvalidURIException.new(s)
  end
end

#token_for_userObject



196
197
198
# File 'lib/rhc/helpers.rb', line 196

def token_for_user
  options.token or (token_store.get(options.rhlogin, options.server) if options.rhlogin && options.use_authorization_tokens)
end

#unix?Boolean

Returns:

  • (Boolean)


387
# File 'lib/rhc/helpers.rb', line 387

def unix? ; !jruby? && !windows? end

#user_agentObject

Web related requests



97
98
99
# File 'lib/rhc/helpers.rb', line 97

def user_agent
  "app/#{RHC::VERSION::STRING} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})#{" (API #{RHC::Rest::Client::CLIENT_API_VERSIONS})"}"
end

#warn(msg, *args) ⇒ Object



287
288
289
# File 'lib/rhc/helpers.rb', line 287

def warn(msg, *args)
  say color(msg, :yellow), *args
end

#windows?Boolean

Returns:

  • (Boolean)


386
# File 'lib/rhc/helpers.rb', line 386

def windows? ; RUBY_PLATFORM =~ /win(32|dows|ce)|djgpp|(ms|cyg|bcc)win|mingw32/i end

#with_tolerant_encoding(&block) ⇒ Object



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/rhc/helpers.rb', line 416

def with_tolerant_encoding(&block)
  # :nocov:
  if RUBY_VERSION.to_f >= 1.9
    orig_default_internal = Encoding.default_internal
    Encoding.default_internal = 'ISO-8859-1'
  else
    orig_default_kcode = $KCODE
    $KCODE = 'N'
  end
  yield
ensure
  if RUBY_VERSION.to_f >= 1.9
    Encoding.default_internal = orig_default_internal
  else
    $KCODE = orig_default_kcode
  end
  # :nocov:
end