class CF::CLI

Public Class Methods

client() click to toggle source
# File lib/cf/cli.rb, line 447
def client
  @@client
end
client=(c) click to toggle source
# File lib/cf/cli.rb, line 451
def client=(c)
  @@client = c
end

Private Class Methods

by_name(what, display = what) click to toggle source
# File lib/cf/cli.rb, line 467
def by_name(what, display = what)
  proc { |name, *_|
    client.send(:"#{what}_by_name", name) ||
      fail_unknown(display, name)
  }
end
find_by_name(display, &blk) click to toggle source
# File lib/cf/cli.rb, line 457
def find_by_name(display, &blk)
  proc { |name, *args|
    choices, _ = args
    choices ||= instance_exec(&blk) if block_given?

    choices.find { |c| c.name == name } ||
      fail_unknown(display, name)
  }
end
find_by_name_insensitive(display, &blk) click to toggle source
# File lib/cf/cli.rb, line 474
def find_by_name_insensitive(display, &blk)
  proc { |name, *args|
    choices, _ = args
    choices ||= instance_exec(&blk) if block_given?

    choices.find { |c| c.name.upcase == name.upcase } ||
      fail_unknown(display, name)
  }
end

Public Instance Methods

add_exception_name_to_msg(e) click to toggle source
# File lib/cf/cli.rb, line 180
def add_exception_name_to_msg(e)
  msg = e.class.name
  msg << ": #{e}" unless e.to_s.empty?
  msg
end
build_client(target, token = nil) click to toggle source
# File lib/cf/cli.rb, line 435
def build_client(target, token = nil)
  client = CFoundry::V2::Client.new(target, token)
  client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy']
  client.https_proxy = input[:https_proxy] || ENV['HTTPS_PROXY'] || ENV['https_proxy']
  client
end
check_logged_in() click to toggle source
# File lib/cf/cli.rb, line 76
def check_logged_in
  check_target
  unless client.logged_in?
    if force?
      fail "Please log in with 'truck login'."
    else
      line c("Please log in first to proceed.", :warning)
      line
      invoke :login
      invalidate_client
    end
  end
end
check_target() click to toggle source
# File lib/cf/cli.rb, line 70
def check_target
  unless client && client.target
    fail "Please select a target with 'truck target'."
  end
end
client(target = client_target) click to toggle source
# File lib/cf/cli.rb, line 407
def client(target = client_target)
  return @@client if defined?(@@client) && @@client
  return unless target

  info = target_info(target)
  token = info[:token] && CFoundry::AuthToken.from_hash(info)

  fail "V1 targets are no longer supported." if info[:version] == 1

  @@client = build_client(target, token)

  @@client.trace = input[:trace]

  uri = URI.parse(target)
  @@client.log = File.expand_path("#{LOGS_DIR}/#{uri.host}.log")

  unless info.key? :version
    info[:version] = @@client.version
    save_target_info(info, target)
  end

  @@client.current_organization = @@client.organization(info[:organization]) if info[:organization]
  @@client.current_space = @@client.space(info[:space]) if info[:space]

  @@client
rescue CFoundry::InvalidTarget
end
client_target() click to toggle source
# File lib/cf/cli.rb, line 338
def client_target
  return File.read(target_file).chomp if File.exists?(target_file)
end
color_enabled?() click to toggle source
# File lib/cf/cli.rb, line 270
def color_enabled?
  input[:color]
end
debug?() click to toggle source
# File lib/cf/cli.rb, line 266
def debug?
  !!input[:debug]
end
default_action() click to toggle source
Calls superclass method
# File lib/cf/cli.rb, line 62
def default_action
  if input[:version]
    line "cf #{VERSION}"
  else
    super
  end
end
ensure_config_dir() click to toggle source
# File lib/cf/cli.rb, line 342
def ensure_config_dir
  config = File.expand_path(CF::CONFIG_DIR)
  FileUtils.mkdir_p(config) unless File.exist? config
end
err(msg, status = 1) click to toggle source
# File lib/cf/cli.rb, line 301
def err(msg, status = 1)
  $stderr.puts c(msg, :error)
  exit_status status
