convoy 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.irbrc +3 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +705 -0
- data/Rakefile +1 -0
- data/convoy.gemspec +24 -0
- data/examples/.my_apprc +24 -0
- data/examples/basic +10 -0
- data/examples/basic_config_file +16 -0
- data/examples/basic_conflicts +17 -0
- data/examples/basic_depends_on +25 -0
- data/examples/basic_flags +15 -0
- data/examples/basic_options +14 -0
- data/examples/basic_options_multi +15 -0
- data/examples/basic_require_arguments +17 -0
- data/examples/basic_texts +21 -0
- data/examples/basic_validations +21 -0
- data/examples/basic_with_everything +30 -0
- data/examples/commands/example_command.rb +13 -0
- data/examples/suite_complex +65 -0
- data/examples/suite_simple +19 -0
- data/examples/suite_with_sub_commands +94 -0
- data/lib/convoy.rb +83 -0
- data/lib/convoy/action_command/base.rb +85 -0
- data/lib/convoy/action_command/escort_utility_command.rb +53 -0
- data/lib/convoy/app.rb +127 -0
- data/lib/convoy/arguments.rb +20 -0
- data/lib/convoy/auto_options.rb +71 -0
- data/lib/convoy/error/error.rb +33 -0
- data/lib/convoy/formatter/command.rb +87 -0
- data/lib/convoy/formatter/commands.rb +37 -0
- data/lib/convoy/formatter/cursor_position.rb +29 -0
- data/lib/convoy/formatter/default_help_formatter.rb +117 -0
- data/lib/convoy/formatter/global_command.rb +17 -0
- data/lib/convoy/formatter/option.rb +152 -0
- data/lib/convoy/formatter/options.rb +28 -0
- data/lib/convoy/formatter/shell_command_executor.rb +49 -0
- data/lib/convoy/formatter/stream_output_formatter.rb +88 -0
- data/lib/convoy/formatter/string_grid.rb +108 -0
- data/lib/convoy/formatter/string_splitter.rb +50 -0
- data/lib/convoy/formatter/terminal.rb +30 -0
- data/lib/convoy/global_pre_parser.rb +43 -0
- data/lib/convoy/logger.rb +75 -0
- data/lib/convoy/option_dependency_validator.rb +82 -0
- data/lib/convoy/option_parser.rb +155 -0
- data/lib/convoy/setup/configuration/generator.rb +75 -0
- data/lib/convoy/setup/configuration/instance.rb +34 -0
- data/lib/convoy/setup/configuration/loader.rb +43 -0
- data/lib/convoy/setup/configuration/locator/base.rb +19 -0
- data/lib/convoy/setup/configuration/locator/chaining.rb +29 -0
- data/lib/convoy/setup/configuration/locator/descending_to_home.rb +23 -0
- data/lib/convoy/setup/configuration/locator/executing_script_directory.rb +15 -0
- data/lib/convoy/setup/configuration/locator/specified_directory.rb +21 -0
- data/lib/convoy/setup/configuration/merge_tool.rb +38 -0
- data/lib/convoy/setup/configuration/reader.rb +36 -0
- data/lib/convoy/setup/configuration/writer.rb +46 -0
- data/lib/convoy/setup/dsl/action.rb +17 -0
- data/lib/convoy/setup/dsl/command.rb +67 -0
- data/lib/convoy/setup/dsl/config_file.rb +13 -0
- data/lib/convoy/setup/dsl/global.rb +29 -0
- data/lib/convoy/setup/dsl/options.rb +81 -0
- data/lib/convoy/setup_accessor.rb +206 -0
- data/lib/convoy/trollop.rb +861 -0
- data/lib/convoy/utils.rb +21 -0
- data/lib/convoy/validator.rb +45 -0
- data/spec/integration/basic_config_file_spec.rb +126 -0
- data/spec/integration/basic_conflicts_spec.rb +47 -0
- data/spec/integration/basic_depends_on_spec.rb +275 -0
- data/spec/integration/basic_options_spec.rb +41 -0
- data/spec/integration/basic_options_with_multi_spec.rb +30 -0
- data/spec/integration/basic_spec.rb +38 -0
- data/spec/integration/basic_validations_spec.rb +77 -0
- data/spec/integration/basic_with_arguments_spec.rb +35 -0
- data/spec/integration/basic_with_text_fields_spec.rb +21 -0
- data/spec/integration/suite_simple_spec.rb +45 -0
- data/spec/integration/suite_sub_command_spec.rb +51 -0
- data/spec/lib/convoy/action_command/base_spec.rb +200 -0
- data/spec/lib/convoy/formatter/command_spec.rb +238 -0
- data/spec/lib/convoy/formatter/global_command_spec.rb +50 -0
- data/spec/lib/convoy/formatter/option_spec.rb +300 -0
- data/spec/lib/convoy/formatter/shell_command_executor_spec.rb +59 -0
- data/spec/lib/convoy/formatter/stream_output_formatter_spec.rb +214 -0
- data/spec/lib/convoy/formatter/string_grid_spec.rb +59 -0
- data/spec/lib/convoy/formatter/string_splitter_spec.rb +50 -0
- data/spec/lib/convoy/formatter/terminal_spec.rb +19 -0
- data/spec/lib/convoy/setup/configuration/generator_spec.rb +101 -0
- data/spec/lib/convoy/setup/configuration/loader_spec.rb +79 -0
- data/spec/lib/convoy/setup/configuration/locator/chaining_spec.rb +81 -0
- data/spec/lib/convoy/setup/configuration/locator/descending_to_home_spec.rb +57 -0
- data/spec/lib/convoy/setup/configuration/locator/executing_script_directory_spec.rb +29 -0
- data/spec/lib/convoy/setup/configuration/locator/specified_directory_spec.rb +33 -0
- data/spec/lib/convoy/setup/configuration/merge_tool_spec.rb +41 -0
- data/spec/lib/convoy/setup/configuration/reader_spec.rb +41 -0
- data/spec/lib/convoy/setup/configuration/writer_spec.rb +75 -0
- data/spec/lib/convoy/setup_accessor_spec.rb +226 -0
- data/spec/lib/convoy/utils_spec.rb +30 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/integration_helpers.rb +2 -0
- data/spec/support/matchers/execute_action_for_command_matcher.rb +21 -0
- data/spec/support/matchers/execute_action_with_arguments_matcher.rb +25 -0
- data/spec/support/matchers/execute_action_with_options_matcher.rb +29 -0
- data/spec/support/matchers/exit_with_code_matcher.rb +29 -0
- data/spec/support/shared_contexts/integration_setup.rb +34 -0
- metadata +292 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Convoy
|
4
|
+
module Formatter
|
5
|
+
class ShellCommandExecutor
|
6
|
+
attr_reader :command
|
7
|
+
|
8
|
+
def initialize(command)
|
9
|
+
@command = command
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute_in_current_shell(success_callback = nil, error_callback = nil)
|
13
|
+
begin
|
14
|
+
result = `#{command}`
|
15
|
+
process_status = $?
|
16
|
+
raise Convoy::InternalError.new("Shell command exited with a non-zero (#{process_status.exitstatus}) exit code") if process_status.exitstatus != 0
|
17
|
+
success_callback.call(command, result) if success_callback
|
18
|
+
rescue => e
|
19
|
+
error_callback.call(command, e) if error_callback
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#def execute_in_new_shell(success_callback = nil, error_callback = nil)
|
25
|
+
#stdin, stdout, stderr = nil, nil, nil
|
26
|
+
#begin
|
27
|
+
#stdin, stdout, stderr, thread = ensure_successful_exit do
|
28
|
+
#Open3.popen3(command)
|
29
|
+
#end
|
30
|
+
#success_callback.call(command, stdin, stdout, stderr) if success_callback
|
31
|
+
#rescue => e
|
32
|
+
#error_callback.call(command, e) if error_callback
|
33
|
+
#nil
|
34
|
+
#ensure
|
35
|
+
#[stdin, stdout, stderr].each {|io| io.close if io}
|
36
|
+
#end
|
37
|
+
#end
|
38
|
+
|
39
|
+
#private
|
40
|
+
|
41
|
+
#def ensure_successful_exit(&block)
|
42
|
+
#stdin, stdout, stderr, thread = block.call
|
43
|
+
#process_status = thread.value
|
44
|
+
#raise Convoy::InternalError.new("Shell command exited with a non-zero (#{process_status.exitstatus}) exit code") if process_status.exitstatus != 0
|
45
|
+
#[stdin, stdout, stderr, thread]
|
46
|
+
#end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Convoy
|
2
|
+
module Formatter
|
3
|
+
class StreamOutputFormatter
|
4
|
+
DEFAULT_OUTPUT_WIDTH = 80
|
5
|
+
DEFAULT_INDENT_STRING = ' '
|
6
|
+
DEFAULT_INDENT = 0
|
7
|
+
|
8
|
+
attr_reader :stream, :indent_string, :current_indent, :max_output_width, :cursor_position
|
9
|
+
|
10
|
+
def initialize(stream = $stdout, options = {}, &block)
|
11
|
+
@stream = stream
|
12
|
+
@max_output_width = options[:max_output_width] || DEFAULT_OUTPUT_WIDTH
|
13
|
+
@indent_string = options[:indent_string] || DEFAULT_INDENT_STRING
|
14
|
+
@current_indent = options[:current_indent] || DEFAULT_INDENT
|
15
|
+
@cursor_position = CursorPosition.new(@max_output_width)
|
16
|
+
block.call(self) if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def print(string)
|
20
|
+
splitter_input = pad_string_to_account_for_cursor_position(string.to_s)
|
21
|
+
segments = StringSplitter.new(max_output_width).split(splitter_input)
|
22
|
+
segments = remove_padding_that_account_for_cursor_position(segments)
|
23
|
+
segments.each do |segment|
|
24
|
+
output_string = "#{current_indent_string}#{segment}"
|
25
|
+
output_string = segment unless cursor_position.newline?
|
26
|
+
stream.print output_string
|
27
|
+
cursor_position.update_for(segment)
|
28
|
+
newline if segments.last != segment
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def puts(string, options = {:newlines => 1})
|
33
|
+
print(string)
|
34
|
+
newline(options[:newlines])
|
35
|
+
end
|
36
|
+
|
37
|
+
def newline(newline_count = 1)
|
38
|
+
stream.print("\n" * newline_count)
|
39
|
+
cursor_position.reset if newline_count > 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def indent(count, &block)
|
43
|
+
newline unless cursor_position.newline?
|
44
|
+
new_indent = current_indent + count
|
45
|
+
self.class.new(stream, :max_output_width => max_output_width - count, :indent_string => indent_string, :current_indent => new_indent, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def grid(options = {}, &block)
|
49
|
+
if block_given?
|
50
|
+
options[:width] ||= max_output_width
|
51
|
+
grid = StringGrid.new(options, &block)
|
52
|
+
puts grid.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def pad_string_to_account_for_cursor_position(string)
|
59
|
+
"#{padding_string}#{string}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def remove_padding_that_account_for_cursor_position(segments)
|
63
|
+
first_string = segments.first
|
64
|
+
if first_string
|
65
|
+
segments[0] = first_string.sub(/#{padding_string}/, '')
|
66
|
+
end
|
67
|
+
segments
|
68
|
+
end
|
69
|
+
|
70
|
+
def padding_string
|
71
|
+
"." * cursor_position.position
|
72
|
+
end
|
73
|
+
|
74
|
+
def current_indent_width
|
75
|
+
current_indent_string.length
|
76
|
+
end
|
77
|
+
|
78
|
+
def current_indent_string
|
79
|
+
indent_string * current_indent
|
80
|
+
end
|
81
|
+
|
82
|
+
#def table(options = {}, &block)
|
83
|
+
#BorderlessTable.new(self, options).output(&block)
|
84
|
+
#newline(options[:newlines] || 1)
|
85
|
+
#end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Convoy
|
2
|
+
module Formatter
|
3
|
+
class StringGrid
|
4
|
+
DEFAULT_WIDTH = 80
|
5
|
+
|
6
|
+
attr_reader :column_count, :width
|
7
|
+
attr_accessor :rows
|
8
|
+
|
9
|
+
def initialize(options = {}, &block)
|
10
|
+
@width = options[:width] || DEFAULT_WIDTH
|
11
|
+
@column_count = options[:columns] || 3
|
12
|
+
@rows = []
|
13
|
+
block.call(self) if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def row(*column_values)
|
17
|
+
while column_values.size < @column_count
|
18
|
+
column_values << ''
|
19
|
+
end
|
20
|
+
rows << column_values.map(&:to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
buffer = []
|
25
|
+
rows.each do |cells|
|
26
|
+
virtual_row = normalize_virtual_row(virtual_row_for(cells))
|
27
|
+
physical_row_count_for(virtual_row).times do |physical_count|
|
28
|
+
physical_row = format_physical_row_values(physical_row_for(virtual_row, physical_count))
|
29
|
+
buffer << physical_row.join("").chomp
|
30
|
+
end
|
31
|
+
end
|
32
|
+
buffer.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def format_physical_row_values(physical_row)
|
38
|
+
physical_row.each_with_index.map do |value, index|
|
39
|
+
cell_value(value, index)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def physical_row_for(virtual_row, index)
|
44
|
+
virtual_row.map { |physical| physical[index] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def virtual_row_for(column_values)
|
48
|
+
virtual_row = []
|
49
|
+
column_values.each_with_index do |cell, index|
|
50
|
+
virtual_row << Convoy::Formatter::StringSplitter.new(column_width(index) - 1).split(cell)
|
51
|
+
end
|
52
|
+
normalize_virtual_row(virtual_row)
|
53
|
+
end
|
54
|
+
|
55
|
+
def normalize_virtual_row(virtual_row)
|
56
|
+
virtual_row.map do |physical|
|
57
|
+
while physical.size < physical_row_count_for(virtual_row)
|
58
|
+
physical << ""
|
59
|
+
end
|
60
|
+
physical
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def physical_row_count_for(virtual_row)
|
65
|
+
virtual_row.map { |physical| physical.size }.max
|
66
|
+
end
|
67
|
+
|
68
|
+
def column_width(column_index)
|
69
|
+
width = fair_column_width(column_index)
|
70
|
+
if column_index == column_count - 1
|
71
|
+
width = last_column_width
|
72
|
+
end
|
73
|
+
width
|
74
|
+
end
|
75
|
+
|
76
|
+
def fair_column_width(index)
|
77
|
+
width = values_in_column(index).map(&:length).max
|
78
|
+
width = width + 1
|
79
|
+
width > max_column_width ? max_column_width : width
|
80
|
+
end
|
81
|
+
|
82
|
+
def last_column_width
|
83
|
+
full_fair_column_width = max_column_width * column_count + max_column_width_remainder
|
84
|
+
all_but_last_fair_column_width = 0
|
85
|
+
(column_count - 1).times do |index|
|
86
|
+
all_but_last_fair_column_width += fair_column_width(index)
|
87
|
+
end
|
88
|
+
full_fair_column_width - all_but_last_fair_column_width
|
89
|
+
end
|
90
|
+
|
91
|
+
def values_in_column(column_index)
|
92
|
+
rows.map { |cells| cells[column_index] }
|
93
|
+
end
|
94
|
+
|
95
|
+
def max_column_width
|
96
|
+
width/column_count
|
97
|
+
end
|
98
|
+
|
99
|
+
def max_column_width_remainder
|
100
|
+
width%column_count
|
101
|
+
end
|
102
|
+
|
103
|
+
def cell_value(value, column_index)
|
104
|
+
sprintf("%-#{column_width(column_index)}s", value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Convoy
|
2
|
+
module Formatter
|
3
|
+
class StringSplitter
|
4
|
+
attr_reader :max_segment_width #, :first_segment_max_length
|
5
|
+
|
6
|
+
def initialize(max_segment_width, options = {})
|
7
|
+
@max_segment_width = max_segment_width
|
8
|
+
#@first_segment_max_length = options[:first_segment_max_length] || max_segment_width
|
9
|
+
end
|
10
|
+
|
11
|
+
def split(input_string)
|
12
|
+
input_strings = input_string.split("\n")
|
13
|
+
[split_strings(input_strings)].flatten
|
14
|
+
#first_string = strings.shift
|
15
|
+
#other_strings = strings
|
16
|
+
#result = [split_first_string(first_string) + split_strings(other_strings)].flatten
|
17
|
+
#result
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
#def split_first_string(string)
|
23
|
+
#if first_segment_max_length >= string.length
|
24
|
+
#split_string(string)
|
25
|
+
#else
|
26
|
+
#first = string.slice(0, first_segment_max_length)
|
27
|
+
#last = string.slice(first_segment_max_length..-1)
|
28
|
+
#split_strings([first, last])
|
29
|
+
#end
|
30
|
+
#end
|
31
|
+
|
32
|
+
def split_strings(strings)
|
33
|
+
strings.map { |s| split_string(s) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def split_string(string)
|
37
|
+
result = []
|
38
|
+
if string.length > max_segment_width
|
39
|
+
first_part = string.slice(0, max_segment_width)
|
40
|
+
second_part = string.slice(max_segment_width..-1)
|
41
|
+
result << first_part
|
42
|
+
result << split_string(second_part)
|
43
|
+
else
|
44
|
+
result << string
|
45
|
+
end
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Convoy
|
2
|
+
module Formatter
|
3
|
+
class Terminal
|
4
|
+
DEFAULT_WIDTH = 80
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def width
|
8
|
+
tput_width
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def tput_width
|
14
|
+
ShellCommandExecutor.new('/usr/bin/env tput cols').execute_in_current_shell(tput_cols_command_success_callback, tput_cols_command_error_callback) || DEFAULT_WIDTH
|
15
|
+
end
|
16
|
+
|
17
|
+
def tput_cols_command_success_callback
|
18
|
+
lambda { |command, result| result.to_i }
|
19
|
+
end
|
20
|
+
|
21
|
+
def tput_cols_command_error_callback
|
22
|
+
lambda do |command, e|
|
23
|
+
error_logger.debug { e }
|
24
|
+
error_logger.info { "Unable to find terminal width via '#{command}', using default of #{DEFAULT_WIDTH}" }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Convoy
|
2
|
+
class GlobalPreParser
|
3
|
+
attr_reader :setup
|
4
|
+
|
5
|
+
def initialize(setup)
|
6
|
+
@setup = setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse(cli_options)
|
10
|
+
AutoOptions.new(parse_global_options(cli_options))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def parse_global_options(cli_options, context = [])
|
16
|
+
stop_words = setup.command_names_for(context).map(&:to_s)
|
17
|
+
parser = init_parser(stop_words)
|
18
|
+
parser = add_setup_options_to(parser, context)
|
19
|
+
parser.version(setup.version) #set the version if it was provided
|
20
|
+
parser.help_formatter(Convoy::Formatter::DefaultHelpFormatter.new(setup, context))
|
21
|
+
parsed_options = parse_options_string(parser, cli_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def init_parser(stop_words)
|
25
|
+
Trollop::Parser.new.tap do |parser|
|
26
|
+
parser.stop_on(stop_words)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_setup_options_to(parser, context = [])
|
31
|
+
setup.options_for(context).each do |name, opts|
|
32
|
+
parser.opt name, opts[:desc] || "", opts
|
33
|
+
end
|
34
|
+
parser
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_options_string(parser, cli_options)
|
38
|
+
Trollop::with_standard_exception_handling(parser) do
|
39
|
+
parser.parse(cli_options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Convoy
|
4
|
+
class Logger
|
5
|
+
class << self
|
6
|
+
def close
|
7
|
+
error.close
|
8
|
+
output.close
|
9
|
+
end
|
10
|
+
|
11
|
+
def error
|
12
|
+
@error_logger ||= ::Logger.new($stderr).tap do |l|
|
13
|
+
#l.formatter = advanced_error_formatter
|
14
|
+
l.formatter = basic_error_formatter
|
15
|
+
l.sev_threshold = ::Logger::WARN
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def output
|
20
|
+
@output_logger ||= ::Logger.new($stdout).tap do |l|
|
21
|
+
l.formatter = output_formatter
|
22
|
+
l.sev_threshold = ::Logger::DEBUG
|
23
|
+
l.instance_eval do
|
24
|
+
def puts(message = nil, &block)
|
25
|
+
if block_given?
|
26
|
+
fatal(&block)
|
27
|
+
else
|
28
|
+
fatal(message || "")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_error_logger(auto_options)
|
36
|
+
error.formatter = send(:"#{auto_options.error_formatter}_error_formatter")
|
37
|
+
error.sev_threshold = ::Logger.const_get(auto_options.verbosity)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def basic_error_formatter
|
43
|
+
proc do |severity, datetime, progname, msg|
|
44
|
+
"#{msg2str(msg)}\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#"#{severity} [#{datetime.strftime("%d/%b/%Y %H:%M:%S")}] \"#{msg}\"\n"
|
49
|
+
def advanced_error_formatter
|
50
|
+
proc do |severity, datetime, progname, msg|
|
51
|
+
sprintf("%-8s #{msg2str(msg, 10)}\n", severity)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def output_formatter
|
56
|
+
proc do |severity, datetime, progname, msg|
|
57
|
+
"#{msg}\n"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def msg2str(msg, backtrace_indent = 0)
|
62
|
+
case msg
|
63
|
+
when ::String
|
64
|
+
msg
|
65
|
+
when ::Exception
|
66
|
+
"#{msg.message} (#{ msg.class })\n" <<
|
67
|
+
(msg.backtrace || []).map { |line| sprintf("%#{backtrace_indent}s#{line}", "") }.join("\n")
|
68
|
+
else
|
69
|
+
msg.inspect
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|