lib/engineyard/cli/ui.rb
require 'highline'
module EY
class CLI
class UI < Thor::Base.shell
class Tee
def initialize(*ios)
@ios = ios
end
def <<(str)
@ios.each { |io| io << str }
self
end
end
class Prompter
def self.add_answer(arg)
@answers ||= []
@answers << arg
end
def self.questions
@questions
end
def self.enable_mock!
@questions = []
@answers = []
@mock = true
end
def self.highline
@highline ||= HighLine.new($stdin)
end
def self.interactive?
@mock || ($stdout && $stdout.tty?)
end
def self.ask(question, password = false, default = nil)
if @mock
@questions ||= []
@questions << question
answer = @answers.shift
(answer == '' && default) ? default : answer
else
timeout_if_not_interactive do
highline.ask(question) do |q|
q.echo = "*" if password
q.default = default if default
end.to_s
end
end
end
def self.agree(question, default)
if @mock
@questions ||= []
@questions << question
answer = @answers.shift
answer == '' ? default : %w[y yes].include?(answer)
else
timeout_if_not_interactive do
answer = highline.agree(question) {|q| q.default = default ? 'Y/n' : 'N/y' }
case answer
when 'Y/n' then true
when 'N/y' then false
else answer
end
end
end
end
def self.timeout_if_not_interactive(&block)
if interactive?
block.call
else
Timeout.timeout(2, &block)
end
end
end
def error(name, message = nil)
$stdout = $stderr
say_with_status(name, message, :red)
ensure
$stdout = STDOUT
end
def warn(name, message = nil)
say_with_status(name, message, :yellow)
end
def info(message, color = nil)
return if quiet?
say_with_status(message, nil, color)
end
def debug(name, message = nil)
if ENV["DEBUG"]
name = name.inspect unless name.nil? or name.is_a?(String)
message = message.inspect unless message.nil? or message.is_a?(String)
say_with_status(name, message, :blue)
end
end
def say_with_status(name, message=nil, color=nil)
if message
say_status name, message, color
elsif name
say name, color
end
end
def interactive?
Prompter.interactive?
end
def agree(message, default)
Prompter.agree(message, default)
end
def ask(message, password = false, default = nil)
Prompter.ask(message, password, default)
rescue EOFError
return ''
end
def mute_if(bool, &block)
bool ? mute(&block) : yield
end
def server_tuples(servers, username=nil)
user = username && "#{username}@"
servers.map do |server|
host = "#{user}#{server.hostname}"
[host, server.amazon_id, server.role, server.name]
end
end
private :server_tuples
def print_hostnames(servers, username=nil)
server_tuples(servers, username).each do |server_tuple|
puts server_tuple.first
end
end
def print_simple_servers(servers, username=nil)
server_tuples(servers, username).each do |server_tuple|
puts server_tuple.join("\t")
end
end
def print_servers(servers, name, username=nil)
tuples = server_tuples(servers, username)
count = tuples.size
puts "# #{count} server#{count == 1 ? '' : 's'} on #{name}"
host_width = tuples.map {|s| s[0].length }.max
host_format = "%-#{host_width}s" # "%-10s" left align
role_width = tuples.map {|s| s[2].length }.max
role_format = "%-#{role_width}s" # "%-10s" left align
tuples.each do |server_tuple|
puts "#{host_format}\t%s\t#{role_format}\t%s" % server_tuple
end
end
def print_simple_envs(envs)
puts envs.map{|env| env.name }.uniq.sort
end
def print_envs(apps, default_env_name = nil)
apps.sort_by {|app| "#{app.account.name}/#{app.name}" }.each do |app|
puts "#{app.account.name}/#{app.name}"
if app.environments.any?
app.environments.sort_by {|env| env.name }.each do |env|
icount = env.instances_count
iname = case icount
when 0 then "(stopped)"
when 1 then "1 instance"
else "#{icount} instances"
end
name = env.name == default_env_name ? "#{env.name} (default)" : env.name
framework_env = env.framework_env && "[#{env.framework_env.center(12)}]"
puts " #{name.ljust(30)} #{framework_env} #{iname}"
end
else
puts " (No environments)"
end
puts ""
end
end
def deployment_status(deployment)
unless quiet?
say "# Status of last deployment of #{deployment.app_environment.hierarchy_name}:"
say "#"
show_deployment(deployment)
say "#"
end
deployment_result(deployment)
end
def show_deployment(dep)
return if quiet?
output = []
output << ["Account", dep.app.account.name]
output << ["Application", dep.app.name]
output << ["Environment", dep.environment.name]
output << ["Input Ref", dep.ref]
output << ["Resolved Ref", dep.resolved_ref]
output << ["Commit", dep.commit || '(not resolved)']
output << ["Migrate", dep.migrate]
output << ["Migrate command", dep.migrate_command] if dep.migrate
output << ["Deployed by", dep.deployed_by]
output << ["Started at", dep.created_at] if dep.created_at
output << ["Finished at", dep.finished_at] if dep.finished_at
output.each do |att, val|
puts "#\t%-16s %s" % ["#{att}:", val.to_s]
end
end
def deployment_result(dep)
if dep.successful?
say 'Deployment was successful.', :green
elsif dep.finished_at.nil?
say 'Deployment is not finished.', :yellow
else
say 'Deployment failed.', :red
end
end
def print_exception(e)
if e.message.empty? || (e.message == e.class.to_s)
message = nil
else
message = e.message
end
if ENV["DEBUG"]
error(e.class, message)
e.backtrace.each{|l| say(" "*3 + l) }
else
error(message || e.class.to_s)
end
end
def print_help(table)
print_table(table, ident: 2, truncate: true, colwidth: 20)
end
def set_color(string, color, bold=false)
($stdout.tty? || ENV['THOR_SHELL']) ? super : string
end
def err
$stderr
end
def out
$stdout
end
end
end
end