end
execute(cmd, argv, global = {}) click to toggle source
Calls superclass method
# File lib/cf/cli.rb, line 186
def execute(cmd, argv, global = {})
  if input[:help]
    invoke :help, :command => cmd.name.to_s
  else
    wrap_errors do
      @command = cmd
      precondition if respond_to? :precondition

      save_token_if_it_changes do
        super
      end
    end
  end
end
fail(msg) click to toggle source
# File lib/cf/cli.rb, line 306
def fail(msg)
  raise UserError, msg
end
fail_unknown(display, name) click to toggle source
# File lib/cf/cli.rb, line 442
def fail_unknown(display, name)
  fail("Unknown #{display} '#{name}'.")
end
force?() click to toggle source
# File lib/cf/cli.rb, line 262
def force?
  input[:force]
end
formatted_exception_output(e, msg) click to toggle source
# File lib/cf/cli.rb, line 173
def formatted_exception_output(e, msg)
  log_error(e)
  err msg

  raise if debug?
end
help() click to toggle source
# File lib/cf/cli.rb, line 92
def help
  if name = input[:command]
    if cmd = @@commands[name.gsub("-", "_").to_sym]
      Mothership::Help.command_help(cmd)
    else
      unknown_command(name)
    end
  elsif Help.has_groups?
    puts "#{help_header}"

    Mothership::Help.print_help_groups(@@global, true)
  else
    Mothership::Help.basic_help(@@commands, @@global)
  end
end
help_header() click to toggle source
# File lib/cf/cli.rb, line 108
    def help_header
    <<EOS
