Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consoliate command formatting helper methods in CommandFormatter #22

Merged
merged 5 commits into from
Jun 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ Airbrussh is in a pre-1.0 state. This means that its APIs and behavior are subje

* Your contribution here!
* Added Rubocop enforcement to Travis
* Airbrussh now has decent test coverage, and is tested by Travis against a matrix of Ruby and SSHKit versions ([@robd](https://github.com/robd))
* Added Code Climate and Coveralls checks (see badges in the README)
* Airbrussh now has good test coverage, and is tested by Travis against a matrix of Ruby and SSHKit versions ([@robd](https://github.com/robd))
* Changes to support the new SSHKit formatter API, as introduced in [SSHKit #257](https://github.com/capistrano/sshkit/pull/257) ([@robd](https://github.com/robd))
* `Airbrussh.reset` has been removed
* Airbrussh now has its own ANSI color code; it no longer relies on a third-party gem (i.e. `colorize`)

## [0.4.1][] (2015-05-06)

Expand Down
14 changes: 7 additions & 7 deletions lib/airbrussh/capistrano.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "airbrussh"
require "colorize"
require "airbrussh/colors"
require "sshkit/formatter/airbrussh"

# airbrush/capistrano uses a different default configuration
Expand All @@ -10,12 +10,12 @@

# Sanity check!
unless defined?(Capistrano) && defined?(:namespace)
$stderr.puts\
"WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\
"to work.\n"\
"Require this gem within your application's Capfile, as described here:\n"\
"https://github.com/mattbrictson/airbrussh#installation"\
.colorize(:red)
$stderr.puts(
Airbrussh::Colors.red(
"WARNING: airbrussh/capistrano must be loaded by Capistrano in order "\
"to work.\nRequire this gem within your application's Capfile, as "\
"described here:\nhttps://github.com/mattbrictson/airbrussh#installation"
))
end

# Hook into Capistrano's init process to set the formatter
Expand Down
24 changes: 24 additions & 0 deletions lib/airbrussh/colors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Airbrussh
# Very basic support for ANSI color, so that we don't have to rely on
# any external dependencies.
module Colors
ANSI_CODES = {
:red => 31,
:green => 32,
:yellow => 33,
:blue => 34,
:gray => 90
}.freeze

module_function

# Define red, green, blue, etc. methods that return a copy of the
# String that is wrapped in the corresponding ANSI color escape
# sequence.
ANSI_CODES.each do |name, code|
define_method(name) do |string|
"\e[0;#{code};49m#{string}\e[0m"
end
end
end
end
77 changes: 77 additions & 0 deletions lib/airbrussh/command_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# encoding: UTF-8
require "airbrussh/colors"
# rubocop:disable Style/AsciiComments

module Airbrussh
# Decorates an SSHKit::Command to add string output helpers.
class CommandFormatter < SimpleDelegator
include Airbrussh::Colors

# Prefixes the line with the command number and removes the newline.
#
# format_output("hello\n") # => "01 hello"
#
def format_output(line)
"#{number} #{line.chomp}"
end

# Returns the abbreviated command (in yellow) with the number prefix.
#
# start_message # => "01 echo hello"
#
def start_message
"#{number} #{yellow(abbreviated)}"
end

# Returns a green (success) or red (failure) message depending on the
# exit status.
#
# exit_message # => "✔ 01 user@host 0.084s"
# exit_message # => "✘ 01 user@host 0.084s"
#
# If `log_file` is specified, it is appended to the message
# in the failure case.
#
# exit_message("out.log")
# # => "✘ 01 user@host (see out.log for details) 0.084s"
#
def exit_message(log_file=nil)
if failure?
message = red(failure_message(log_file))
else
message = green(success_message)
end
message << " #{gray(runtime)}"
end

private

def user_at_host
user_str = user { host.user }
host_str = host.to_s
[user_str, host_str].join("@")
end

def runtime
format("%5.3fs", super)
end

def abbreviated
to_s.sub(%r{^/usr/bin/env }, "")
end

def number
format("%02d", position + 1)
end

def success_message
"✔ #{number} #{user_at_host}"
end

def failure_message(log_file)
message = "✘ #{number} #{user_at_host}"
message << " (see #{log_file} for details)" if log_file
message
end
end
end
65 changes: 18 additions & 47 deletions lib/airbrussh/formatter.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# encoding: UTF-8
require "airbrussh/colors"
require "airbrussh/command_formatter"
require "airbrussh/command_output"
require "airbrussh/console"
require "airbrussh/rake/command"
require "airbrussh/rake/context"
require "colorize"
require "ostruct"
require "sshkit"

module Airbrussh
class Formatter < SSHKit::Formatter::Abstract
include Airbrussh::Colors
extend Forwardable

attr_reader :config, :context
def_delegator :context, :current_task_name

Expand All @@ -34,10 +35,6 @@ def create_log_file_formatter
)
end

def print_line(string)
@console.print_line(string)
end

def write_banner
return unless config.banner
if config.banner == :auto
Expand Down Expand Up @@ -115,17 +112,13 @@ def on_deploy_failure
def write_log_message(log_message)
return if debug?(log_message)
print_task_if_changed
@console.print_line(light_black(" " + log_message.to_s))
print_indented_line(gray(log_message.to_s))
end

def write_command_start(command)
return if debug?(command)
print_task_if_changed

if command.first_execution?
shell_string = shell_string(command)
print_line " #{command_number(command)} #{yellow(shell_string)}"
end
print_indented_line(command.start_message) if command.first_execution?
end

# Prints the data from the stdout and stderr streams of the given command,
Expand All @@ -143,7 +136,7 @@ def write_command_output(command)
def write_command_output_line(command, stream, line)
hide_command_output = !config.public_send("command_output_#{stream}?")
return if hide_command_output || debug?(command)
print_line " #{command_number(command)} #{line.chomp}"
print_indented_line(command.format_output(line))
end

def print_task_if_changed
Expand All @@ -156,32 +149,7 @@ def print_task_if_changed

def write_command_exit(command)
return if debug?(command)
print_line " #{format_exit_status(command)} #{runtime(command)}"
end

def format_exit_status(command)
user = command.user { command.host.user }
host = command.host.to_s
user_at_host = [user, host].join("@")
number = command_number(command)

if command.failure?
red("✘ #{number} #{user_at_host} (see #{@log_file} for details)")
else
green("✔ #{number} #{user_at_host}")
end
end

def runtime(command)
light_black(format("%5.3fs", command.runtime))
end

def shell_string(command)
command.to_s.sub(%r{^/usr/bin/env }, "")
end

def command_number(command)
format("%02d", command.position + 1)
print_indented_line(command.exit_message(@log_file), -2)
end

def clock
Expand All @@ -194,18 +162,21 @@ def clock
format("%02d:%02d", minutes, seconds)
end

%w(light_black red blue green yellow).each do |color|
define_method(color) do |string|
string.to_s.colorize(color.to_sym)
end
end

def debug?(obj)
obj.verbosity <= SSHKit::Logger::DEBUG
end

def decorate(command)
@context.decorate_command(command)
Airbrussh::CommandFormatter.new(@context.decorate_command(command))
end

def print_line(string)
@console.print_line(string)
end

def print_indented_line(string, offset=0)
indent = " " * (6 + offset)
print_line([indent, string].join)
end
end
end
26 changes: 26 additions & 0 deletions test/airbrussh/colors_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require "minitest_helper"
require "airbrussh/colors"

class Airbrussh::ColorsTest < Minitest::Test
include Airbrussh::Colors

def test_red
assert_equal("\e[0;31;49mhello\e[0m", red("hello"))
end

def test_green
assert_equal("\e[0;32;49mhello\e[0m", green("hello"))
end

def test_yellow
assert_equal("\e[0;33;49mhello\e[0m", yellow("hello"))
end

def test_blue
assert_equal("\e[0;34;49mhello\e[0m", blue("hello"))
end

def test_gray
assert_equal("\e[0;90;49mhello\e[0m", gray("hello"))
end
end
43 changes: 43 additions & 0 deletions test/airbrussh/command_formatter_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# encoding: UTF-8
require "minitest_helper"
require "ostruct"
require "airbrussh/command_formatter"

class Airbrussh::CommandFormatterTest < Minitest::Test
def setup
sshkit_command = OpenStruct.new(
:host => "12.34.56.78",
:user => "deployer",
:runtime => 1.23456,
:position => 0,
:failure? => false
)
def sshkit_command.to_s
"/usr/bin/env echo hello"
end
@command = Airbrussh::CommandFormatter.new(sshkit_command)
end

def test_format_output
assert_equal("01 hello", @command.format_output("hello\n"))
end

def test_start_message
assert_equal("01 \e[0;33;49mecho hello\e[0m", @command.start_message)
end

def test_exit_message_success
assert_equal(
"\e[0;32;49m✔ 01 [email protected]\e[0m \e[0;90;49m1.235s\e[0m",
@command.exit_message)
end

def test_exit_message_failure
@command.stub(:failure?, true) do
assert_equal(
"\e[0;31;49m✘ 01 [email protected] (see out.log for details)\e[0m "\
"\e[0;90;49m1.235s\e[0m",
@command.exit_message("out.log"))
end
end
end