escort 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +8 -0
- data/README.md +365 -14
- data/TODO.md +157 -44
- data/escort.gemspec +1 -0
- data/examples/{1_1_basic.rb → attic/1_1_basic.rb} +0 -0
- data/examples/{1_2_basic_requires_arguments.rb → attic/1_2_basic_requires_arguments.rb} +0 -0
- data/examples/{2_2_command.rb → attic/2_2_command.rb} +0 -0
- data/examples/{2_2_command_requires_arguments.rb → attic/2_2_command_requires_arguments.rb} +0 -0
- data/examples/{2_3_nested_commands.rb → attic/2_3_nested_commands.rb} +0 -0
- data/examples/{3_validations.rb → attic/3_validations.rb} +0 -0
- data/examples/{4_1_config_file.rb → attic/4_1_config_file.rb} +0 -0
- data/examples/{argument_handling → attic/argument_handling}/basic.rb +0 -0
- data/examples/{argument_handling → attic/argument_handling}/basic_command.rb +0 -0
- data/examples/{argument_handling → attic/argument_handling}/no_arguments.rb +0 -0
- data/examples/{argument_handling → attic/argument_handling}/no_arguments_command.rb +0 -0
- data/examples/{command_aliases → attic/command_aliases}/app.rb +0 -0
- data/examples/{config_file → attic/config_file}/.apprc2 +0 -0
- data/examples/{config_file → attic/config_file}/app.rb +0 -0
- data/examples/{config_file → attic/config_file}/sub_commands.rb +0 -0
- data/examples/{default_command → attic/default_command}/app.rb +0 -0
- data/examples/{sub_commands → attic/sub_commands}/app.rb +0 -0
- data/examples/{validation_basic → attic/validation_basic}/app.rb +0 -0
- data/examples/basic +10 -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/command +19 -0
- data/examples/commands/example_command.rb +13 -0
- data/lib/escort/action_command/base.rb +4 -0
- data/lib/escort/app.rb +33 -11
- data/lib/escort/formatter/borderless_table.rb +4 -0
- data/lib/escort/formatter/command.rb +87 -0
- data/lib/escort/formatter/commands.rb +36 -0
- data/lib/escort/formatter/default_help_formatter.rb +68 -73
- data/lib/escort/formatter/global_command.rb +17 -0
- data/lib/escort/formatter/option.rb +138 -0
- data/lib/escort/formatter/options.rb +17 -3
- data/lib/escort/formatter/shell_command_executor.rb +49 -0
- data/lib/escort/formatter/terminal.rb +17 -9
- data/lib/escort/formatter/terminal_formatter.rb +6 -0
- data/lib/escort/logger.rb +4 -4
- data/lib/escort/option_dependency_validator.rb +83 -0
- data/lib/escort/option_parser.rb +11 -1
- data/lib/escort/setup/configuration/reader.rb +0 -2
- data/lib/escort/setup/configuration/writer.rb +0 -2
- data/lib/escort/setup/dsl/command.rb +2 -7
- data/lib/escort/setup/dsl/global.rb +2 -9
- data/lib/escort/setup/dsl/options.rb +56 -0
- data/lib/escort/setup_accessor.rb +23 -6
- data/lib/escort/trollop.rb +4 -3
- data/lib/escort/validator.rb +4 -1
- data/lib/escort/version.rb +1 -1
- data/lib/escort.rb +8 -1
- 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 +9 -21
- data/spec/integration/basic_options_with_multi_spec.rb +30 -0
- data/spec/integration/basic_spec.rb +5 -6
- data/spec/integration/basic_validations_spec.rb +77 -0
- data/spec/integration/basic_with_arguments_spec.rb +33 -0
- data/spec/integration/basic_with_text_fields_spec.rb +21 -0
- data/spec/lib/escort/formatter/command_spec.rb +238 -0
- data/spec/lib/escort/formatter/global_command_spec.rb +50 -0
- data/spec/lib/escort/formatter/option_spec.rb +300 -0
- data/spec/lib/escort/formatter/shell_command_executor_spec.rb +59 -0
- data/spec/lib/escort/formatter/string_splitter_spec.rb +12 -0
- data/spec/lib/escort/formatter/terminal_spec.rb +19 -0
- data/spec/lib/escort/setup_accessor_spec.rb +1 -0
- data/spec/spec_helper.rb +9 -3
- data/spec/support/integration_helpers.rb +2 -0
- data/spec/{helpers/execute_action_matcher.rb → support/matchers/execute_action_for_command_matcher.rb} +3 -3
- 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 +86 -28
- data/examples/basic/app.rb +0 -16
- data/lib/escort/formatter/common.rb +0 -58
- data/spec/helpers/exit_with_code_matcher.rb +0 -21
- data/spec/helpers/give_option_to_action_with_value_matcher.rb +0 -22
@@ -0,0 +1,87 @@
|
|
1
|
+
module Escort
|
2
|
+
module Formatter
|
3
|
+
class Command
|
4
|
+
attr_reader :setup, :context, :name
|
5
|
+
|
6
|
+
def initialize(command_name, setup, context)
|
7
|
+
@setup = setup
|
8
|
+
@context = context
|
9
|
+
@name = command_name.to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
def name_with_aliases
|
13
|
+
[name, aliases].flatten.join(", ")
|
14
|
+
end
|
15
|
+
|
16
|
+
def outline
|
17
|
+
summary.empty? ? description : summary
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
@description ||= setup.command_description_for(name, context) || ""
|
22
|
+
end
|
23
|
+
|
24
|
+
def summary
|
25
|
+
@summary ||= setup.command_summary_for(name, context) || ""
|
26
|
+
end
|
27
|
+
|
28
|
+
def aliases
|
29
|
+
@aliases ||= setup.command_aliases_for(name, context)
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_aliases?
|
33
|
+
aliases && aliases.size > 0 ? true : false
|
34
|
+
end
|
35
|
+
|
36
|
+
def script_name
|
37
|
+
[canonical_script_name, context].flatten.join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
def child_commands
|
41
|
+
@child_commands ||= setup.canonical_command_names_for(context) || []
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_child_commands?
|
45
|
+
child_commands.length > 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def requires_arguments?
|
49
|
+
@requires_arguments ||= setup.arguments_required_for(context)
|
50
|
+
end
|
51
|
+
|
52
|
+
def usage
|
53
|
+
[script_name_usage_string, parent_commands_usage_string, child_command_usage_string, arguments_usage_string].flatten.reject(&:empty?).join(" ")
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def script_name_usage_string
|
59
|
+
"#{canonical_script_name} [options]"
|
60
|
+
end
|
61
|
+
|
62
|
+
def parent_commands_usage_string
|
63
|
+
context.map{|command_name| command_with_options(command_name)}.join(" ")
|
64
|
+
end
|
65
|
+
|
66
|
+
def child_command_usage_string
|
67
|
+
has_child_commands? ? "command [command_options]" : ""
|
68
|
+
end
|
69
|
+
|
70
|
+
def arguments_usage_string
|
71
|
+
requires_arguments? ? "arguments" : "[arguments]"
|
72
|
+
end
|
73
|
+
|
74
|
+
def command_with_options(command_name)
|
75
|
+
"#{command_name} [#{command_name}_options]"
|
76
|
+
end
|
77
|
+
|
78
|
+
def canonical_script_name
|
79
|
+
File.basename($0)
|
80
|
+
end
|
81
|
+
|
82
|
+
def alias_string
|
83
|
+
@alias_string ||= aliases.join(", ") if has_aliases?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Escort
|
2
|
+
module Formatter
|
3
|
+
class Commands
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def command_for(setup, context)
|
8
|
+
if context.empty?
|
9
|
+
GlobalCommand.new(setup)
|
10
|
+
else
|
11
|
+
Command.new(context.last, setup, context)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :setup, :context
|
17
|
+
|
18
|
+
def initialize(setup, context)
|
19
|
+
@setup = setup
|
20
|
+
@context = context
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
setup.canonical_command_names_for(context).each do |command_name|
|
25
|
+
command = Command.new(command_name, setup, context)
|
26
|
+
block.call(command)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def count
|
31
|
+
setup.canonical_command_names_for(context).size
|
32
|
+
end
|
33
|
+
alias_method :size, :count
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Escort
|
2
2
|
module Formatter
|
3
3
|
class DefaultHelpFormatter
|
4
|
-
include Escort::Formatter::Common
|
5
|
-
|
6
4
|
attr_reader :setup, :context
|
7
5
|
|
8
6
|
def initialize(setup, context)
|
@@ -11,95 +9,92 @@ module Escort
|
|
11
9
|
end
|
12
10
|
|
13
11
|
def print(parser)
|
14
|
-
|
15
|
-
|
12
|
+
options = Options.new(parser, setup, context)
|
13
|
+
commands = Commands.new(setup, context)
|
14
|
+
current_command = Commands.command_for(setup, context)
|
16
15
|
|
17
16
|
TerminalFormatter.display($stdout, Terminal.width) do |d|
|
18
|
-
d
|
19
|
-
d
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
d.put(setup.description_for(context), :newlines => 2) if setup.description_for(context)
|
24
|
-
end
|
25
|
-
d.puts "USAGE"
|
26
|
-
d.indent(4) do
|
27
|
-
context_usage_part = context.map { |command_name| "#{command_name} [#{command_name} options]" }.join(" ")
|
28
|
-
context_usage_part ||= ""
|
29
|
-
nested_command_part = "command [command options]" if !setup.canonical_command_names_for(context).nil? && setup.canonical_command_names_for(context).length > 0
|
30
|
-
nested_command_part ||= ""
|
31
|
-
usage_string = "#{script_name} [options] #{context_usage_part} #{nested_command_part} [arguments...]".gsub(/\s+/, ' ')
|
32
|
-
d.put usage_string, :newlines => 2
|
33
|
-
end
|
34
|
-
if setup.version
|
35
|
-
d.puts "VERSION"
|
36
|
-
d.indent(4) {
|
37
|
-
d.put setup.version, :newlines => 2
|
38
|
-
}
|
39
|
-
end
|
40
|
-
if option_strings.keys.size > 0
|
41
|
-
d.puts "OPTIONS"
|
42
|
-
d.indent(4) {
|
43
|
-
d.table(:columns => 3, :newlines => 1) do |t|
|
44
|
-
option_strings.each_pair do |key, value|
|
45
|
-
t.row value[:string], '-', value[:desc] || ''
|
46
|
-
end
|
47
|
-
end
|
48
|
-
}
|
49
|
-
end
|
50
|
-
if command_strings.keys.size > 0
|
51
|
-
d.puts "COMMANDS"
|
52
|
-
d.indent(4) {
|
53
|
-
d.table(:columns => 3, :newlines => 1) do |t|
|
54
|
-
command_strings.each_pair do |command_name, values_array|
|
55
|
-
t.row values_array[0], '-', command_outline(values_array)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
}
|
59
|
-
end
|
17
|
+
name_help(current_command, d)
|
18
|
+
usage_help(current_command, d)
|
19
|
+
version_help(current_command, d)
|
20
|
+
options_help(options, d)
|
21
|
+
commands_help(commands, d)
|
60
22
|
end
|
61
23
|
end
|
62
24
|
|
63
|
-
|
64
25
|
private
|
65
26
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
27
|
+
def name_help(current_command, d)
|
28
|
+
d.puts "NAME"
|
29
|
+
d.indent(4) do
|
30
|
+
d.table(:columns => 3, :newlines => 1) do |t|
|
31
|
+
t.row current_command.script_name, '-', current_command.summary
|
32
|
+
end
|
33
|
+
d.put(setup.description_for(context), :newlines => 2) if setup.description_for(context)
|
34
|
+
end
|
71
35
|
end
|
72
36
|
|
73
|
-
def
|
74
|
-
|
37
|
+
def usage_help(current_command, d)
|
38
|
+
d.puts "USAGE"
|
39
|
+
d.indent(4) do
|
40
|
+
d.put current_command.usage, :newlines => 2
|
41
|
+
end
|
75
42
|
end
|
76
43
|
|
77
|
-
def current_command
|
78
|
-
|
44
|
+
def version_help(current_command, d)
|
45
|
+
if setup.version
|
46
|
+
d.puts "VERSION"
|
47
|
+
d.indent(4) {
|
48
|
+
d.put setup.version, :newlines => 2
|
49
|
+
}
|
50
|
+
end
|
79
51
|
end
|
80
52
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
53
|
+
def options_help(options, d)
|
54
|
+
if options.count > 0
|
55
|
+
d.puts "OPTIONS"
|
56
|
+
d.indent(4) {
|
57
|
+
d.table(:columns => 3, :newlines => 1) do |t|
|
58
|
+
options.each do |option|
|
59
|
+
t.row option.usage, '-', option.description
|
60
|
+
option_conflicts_help(option, t)
|
61
|
+
option_dependencies_help(option, t)
|
62
|
+
option_validations_help(option, t)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def option_conflicts_help(option, t)
|
70
|
+
if option.has_conflicts?
|
71
|
+
t.row '', '', "- #{option.conflicts}"
|
72
|
+
end
|
85
73
|
end
|
86
74
|
|
87
|
-
def
|
88
|
-
|
75
|
+
def option_dependencies_help(option, t)
|
76
|
+
if option.has_dependencies?
|
77
|
+
t.row '', '', "- #{option.dependencies}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def option_validations_help(option, t)
|
82
|
+
if option.has_validations?
|
83
|
+
t.row '', '', "- #{option.validations}"
|
84
|
+
end
|
89
85
|
end
|
90
86
|
|
91
|
-
def
|
92
|
-
commands
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
87
|
+
def commands_help(commands, d)
|
88
|
+
if commands.count > 0
|
89
|
+
d.puts "COMMANDS"
|
90
|
+
d.indent(4) {
|
91
|
+
d.table(:columns => 3, :newlines => 1) do |t|
|
92
|
+
commands.each do |command|
|
93
|
+
t.row command.name_with_aliases, '-', command.outline
|
94
|
+
end
|
95
|
+
end
|
96
|
+
}
|
101
97
|
end
|
102
|
-
commands
|
103
98
|
end
|
104
99
|
end
|
105
100
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Escort
|
2
|
+
module Formatter
|
3
|
+
class GlobalCommand < Command
|
4
|
+
def initialize(setup)
|
5
|
+
super(:global, setup, [])
|
6
|
+
end
|
7
|
+
|
8
|
+
def summary
|
9
|
+
@summary ||= setup.summary_for(context) || ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
@description ||= setup.description_for(context) || ""
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Escort
|
2
|
+
module Formatter
|
3
|
+
class Option
|
4
|
+
attr_reader :name, :details, :setup, :context
|
5
|
+
|
6
|
+
def initialize(name, details, setup, context)
|
7
|
+
@name = name.to_sym
|
8
|
+
@details = details
|
9
|
+
@setup = setup
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
def usage
|
14
|
+
[long_string, short_string, type_string].select{|item| !item.empty?}.join(" ")
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
[base_description_string, description_default_string].select{|item| !item.empty?}.join(" ")
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_conflicts?
|
22
|
+
!conflicts_list.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def conflicts
|
26
|
+
has_conflicts? ? "conflicts with: #{conflicts_list.map{|option| "--#{option}"}.join(', ')}" : ''
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_dependencies?
|
30
|
+
!dependencies_list.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def dependencies
|
34
|
+
has_dependencies? ? "depends on: #{format_dependency_list(dependencies_list).join(', ')}" : ''
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_validations?
|
38
|
+
!validations_list.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def validations
|
42
|
+
has_validations? ? "#{validation_messages.join("\n- ")}" : ''
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def validation_messages
|
47
|
+
validations_list.map{|validation| validation[:desc]}
|
48
|
+
end
|
49
|
+
|
50
|
+
def validations_list
|
51
|
+
setup.validations_for(context)[name] || []
|
52
|
+
end
|
53
|
+
|
54
|
+
def format_dependency_list(dependency_list)
|
55
|
+
dependencies_list.map do |option|
|
56
|
+
case option
|
57
|
+
when Hash
|
58
|
+
option.inject([]){|acc, (key, value)| acc << "--#{key}=#{value}"}.join(', ')
|
59
|
+
else
|
60
|
+
"--#{option}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def dependencies_list
|
66
|
+
setup.dependencies_for(context)[name] || []
|
67
|
+
end
|
68
|
+
|
69
|
+
def conflicts_list
|
70
|
+
setup.conflicting_options_for(context)[name] || []
|
71
|
+
end
|
72
|
+
|
73
|
+
def base_description_string
|
74
|
+
details[:desc] || details[:description] || ''
|
75
|
+
end
|
76
|
+
|
77
|
+
def description_default_string
|
78
|
+
if details[:default]
|
79
|
+
base_description_string =~ /\.$/ ? "(Default: #{default_string})" : "(default: #{default_string})"
|
80
|
+
else
|
81
|
+
""
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def default_string
|
86
|
+
case details[:default]
|
87
|
+
when $stdout; "<stdout>"
|
88
|
+
when $stdin; "<stdin>"
|
89
|
+
when $stderr; "<stderr>"
|
90
|
+
when Array
|
91
|
+
details[:default].join(", ")
|
92
|
+
else
|
93
|
+
details[:default].to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def short_string
|
98
|
+
details[:short] && details[:short] != :none ? "-#{details[:short]}" : ""
|
99
|
+
end
|
100
|
+
|
101
|
+
def long_string
|
102
|
+
if flag_with_default_true?
|
103
|
+
"#{base_long_string}, --no-#{details[:long]}"
|
104
|
+
else
|
105
|
+
base_long_string
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def base_long_string
|
110
|
+
"--#{details[:long]}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def type_string
|
114
|
+
case details[:type]
|
115
|
+
when :flag; ""
|
116
|
+
when :int; "<i>"
|
117
|
+
when :ints; "<i+>"
|
118
|
+
when :string; "<s>"
|
119
|
+
when :strings; "<s+>"
|
120
|
+
when :float; "<f>"
|
121
|
+
when :floats; "<f+>"
|
122
|
+
when :io; "<filename/uri>"
|
123
|
+
when :ios; "<filename/uri+>"
|
124
|
+
when :date; "<date>"
|
125
|
+
when :dates; "<date+>"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def flag_with_default_true?
|
130
|
+
flag? && details[:default]
|
131
|
+
end
|
132
|
+
|
133
|
+
def flag?
|
134
|
+
details[:type] == :flag
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -1,13 +1,27 @@
|
|
1
1
|
module Escort
|
2
2
|
module Formatter
|
3
3
|
class Options
|
4
|
-
|
4
|
+
include Enumerable
|
5
5
|
|
6
|
-
|
6
|
+
attr_reader :parser, :setup, :context
|
7
|
+
|
8
|
+
def initialize(parser, setup, context)
|
9
|
+
@parser = parser
|
7
10
|
@setup = setup
|
8
11
|
@context = context
|
9
|
-
@parser = parser
|
10
12
|
end
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
parser.specs.each do |option_name, details|
|
16
|
+
option = Option.new(option_name, details, setup, context)
|
17
|
+
block.call(option)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def count
|
22
|
+
parser.specs.keys.size
|
23
|
+
end
|
24
|
+
alias_method :size, :count
|
11
25
|
end
|
12
26
|
end
|
13
27
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Escort
|
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 Escort::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 Escort::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
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'curses'
|
2
|
-
|
3
1
|
module Escort
|
4
2
|
module Formatter
|
5
3
|
class Terminal
|
@@ -7,14 +5,24 @@ module Escort
|
|
7
5
|
|
8
6
|
class << self
|
9
7
|
def width
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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}"}
|
16
25
|
end
|
17
|
-
screen_size
|
18
26
|
end
|
19
27
|
end
|
20
28
|
end
|
@@ -1,3 +1,9 @@
|
|
1
|
+
#TODO rename to StreamOutputFormatter
|
2
|
+
#get rid of the display method, it doesn't really add anything
|
3
|
+
#the max_width should be max_line_width not terminal_columns, there should be no default max_width
|
4
|
+
#indent_count should be indent_width
|
5
|
+
#probably don't really need indent_char, we can assume it is a space
|
6
|
+
#this will only work well with ASCII chars only!!!
|
1
7
|
module Escort
|
2
8
|
module Formatter
|
3
9
|
class TerminalFormatter
|
data/lib/escort/logger.rb
CHANGED
@@ -41,20 +41,20 @@ module Escort
|
|
41
41
|
|
42
42
|
def basic_error_formatter
|
43
43
|
proc do |severity, datetime, progname, msg|
|
44
|
-
"
|
44
|
+
"#{msg2str(msg)}\n"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
#"#{severity} [#{datetime.strftime("%d/%b/%Y %H:%M:%S")}] \"#{msg}\"\n"
|
49
49
|
def advanced_error_formatter
|
50
50
|
proc do |severity, datetime, progname, msg|
|
51
|
-
sprintf("%-8s
|
51
|
+
sprintf("%-8s #{msg2str(msg, 10)}\n", severity)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
def output_formatter
|
56
56
|
proc do |severity, datetime, progname, msg|
|
57
|
-
"
|
57
|
+
"#{msg}\n"
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -64,7 +64,7 @@ module Escort
|
|
64
64
|
msg
|
65
65
|
when ::Exception
|
66
66
|
"#{msg.message} (#{ msg.class })\n" <<
|
67
|
-
(msg.backtrace || []).map{|line| sprintf("%#{backtrace_indent}s#{line}", "
|
67
|
+
(msg.backtrace || []).map{|line| sprintf("%#{backtrace_indent}s#{line}", "")}.join("\n")
|
68
68
|
else
|
69
69
|
msg.inspect
|
70
70
|
end
|