module Heroku::Command

Constants

BaseWithApp

Public Class Methods

command_aliases() click to toggle source
# File lib/heroku/command.rb, line 24
def self.command_aliases
  @@command_aliases ||= {}
end
commands() click to toggle source
# File lib/heroku/command.rb, line 20
def self.commands
  @@commands ||= {}
end
current_args() click to toggle source
# File lib/heroku/command.rb, line 48
def self.current_args
  @current_args
end
current_command() click to toggle source
# File lib/heroku/command.rb, line 44
def self.current_command
  @current_command
end
current_options() click to toggle source
# File lib/heroku/command.rb, line 52
def self.current_options
  @current_options
end
extract_error(body, options={}) { |: "Internal server error.\nRun 'heroku status' to check for known platform issues."| ... } click to toggle source
# File lib/heroku/command.rb, line 181
def self.extract_error(body, options={})
  default_error = block_given? ? yield : "Internal server error.\nRun 'heroku status' to check for known platform issues."
  parse_error_xml(body) || parse_error_json(body) || parse_error_plain(body) || default_error
end
files() click to toggle source
# File lib/heroku/command.rb, line 28
def self.files
  @@files ||= Hash.new {|hash,key| hash[key] = File.readlines(key).map {|line| line.strip}}
end
global_option(name, *args) click to toggle source
# File lib/heroku/command.rb, line 60
def self.global_option(name, *args)
  global_options << { :name => name, :args => args }
end
global_options() click to toggle source
# File lib/heroku/command.rb, line 56
def self.global_options
  @global_options ||= []
end
load() click to toggle source
# File lib/heroku/command.rb, line 13
def self.load
  Dir[File.join(File.dirname(__FILE__), "command", "*.rb")].each do |file|
    require file
  end
  Heroku::Plugin.load!
end
namespaces() click to toggle source
# File lib/heroku/command.rb, line 32
def self.namespaces
  @@namespaces ||= {}
end
parse(cmd) click to toggle source
# File lib/heroku/command.rb, line 177
def self.parse(cmd)
  commands[cmd] || commands[command_aliases[cmd]]
end
parse_error_json(body) click to toggle source
# File lib/heroku/command.rb, line 193
def self.parse_error_json(body)
  json = json_decode(body.to_s) rescue false
  json ? json['error'] : nil
end
parse_error_plain(body) click to toggle source
# File lib/heroku/command.rb, line 198
def self.parse_error_plain(body)
  return unless body.respond_to?(:headers) && body.headers[:content_type].to_s.include?("text/plain")
  body.to_s
end
parse_error_xml(body) click to toggle source
# File lib/heroku/command.rb, line 186
def self.parse_error_xml(body)
  xml_errors = REXML::Document.new(body).elements.to_a("//errors/error")
  msg = xml_errors.map { |a| a.text }.join(" / ")
  return msg unless msg.empty?
rescue Exception
end
prepare_run(cmd, args=[]) click to toggle source
# File lib/heroku/command.rb, line 69
def self.prepare_run(cmd, args=[])
  command = parse(cmd)

  unless command
    if %w( -v --version ).include?(cmd)
      display Heroku::VERSION
      exit
    end

    output_with_bang("`#{cmd}` is not a heroku command.")

    distances = {}
    (commands.keys + command_aliases.keys).each do |suggestion|
      distance = string_distance(cmd, suggestion)
      distances[distance] ||= []
      distances[distance] << suggestion
    end

    if distances.keys.min < 4
      suggestions = distances[distances.keys.min].sort
      if suggestions.length == 1
        output_with_bang("Perhaps you meant `#{suggestions.first}`.")
      else
        output_with_bang("Perhaps you meant #{suggestions[0...-1].map {|suggestion| "`#{suggestion}`"}.join(', ')} or `#{suggestions.last}`.")
      end
    end

    output_with_bang("See `heroku help` for additional details.")
    exit(1)
  end

  @current_command = cmd

  opts = {}
  invalid_options = []

  parser = OptionParser.new do |parser|
    # overwrite OptionParsers Officious['version'] to avoid conflicts
    # see: https://github.com/ruby/ruby/blob/trunk/lib/optparse.rb#L814
    parser.on("--version") do |value|
      invalid_options << "--version"
    end
    global_options.each do |global_option|
      parser.on(*global_option[:args]) do |value|
        opts[global_option[:name]] = value
      end
    end
    command[:options].each do |name, option|
      parser.on("-#{option[:short]}", "--#{option[:long]}", option[:desc]) do |value|
        opts[name.gsub("-", "_").to_sym] = value
      end
    end
  end

  begin
    parser.order!(args) do |nonopt|
      invalid_options << nonopt
    end
  rescue OptionParser::InvalidOption => ex
    invalid_options << ex.args.first
    retry
  end

  if opts[:help]
    args.unshift cmd unless cmd =~ %r^-.*/
    cmd = "help"
    command = parse(cmd)
  end

  args.concat(invalid_options)

  @current_args = args
  @current_options = opts

  [ command[:klass].new(args.dup, opts.dup), command[:method] ]
end
register_command(command) click to toggle source
# File lib/heroku/command.rb, line 36
def self.register_command(command)
  commands[command[:command]] = command
end
register_namespace(namespace) click to toggle source
# File lib/heroku/command.rb, line 40
def self.register_namespace(namespace)
  namespaces[namespace[:name]] = namespace
end
run(cmd, arguments=[]) click to toggle source
# File lib/heroku/command.rb, line 146
def self.run(cmd, arguments=[])
  object, method = prepare_run(cmd, arguments.dup)
  object.send(method)
rescue RestClient::Unauthorized
  puts "Authentication failure"
  unless ENV['HEROKU_API_KEY']
    run "login"
    retry
  end
rescue RestClient::PaymentRequired => e
  retry if run('account:confirm_billing', arguments.dup)
rescue RestClient::ResourceNotFound => e
  error extract_error(e.http_body) {
    e.http_body =~ %r^[\w\s]+ not found.?$/ ? e.http_body : "Resource not found"
  }
rescue RestClient::Locked => e
  app = e.response.headers[:x_confirmation_required]
  if confirm_command(app, extract_error(e.response.body))
    arguments << '--confirm' << app
    retry
  end
rescue RestClient::RequestFailed => e
  error extract_error(e.http_body)
rescue RestClient::RequestTimeout
  error "API request timed out. Please try again, or contact support@heroku.com if this issue persists."
rescue CommandFailed => e
  error e.message
rescue OptionParser::ParseError => ex
  commands[cmd] ? run("help", [cmd]) : run("help")
end