sshkit 1.7.1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/BREAKING_API_WISHLIST.md +14 -0
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +43 -0
- data/EXAMPLES.md +265 -169
- data/Gemfile +7 -0
- data/README.md +274 -9
- data/RELEASING.md +16 -8
- data/Rakefile +8 -0
- data/lib/sshkit.rb +0 -9
- data/lib/sshkit/all.rb +6 -4
- data/lib/sshkit/backends/abstract.rb +42 -42
- data/lib/sshkit/backends/connection_pool.rb +57 -8
- data/lib/sshkit/backends/local.rb +21 -50
- data/lib/sshkit/backends/netssh.rb +45 -98
- data/lib/sshkit/backends/printer.rb +3 -23
- data/lib/sshkit/backends/skipper.rb +4 -8
- data/lib/sshkit/color.rb +51 -20
- data/lib/sshkit/command.rb +68 -47
- data/lib/sshkit/configuration.rb +38 -5
- data/lib/sshkit/deprecation_logger.rb +17 -0
- data/lib/sshkit/formatters/abstract.rb +28 -4
- data/lib/sshkit/formatters/black_hole.rb +1 -2
- data/lib/sshkit/formatters/dot.rb +3 -10
- data/lib/sshkit/formatters/pretty.rb +31 -56
- data/lib/sshkit/formatters/simple_text.rb +6 -44
- data/lib/sshkit/host.rb +5 -6
- data/lib/sshkit/logger.rb +0 -1
- data/lib/sshkit/mapping_interaction_handler.rb +47 -0
- data/lib/sshkit/runners/parallel.rb +1 -1
- data/lib/sshkit/runners/sequential.rb +1 -1
- data/lib/sshkit/version.rb +1 -1
- data/sshkit.gemspec +0 -1
- data/test/functional/backends/test_local.rb +14 -1
- data/test/functional/backends/test_netssh.rb +58 -50
- data/test/helper.rb +2 -2
- data/test/unit/backends/test_abstract.rb +145 -0
- data/test/unit/backends/test_connection_pool.rb +27 -2
- data/test/unit/backends/test_printer.rb +47 -47
- data/test/unit/formatters/test_custom.rb +65 -0
- data/test/unit/formatters/test_dot.rb +25 -32
- data/test/unit/formatters/test_pretty.rb +114 -22
- data/test/unit/formatters/test_simple_text.rb +83 -0
- data/test/unit/test_color.rb +69 -5
- data/test/unit/test_command.rb +53 -18
- data/test/unit/test_command_map.rb +0 -4
- data/test/unit/test_configuration.rb +47 -7
- data/test/unit/test_coordinator.rb +45 -52
- data/test/unit/test_deprecation_logger.rb +38 -0
- data/test/unit/test_host.rb +3 -4
- data/test/unit/test_logger.rb +0 -1
- data/test/unit/test_mapping_interaction_handler.rb +101 -0
- metadata +37 -41
- data/lib/sshkit/utils/capture_output_methods.rb +0 -13
- data/test/functional/test_coordinator.rb +0 -17
data/lib/sshkit/color.rb
CHANGED
@@ -1,27 +1,58 @@
|
|
1
|
-
|
1
|
+
module SSHKit
|
2
|
+
# Very basic support for ANSI color, so that we don't have to rely on
|
3
|
+
# any external dependencies. This class handles colorizing strings, and
|
4
|
+
# automatically disabling color if the underlying output is not a tty.
|
5
|
+
#
|
6
|
+
class Color
|
7
|
+
COLOR_CODES = {
|
8
|
+
:black => 30,
|
9
|
+
:red => 31,
|
10
|
+
:green => 32,
|
11
|
+
:yellow => 33,
|
12
|
+
:blue => 34,
|
13
|
+
:magenta => 35,
|
14
|
+
:cyan => 36,
|
15
|
+
:white => 37,
|
16
|
+
:light_black => 90,
|
17
|
+
:light_red => 91,
|
18
|
+
:light_green => 92,
|
19
|
+
:light_yellow => 93,
|
20
|
+
:light_blue => 94,
|
21
|
+
:light_magenta => 95,
|
22
|
+
:light_cyan => 96,
|
23
|
+
:light_white => 97
|
24
|
+
}.freeze
|
2
25
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def #{color}(string = '')
|
7
|
-
string = yield if block_given?
|
8
|
-
colorize? ? string.colorize(:color => :#{color}) : string
|
9
|
-
end
|
10
|
-
RUBY
|
11
|
-
end
|
26
|
+
def initialize(output, env=ENV)
|
27
|
+
@output, @env = output, env
|
28
|
+
end
|
12
29
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
30
|
+
# Converts the given obj to string and surrounds in the appropriate ANSI
|
31
|
+
# color escape sequence, based on the specified color and mode. The color
|
32
|
+
# must be a symbol (see COLOR_CODES for a complete list).
|
33
|
+
#
|
34
|
+
# If the underlying output does not support ANSI color (see `colorize?),
|
35
|
+
# the string will be not be colorized. Likewise if the specified color
|
36
|
+
# symbol is unrecognized, the string will not be colorized.
|
37
|
+
#
|
38
|
+
# Note that the only mode currently support is :bold. All other values
|
39
|
+
# will be silently ignored (i.e. treated the same as mode=nil).
|
40
|
+
#
|
41
|
+
def colorize(obj, color, mode=nil)
|
42
|
+
string = obj.to_s
|
43
|
+
return string unless colorize?
|
44
|
+
return string unless COLOR_CODES.key?(color)
|
45
|
+
|
46
|
+
result = mode == :bold ? "\e[1;" : "\e[0;"
|
47
|
+
result << COLOR_CODES.fetch(color).to_s
|
48
|
+
result << ";49m#{string}\e[0m"
|
49
|
+
end
|
21
50
|
|
22
|
-
|
51
|
+
# Returns `true` if the underlying output is a tty, or if the SSHKIT_COLOR
|
52
|
+
# environment variable is set.
|
53
|
+
#
|
23
54
|
def colorize?
|
24
|
-
|
55
|
+
@env['SSHKIT_COLOR'] || (@output.respond_to?(:tty?) && @output.tty?)
|
25
56
|
end
|
26
57
|
end
|
27
58
|
end
|
data/lib/sshkit/command.rb
CHANGED
@@ -4,38 +4,12 @@ require 'securerandom'
|
|
4
4
|
# @author Lee Hambley
|
5
5
|
module SSHKit
|
6
6
|
|
7
|
-
# @author Lee Hambley
|
8
|
-
module CommandHelper
|
9
|
-
|
10
|
-
def rake(tasks=[])
|
11
|
-
execute :rake, tasks
|
12
|
-
end
|
13
|
-
|
14
|
-
def make(tasks=[])
|
15
|
-
execute :make, tasks
|
16
|
-
end
|
17
|
-
|
18
|
-
def execute(command, args=[])
|
19
|
-
Command.new(command, args)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def map(command)
|
25
|
-
SSHKit.config.command_map[command.to_sym]
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
7
|
# @author Lee Hambley
|
31
8
|
class Command
|
32
9
|
|
33
10
|
Failed = Class.new(SSHKit::StandardError)
|
34
11
|
|
35
|
-
attr_reader :command, :args, :options, :started_at, :started, :exit_status
|
36
|
-
|
37
|
-
attr_accessor :stdout, :stderr
|
38
|
-
attr_accessor :full_stdout, :full_stderr
|
12
|
+
attr_reader :command, :args, :options, :started_at, :started, :exit_status, :full_stdout, :full_stderr
|
39
13
|
|
40
14
|
# Initialize a new Command object
|
41
15
|
#
|
@@ -45,14 +19,13 @@ module SSHKit
|
|
45
19
|
# nothing in stdin or stdout
|
46
20
|
#
|
47
21
|
def initialize(*args)
|
48
|
-
raise ArgumentError, "
|
22
|
+
raise ArgumentError, "Must pass arguments to Command.new" if args.empty?
|
49
23
|
@options = default_options.merge(args.extract_options!)
|
50
24
|
@command = args.shift.to_s.strip.to_sym
|
51
25
|
@args = args
|
52
26
|
@options.symbolize_keys!
|
53
27
|
sanitize_command!
|
54
|
-
@stdout, @stderr = String.new, String.new
|
55
|
-
@full_stdout, @full_stderr = String.new, String.new
|
28
|
+
@stdout, @stderr, @full_stdout, @full_stderr = String.new, String.new, String.new, String.new
|
56
29
|
end
|
57
30
|
|
58
31
|
def complete?
|
@@ -83,6 +56,38 @@ module SSHKit
|
|
83
56
|
end
|
84
57
|
alias :failed? :failure?
|
85
58
|
|
59
|
+
def stdout
|
60
|
+
log_reader_deprecation('stdout')
|
61
|
+
@stdout
|
62
|
+
end
|
63
|
+
|
64
|
+
def stdout=(new_value)
|
65
|
+
log_writer_deprecation('stdout')
|
66
|
+
@stdout = new_value
|
67
|
+
end
|
68
|
+
|
69
|
+
def stderr
|
70
|
+
log_reader_deprecation('stderr')
|
71
|
+
@stderr
|
72
|
+
end
|
73
|
+
|
74
|
+
def stderr=(new_value)
|
75
|
+
log_writer_deprecation('stderr')
|
76
|
+
@stderr = new_value
|
77
|
+
end
|
78
|
+
|
79
|
+
def on_stdout(channel, data)
|
80
|
+
@stdout = data
|
81
|
+
@full_stdout += data
|
82
|
+
call_interaction_handler(:stdout, data, channel)
|
83
|
+
end
|
84
|
+
|
85
|
+
def on_stderr(channel, data)
|
86
|
+
@stderr = data
|
87
|
+
@full_stderr += data
|
88
|
+
call_interaction_handler(:stderr, data, channel)
|
89
|
+
end
|
90
|
+
|
86
91
|
def exit_status=(new_exit_status)
|
87
92
|
@finished_at = Time.now
|
88
93
|
@exit_status = new_exit_status
|
@@ -125,7 +130,7 @@ module SSHKit
|
|
125
130
|
end
|
126
131
|
|
127
132
|
def verbosity
|
128
|
-
if vb = options[:verbosity]
|
133
|
+
if (vb = options[:verbosity])
|
129
134
|
case vb.class.name
|
130
135
|
when 'Symbol' then return Logger.const_get(vb.to_s.upcase)
|
131
136
|
when 'Fixnum' then return vb
|
@@ -136,12 +141,12 @@ module SSHKit
|
|
136
141
|
end
|
137
142
|
|
138
143
|
def should_map?
|
139
|
-
!command.match
|
144
|
+
!command.match(/\s/)
|
140
145
|
end
|
141
146
|
|
142
|
-
def within(&
|
147
|
+
def within(&_block)
|
143
148
|
return yield unless options[:in]
|
144
|
-
"cd #{options[:in]} && %s"
|
149
|
+
sprintf("cd #{options[:in]} && %s", yield)
|
145
150
|
end
|
146
151
|
|
147
152
|
def environment_hash
|
@@ -150,35 +155,33 @@ module SSHKit
|
|
150
155
|
|
151
156
|
def environment_string
|
152
157
|
environment_hash.collect do |key,value|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
"#{key.to_s}=#{value}"
|
157
|
-
end
|
158
|
+
key_string = key.is_a?(Symbol) ? key.to_s.upcase : key.to_s
|
159
|
+
escaped_value = value.to_s.gsub(/"/, '\"')
|
160
|
+
%{#{key_string}="#{escaped_value}"}
|
158
161
|
end.join(' ')
|
159
162
|
end
|
160
163
|
|
161
|
-
def with(&
|
164
|
+
def with(&_block)
|
162
165
|
return yield unless environment_hash.any?
|
163
|
-
"( #{environment_string} %s )"
|
166
|
+
sprintf("( export #{environment_string} ; %s )", yield)
|
164
167
|
end
|
165
168
|
|
166
|
-
def user(&
|
169
|
+
def user(&_block)
|
167
170
|
return yield unless options[:user]
|
168
171
|
"sudo -u #{options[:user]} #{environment_string + " " unless environment_string.empty?}-- sh -c '%s'" % %Q{#{yield}}
|
169
172
|
end
|
170
173
|
|
171
|
-
def in_background(&
|
174
|
+
def in_background(&_block)
|
172
175
|
return yield unless options[:run_in_background]
|
173
|
-
"( nohup %s > /dev/null & )"
|
176
|
+
sprintf("( nohup %s > /dev/null & )", yield)
|
174
177
|
end
|
175
178
|
|
176
|
-
def umask(&
|
179
|
+
def umask(&_block)
|
177
180
|
return yield unless SSHKit.config.umask
|
178
|
-
"umask #{SSHKit.config.umask} && %s"
|
181
|
+
sprintf("umask #{SSHKit.config.umask} && %s", yield)
|
179
182
|
end
|
180
183
|
|
181
|
-
def group(&
|
184
|
+
def group(&_block)
|
182
185
|
return yield unless options[:group]
|
183
186
|
"sg #{options[:group]} -c \\\"%s\\\"" % %Q{#{yield}}
|
184
187
|
# We could also use the so-called heredoc format perhaps:
|
@@ -227,6 +230,24 @@ module SSHKit
|
|
227
230
|
end
|
228
231
|
end
|
229
232
|
|
233
|
+
def call_interaction_handler(stream_name, data, channel)
|
234
|
+
interaction_handler = options[:interaction_handler]
|
235
|
+
interaction_handler = MappingInteractionHandler.new(interaction_handler) if interaction_handler.kind_of?(Hash)
|
236
|
+
interaction_handler.on_data(self, stream_name, data, channel) if interaction_handler.respond_to?(:on_data)
|
237
|
+
end
|
238
|
+
|
239
|
+
def log_reader_deprecation(stream)
|
240
|
+
SSHKit.config.deprecation_logger.log(
|
241
|
+
"The #{stream} method on Command is deprecated. " \
|
242
|
+
"The @#{stream} attribute will be removed in a future release. Use full_#{stream}() instead."
|
243
|
+
)
|
244
|
+
end
|
245
|
+
|
246
|
+
def log_writer_deprecation(stream)
|
247
|
+
SSHKit.config.deprecation_logger.log(
|
248
|
+
"The #{stream}= method on Command is deprecated. The @#{stream} attribute will be removed in a future release."
|
249
|
+
)
|
250
|
+
end
|
230
251
|
end
|
231
252
|
|
232
253
|
end
|
data/lib/sshkit/configuration.rb
CHANGED
@@ -6,7 +6,16 @@ module SSHKit
|
|
6
6
|
attr_writer :output, :backend, :default_env
|
7
7
|
|
8
8
|
def output
|
9
|
-
@output ||=
|
9
|
+
@output ||= use_format(:pretty)
|
10
|
+
end
|
11
|
+
|
12
|
+
def deprecation_logger
|
13
|
+
self.deprecation_output = $stderr if @deprecation_logger.nil?
|
14
|
+
@deprecation_logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def deprecation_output=(out)
|
18
|
+
@deprecation_logger = DeprecationLogger.new(out)
|
10
19
|
end
|
11
20
|
|
12
21
|
def default_env
|
@@ -25,8 +34,29 @@ module SSHKit
|
|
25
34
|
@output_verbosity = logger(verbosity)
|
26
35
|
end
|
27
36
|
|
37
|
+
# TODO: deprecate in favor of `use_format`
|
28
38
|
def format=(format)
|
29
|
-
|
39
|
+
use_format(format)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Tell SSHKit to use the specified `formatter` for stdout. The formatter
|
43
|
+
# can be the name of a built-in SSHKit formatter, like `:pretty`, a
|
44
|
+
# formatter class, like `SSHKit::Formatter::Pretty`, or a custom formatter
|
45
|
+
# class you've written yourself.
|
46
|
+
#
|
47
|
+
# Additional arguments will be passed to the formatter's constructor.
|
48
|
+
#
|
49
|
+
# Example:
|
50
|
+
#
|
51
|
+
# config.use_format(:pretty)
|
52
|
+
#
|
53
|
+
# Is equivalent to:
|
54
|
+
#
|
55
|
+
# config.output = SSHKit::Formatter::Pretty.new($stdout)
|
56
|
+
#
|
57
|
+
def use_format(formatter, *args)
|
58
|
+
klass = formatter.is_a?(Class) ? formatter : formatter_class(formatter)
|
59
|
+
self.output = klass.new($stdout, *args)
|
30
60
|
end
|
31
61
|
|
32
62
|
def command_map
|
@@ -43,10 +73,13 @@ module SSHKit
|
|
43
73
|
verbosity.is_a?(Integer) ? verbosity : Logger.const_get(verbosity.upcase)
|
44
74
|
end
|
45
75
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
76
|
+
def formatter_class(symbol)
|
77
|
+
name = symbol.to_s.downcase
|
78
|
+
found = SSHKit::Formatter.constants.find do |const|
|
79
|
+
const.to_s.downcase == name
|
49
80
|
end
|
81
|
+
fail NameError, 'Unrecognized SSHKit::Formatter "#{symbol}"' if found.nil?
|
82
|
+
SSHKit::Formatter.const_get(found)
|
50
83
|
end
|
51
84
|
|
52
85
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SSHKit
|
2
|
+
class DeprecationLogger
|
3
|
+
def initialize(out)
|
4
|
+
@out = out
|
5
|
+
@previous_warnings = Set.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def log(message)
|
9
|
+
return if @out.nil?
|
10
|
+
warning_msg = "[Deprecated] #{message}\n"
|
11
|
+
caller_line = caller.find { |line| !line.include?('lib/sshkit') }
|
12
|
+
warning_msg << " (Called from #{caller_line})\n" unless caller_line.nil?
|
13
|
+
@out << warning_msg unless @previous_warnings.include?(warning_msg)
|
14
|
+
@previous_warnings << warning_msg
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -9,15 +9,39 @@ module SSHKit
|
|
9
9
|
extend Forwardable
|
10
10
|
attr_reader :original_output
|
11
11
|
def_delegators :@original_output, :read, :rewind
|
12
|
+
def_delegators :@color, :colorize
|
12
13
|
|
13
|
-
def initialize(
|
14
|
-
@original_output =
|
14
|
+
def initialize(output)
|
15
|
+
@original_output = output
|
16
|
+
@color = SSHKit::Color.new(output)
|
15
17
|
end
|
16
18
|
|
17
|
-
|
19
|
+
%w(fatal error warn info debug).each do |level|
|
20
|
+
define_method(level) do |message|
|
21
|
+
write(LogMessage.new(Logger.const_get(level.upcase), message))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
alias :log :info
|
25
|
+
|
26
|
+
def log_command_start(command)
|
27
|
+
write(command)
|
28
|
+
end
|
29
|
+
|
30
|
+
def log_command_data(command, _stream_type, _stream_data)
|
31
|
+
write(command)
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_command_exit(command)
|
35
|
+
write(command)
|
36
|
+
end
|
37
|
+
|
38
|
+
def <<(obj)
|
39
|
+
write(obj)
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(_obj)
|
18
43
|
raise "Abstract formatter should not be used directly, maybe you want SSHKit::Formatter::BlackHole"
|
19
44
|
end
|
20
|
-
alias :<< :write
|
21
45
|
|
22
46
|
end
|
23
47
|
|
@@ -4,18 +4,11 @@ module SSHKit
|
|
4
4
|
|
5
5
|
class Dot < Abstract
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
if obj.finished?
|
10
|
-
original_output << (obj.failure? ? c.red('.') : c.green('.'))
|
11
|
-
end
|
7
|
+
def log_command_exit(command)
|
8
|
+
original_output << colorize('.', command.failure? ? :red : :green)
|
12
9
|
end
|
13
|
-
alias :<< :write
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
def c
|
18
|
-
@c ||= Color
|
11
|
+
def write(_obj)
|
19
12
|
end
|
20
13
|
|
21
14
|
end
|
@@ -4,77 +4,52 @@ module SSHKit
|
|
4
4
|
|
5
5
|
class Pretty < Abstract
|
6
6
|
|
7
|
+
LEVEL_NAMES = %w{ DEBUG INFO WARN ERROR FATAL }.freeze
|
8
|
+
LEVEL_COLORS = [:black, :blue, :yellow, :red, :red].freeze
|
9
|
+
|
7
10
|
def write(obj)
|
8
|
-
|
9
|
-
|
10
|
-
when SSHKit::Command then write_command(obj)
|
11
|
-
when SSHKit::LogMessage then write_log_message(obj)
|
11
|
+
if obj.kind_of?(SSHKit::LogMessage)
|
12
|
+
write_message(obj.verbosity, obj.to_s)
|
12
13
|
else
|
13
|
-
|
14
|
+
raise "write only supports formatting SSHKit::LogMessage, called with #{obj.class}: #{obj.inspect}"
|
14
15
|
end
|
15
16
|
end
|
16
|
-
alias :<< :write
|
17
|
-
|
18
|
-
private
|
19
17
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
original_output << "%6s %s\n" % [level(Logger::DEBUG),
|
26
|
-
uuid(command) + "Command: #{c.blue(command.to_command)}"]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
if SSHKit.config.output_verbosity == Logger::DEBUG
|
31
|
-
unless command.stdout.empty?
|
32
|
-
command.stdout.lines.each do |line|
|
33
|
-
original_output << "%6s %s" % [level(Logger::DEBUG),
|
34
|
-
uuid(command) + c.green("\t" + line)]
|
35
|
-
original_output << "\n" unless line[-1] == "\n"
|
36
|
-
end
|
37
|
-
command.stdout = ''
|
38
|
-
end
|
39
|
-
|
40
|
-
unless command.stderr.empty?
|
41
|
-
command.stderr.lines.each do |line|
|
42
|
-
original_output << "%6s %s" % [level(Logger::DEBUG),
|
43
|
-
uuid(command) + c.red("\t" + line)]
|
44
|
-
original_output << "\n" unless line[-1] == "\n"
|
45
|
-
end
|
46
|
-
command.stderr = ''
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
if command.finished?
|
51
|
-
original_output << "%6s %s\n" % [level(command.verbosity),
|
52
|
-
uuid(command) + "Finished in #{sprintf('%5.3f seconds', command.runtime)} with exit status #{command.exit_status} (#{c.bold { command.failure? ? c.red('failed') : c.green('successful') }})."]
|
53
|
-
end
|
18
|
+
def log_command_start(command)
|
19
|
+
host_prefix = command.host.user ? "as #{colorize(command.host.user, :blue)}@" : 'on '
|
20
|
+
message = "Running #{colorize(command, :yellow, :bold)} #{host_prefix}#{colorize(command.host, :blue)}"
|
21
|
+
write_message(command.verbosity, message, command.uuid)
|
22
|
+
write_message(Logger::DEBUG, "Command: #{colorize(command.to_command, :blue)}", command.uuid)
|
54
23
|
end
|
55
24
|
|
56
|
-
def
|
57
|
-
|
25
|
+
def log_command_data(command, stream_type, stream_data)
|
26
|
+
color = case stream_type
|
27
|
+
when :stdout then :green
|
28
|
+
when :stderr then :red
|
29
|
+
else raise "Unrecognised stream_type #{stream_type}, expected :stdout or :stderr"
|
30
|
+
end
|
31
|
+
write_message(Logger::DEBUG, colorize("\t#{stream_data}".chomp, color), command.uuid)
|
58
32
|
end
|
59
33
|
|
60
|
-
def
|
61
|
-
|
34
|
+
def log_command_exit(command)
|
35
|
+
runtime = sprintf('%5.3f seconds', command.runtime)
|
36
|
+
successful_or_failed = command.failure? ? colorize('failed', :red, :bold) : colorize('successful', :green, :bold)
|
37
|
+
message = "Finished in #{runtime} with exit status #{command.exit_status} (#{successful_or_failed})."
|
38
|
+
write_message(command.verbosity, message, command.uuid)
|
62
39
|
end
|
63
40
|
|
64
|
-
|
65
|
-
"[#{c.green(obj.uuid)}] "
|
66
|
-
end
|
41
|
+
protected
|
67
42
|
|
68
|
-
def
|
69
|
-
|
43
|
+
def format_message(verbosity, message, uuid=nil)
|
44
|
+
message = "[#{colorize(uuid, :green)}] #{message}" unless uuid.nil?
|
45
|
+
level = colorize(Pretty::LEVEL_NAMES[verbosity], Pretty::LEVEL_COLORS[verbosity])
|
46
|
+
'%6s %s' % [level, message]
|
70
47
|
end
|
71
48
|
|
72
|
-
|
73
|
-
%w{ black blue yellow red red }[level_num]
|
74
|
-
end
|
49
|
+
private
|
75
50
|
|
76
|
-
def
|
77
|
-
|
51
|
+
def write_message(verbosity, message, uuid=nil)
|
52
|
+
original_output << "#{format_message(verbosity, message, uuid)}\n" if verbosity >= SSHKit.config.output_verbosity
|
78
53
|
end
|
79
54
|
|
80
55
|
end
|