Cloud Foundry Command Line Interface, version [#{CF::VERSION}]
  Use 'truck help [command]' for command details.
  For docs and support visit http://support.cloudfoundry.com

USAGE EXAMPLES
  $ cf target api.trucker.io        <-- sets the CF instance target where your app will be pushed
  $ cf push                         <-- deploys app to current app space on current target
  $ cf target -s staging            <-- changes currently targeted app space to 'staging'

EOS
    end
invalidate_client() click to toggle source
# File lib/cf/cli.rb, line 402
def invalidate_client
  @@client = nil
  client
end
log_error(e) click to toggle source
# File lib/cf/cli.rb, line 219
def log_error(e)
  ensure_config_dir

  msg = e.class.name
  msg << ": #{e}" unless e.to_s.empty?

  crash_file = File.expand_path(CF::CRASH_FILE)

  FileUtils.mkdir_p(File.dirname(crash_file))

  File.open(crash_file, "w") do |f|
    f.puts "Time of crash:"
    f.puts "  #{Time.now}"
    f.puts ""
    f.puts msg
    f.puts ""

    if e.respond_to?(:request_trace)
      f.puts "<<<"
      f.puts e.request_trace
    end

    if e.respond_to?(:response_trace)
      f.puts e.response_trace
      f.puts ">>>"
      f.puts ""
    end

    cf_dir = File.expand_path("../../../..", __FILE__) + "/"
    e.backtrace.each do |loc|
      if loc =~ /\/gems\//
        f.puts loc.sub(/.*\/gems\//, "")
      else
        f.puts loc.sub(cf_dir, "")
      end
    end
  end
end
log_error_and_dump_crashlog(e) click to toggle source
# File lib/cf/cli.rb, line 166
def log_error_and_dump_crashlog(e)
  log_error(e)
  err File.open(File.expand_path(CF::CRASH_FILE)).readlines.join("")

  raise if debug?
end
name_list(xs) click to toggle source
# File lib/cf/cli.rb, line 316
def name_list(xs)
  if xs.empty?
    d("none")
  else
    xs.collect { |x| c(x.name, :name) }.join(", ")
  end
end
normalize_targets_info(info_by_url) click to toggle source
# File lib/cf/cli.rb, line 370
def normalize_targets_info(info_by_url)
  info_by_url.reduce({}) do |hash, pair|
    key, value = pair
    hash[key] = value.is_a?(String) ? { :token => value } : value
    hash
  end
end
one_of(*paths) click to toggle source
# File lib/cf/cli.rb, line 329
def one_of(*paths)
  paths.each do |p|
    exp = File.expand_path(p)
    return exp if File.exist? exp
  end

  File.expand_path(paths.first)
end
quiet?() click to toggle source
# File lib/cf/cli.rb, line 258
def quiet?
  input[:quiet]
end
remove_target_info(target = client_target) click to toggle source
# File lib/cf/cli.rb, line 396
def remove_target_info(target = client_target)
  ts = targets_info
  ts.delete target
  save_targets(ts)
end
sane_target_url(url) click to toggle source
# File lib/cf/cli.rb, line 324
def sane_target_url(url)
  url = "https://#{url}" if url !~ /^http/
  url.gsub(/\/$/, "")
end
save_target_info(info, target = client_target) click to toggle source
# File lib/cf/cli.rb, line 390
def save_target_info(info, target = client_target)
  ts = targets_info
  ts[target] = info
  save_targets(ts)
end
save_targets(ts) click to toggle source
# File lib/cf/cli.rb, line 382
def save_targets(ts)
  ensure_config_dir

  File.open(File.expand_path(CF::TOKENS_FILE), "w") do |io|
    YAML.dump(ts, io)
  end
end
save_token_if_it_changes() { || ... } click to toggle source
# File lib/cf/cli.rb, line 201
def save_token_if_it_changes
  return yield unless client && client.token

  before_token = client.token

  yield

  after_token = client.token

  return unless after_token

  if before_token != after_token
    info = target_info
    info[:token] = after_token.auth_header
    save_target_info(info)
  end
end
set_target(url) click to toggle source
# File lib/cf/cli.rb, line 347
def set_target(url)
  ensure_config_dir

  File.open(File.expand_path(CF::TARGET_FILE), "w") do |f|
    f.write(url)
  end

  invalidate_client
end
table(headers, rows) click to toggle source
# File lib/cf/cli.rb, line 310
def table(headers, rows)
  tabular(
    !quiet? && headers.collect { |h| h && b(h) },
    *rows)
end
target_info(target = client_target) click to toggle source
# File lib/cf/cli.rb, line 378
def target_info(target = client_target)
  targets_info[target] || {}
end
targets_info() click to toggle source
# File lib/cf/cli.rb, line 357
def targets_info
  new_toks = File.expand_path(CF::TOKENS_FILE)

  info =
    if File.exist? new_toks
      YAML.load_file(new_toks)
    end

  info ||= {}

  normalize_targets_info(info)
end
user_colors() click to toggle source
Calls superclass method
# File lib/cf/cli.rb, line 278
def user_colors
  return @user_colors if @user_colors

  colors = File.expand_path(COLORS_FILE)

  @user_colors = super.dup

  # most terminal schemes are stupid, so use cyan instead
  @user_colors.each do |k, v|
    if v == :blue
      @user_colors[k] = :cyan
    end
  end

  if File.exists?(colors)
    YAML.load_file(colors).each do |k, v|
      @user_colors[k.to_sym] = v.to_sym
    end
  end

  @user_colors
end
verbose?() click to toggle source
# File lib/cf/cli.rb, line 274
def verbose?
  input[:verbose]
end
wrap_errors() { || ... } click to toggle source
# File lib/cf/cli.rb, line 122
def wrap_errors
  yield
rescue CFoundry::Timeout => e
  err(e.message)
rescue Interrupt
  exit_status 130
rescue Mothership::Error
  raise
rescue UserError => e
  log_error(e)
  err e.message
rescue SystemExit
  raise
rescue UserFriendlyError => e
  err e.message
rescue CFoundry::InvalidAuthToken => e
  line
  line c("Invalid authentication token. Try logging in again with 'truck login'. If problems continue, please contact your Cloud Operator.", :warning)
rescue CFoundry::Forbidden => e
  if !$cf_asked_auth
    $cf_asked_auth = true

    line
    line c("Not authenticated! Try logging in:", :warning)

    # TODO: there's no color here; global flags not being passed
    # through (mothership bug?)
    invoke :login

    retry
  end

  log_error(e)

  err "Denied: #{e.description}"
rescue CFoundry::StagingError => e
  message = "Application failed to stage"
  formatted_exception_output(e, message)
rescue CFoundry::APIError => e
  formatted_exception_output(e, add_exception_name_to_msg(e))
rescue Exception => e
  log_error_and_dump_crashlog(e)
end

Private Instance Methods

target_file() click to toggle source
# File lib/cf/cli.rb, line 487
def target_file
  File.expand_path(CF::TARGET_FILE)
end
tokens_file() click to toggle source
# File lib/cf/cli.rb, line 491
def tokens_file
  File.expand_path(CF::TOKENS_FILE)
end