commander-openflighthpc 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +45 -138
- data/commander-openflighthpc.gemspec +2 -1
- data/lib/commander.rb +3 -4
- data/lib/commander/cli.rb +15 -76
- data/lib/commander/command.rb +81 -176
- data/lib/commander/error_handler.rb +62 -0
- data/lib/commander/help_formatters.rb +0 -4
- data/lib/commander/help_formatters/terminal.rb +0 -5
- data/lib/commander/help_formatters/terminal/command_help.erb +14 -6
- data/lib/commander/help_formatters/terminal/help.erb +12 -4
- data/lib/commander/runner.rb +92 -130
- data/lib/commander/version.rb +1 -1
- metadata +21 -46
- data/bin/commander +0 -104
- data/lib/commander/blank.rb +0 -7
- data/lib/commander/core_ext.rb +0 -2
- data/lib/commander/core_ext/array.rb +0 -24
- data/lib/commander/core_ext/object.rb +0 -8
- data/lib/commander/help_formatters/terminal/subcommand_help.erb +0 -23
- data/lib/commander/help_formatters/terminal_compact.rb +0 -11
- data/lib/commander/help_formatters/terminal_compact/command_help.erb +0 -26
- data/lib/commander/help_formatters/terminal_compact/help.erb +0 -29
- data/lib/commander/help_formatters/terminal_compact/subcommand_help.erb +0 -15
- data/lib/commander/import.rb +0 -5
- data/lib/commander/patches/decimal-integer.rb +0 -17
- data/lib/commander/patches/help_formatter_binding.rb +0 -15
- data/lib/commander/patches/implicit-short-tags.rb +0 -75
- data/lib/commander/patches/priority_sort.rb +0 -21
- data/lib/commander/patches/validate_inputs.rb +0 -79
- data/lib/commander/platform.rb +0 -7
- data/spec/command_spec.rb +0 -157
- data/spec/configure_spec.rb +0 -37
- data/spec/core_ext/array_spec.rb +0 -18
- data/spec/core_ext/object_spec.rb +0 -19
- data/spec/help_formatters/terminal_compact_spec.rb +0 -69
- data/spec/help_formatters/terminal_spec.rb +0 -67
- data/spec/methods_spec.rb +0 -61
- data/spec/patches/validate_inputs_spec.rb +0 -84
- data/spec/runner_spec.rb +0 -672
- data/spec/spec_helper.rb +0 -79
- data/spec/ui_spec.rb +0 -30
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'paint'
|
2
|
+
|
3
|
+
module Commander
|
4
|
+
##
|
5
|
+
# Internal error class to delay rendering help text
|
6
|
+
# This is required as the help command points directly to stdout
|
7
|
+
# In general this has a bit of a code smell to it, and should
|
8
|
+
# not be used publicly
|
9
|
+
class InternalCallableError < StandardError
|
10
|
+
attr_accessor :callable
|
11
|
+
|
12
|
+
def initialize(msg = nil, &block)
|
13
|
+
super(msg)
|
14
|
+
self.callable = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
callable.call if callable
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
ErrorHandler = Struct.new(:program_name, :trace) do
|
23
|
+
def parse_trace(*raw_args)
|
24
|
+
# Do not modify the original array
|
25
|
+
args = raw_args.dup
|
26
|
+
|
27
|
+
# Determines if there is a --trace flag before a --
|
28
|
+
trace_index = args.index do |a|
|
29
|
+
if a == '--trace'
|
30
|
+
self.trace = true
|
31
|
+
elsif a == '--'
|
32
|
+
break
|
33
|
+
else
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Removes the --trace flag if required
|
39
|
+
args.tap { |a| a.delete_at(trace_index) if trace_index }
|
40
|
+
end
|
41
|
+
|
42
|
+
def start
|
43
|
+
yield(self) if block_given?
|
44
|
+
rescue => e
|
45
|
+
$stderr.puts e.full_message if trace
|
46
|
+
|
47
|
+
error_msg = "#{Paint[program_name, '#2794d8']}: #{Paint[e.to_s, :red, :bright]}"
|
48
|
+
exit_code = e.respond_to?(:exit_code) ? e.exit_code.to_i : 1
|
49
|
+
case e
|
50
|
+
when InternalCallableError
|
51
|
+
# See: https://shapeshed.com/unix-exit-codes/
|
52
|
+
exit_code = 126
|
53
|
+
$stderr.puts error_msg
|
54
|
+
e.call
|
55
|
+
else
|
56
|
+
$stderr.puts error_msg
|
57
|
+
end
|
58
|
+
exit(exit_code)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -2,16 +2,12 @@ module Commander
|
|
2
2
|
module HelpFormatter
|
3
3
|
autoload :Base, 'commander/help_formatters/base'
|
4
4
|
autoload :Terminal, 'commander/help_formatters/terminal'
|
5
|
-
autoload :TerminalCompact, 'commander/help_formatters/terminal_compact'
|
6
5
|
|
7
6
|
class Context
|
8
7
|
def initialize(target)
|
9
8
|
@target = target
|
10
9
|
end
|
11
10
|
|
12
|
-
# NOTE: `get_binding` has been stubbed! This version will be ignored
|
13
|
-
# See patch for actual version
|
14
|
-
prepend Patches::HelpFormatterBinding
|
15
11
|
def get_binding
|
16
12
|
@target.instance_eval { binding }.tap do |bind|
|
17
13
|
decorate_binding(bind)
|
@@ -11,11 +11,6 @@ module Commander
|
|
11
11
|
template(:command_help).result(Context.new(command).get_binding)
|
12
12
|
end
|
13
13
|
|
14
|
-
def render_subcommand(command)
|
15
|
-
bind = ProgramContext.new(@runner).get_binding({cmd: command})
|
16
|
-
template(:subcommand_help).result(bind)
|
17
|
-
end
|
18
|
-
|
19
14
|
def template(name)
|
20
15
|
ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal', "#{name}.erb")), nil, '-')
|
21
16
|
end
|
@@ -22,14 +22,22 @@
|
|
22
22
|
<%= command %>
|
23
23
|
<% end -%>
|
24
24
|
<% end -%>
|
25
|
-
<% unless
|
25
|
+
<% unless slop.options.empty? -%>
|
26
26
|
|
27
27
|
<%= $terminal.color "OPTIONS", :bold %>:
|
28
|
-
<%
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
<% slop.options.each do |option| -%>
|
29
|
+
|
30
|
+
<% tag = if [Slop::BoolOption, Slop::NullOption].include?(option.class)
|
31
|
+
nil
|
32
|
+
elsif meta = option.config[:meta]
|
33
|
+
meta
|
34
|
+
else
|
35
|
+
option.key.upcase
|
36
|
+
end
|
37
|
+
-%>
|
38
|
+
<%= option.flags.join ', ' %> <%= tag %>
|
39
|
+
<%= Commander::HelpFormatter.indent 8, option.desc %><% if option.default_value %>
|
40
|
+
<%= $terminal.color "Default", :bold %>: <%= option.default_value %><% end %>
|
33
41
|
<% end -%>
|
34
42
|
<% end -%>
|
35
43
|
|
@@ -28,12 +28,20 @@
|
|
28
28
|
<%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
|
29
29
|
<% end %>
|
30
30
|
<% end %>
|
31
|
-
<% unless
|
31
|
+
<% unless global_slop.options.empty? -%>
|
32
32
|
<%= $terminal.color "GLOBAL OPTIONS", :bold %>:
|
33
|
-
<%
|
33
|
+
<% global_slop.options.each do |global| -%>
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
<% tag = if [Slop::BoolOption, Slop::NullOption]
|
36
|
+
nil
|
37
|
+
elsif meta = option.config[:meta]
|
38
|
+
meta
|
39
|
+
else
|
40
|
+
option.key.upcase
|
41
|
+
end
|
42
|
+
-%>
|
43
|
+
<%= global.flags.join ', ' %> <%= tag %>
|
44
|
+
<%= Commander::HelpFormatter.indent 8, global.desc %>
|
37
45
|
<% end -%>
|
38
46
|
<% end -%>
|
39
47
|
<% if program :help -%>
|
data/lib/commander/runner.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'ostruct'
|
2
2
|
|
3
3
|
module Commander
|
4
4
|
class Runner
|
@@ -14,9 +14,8 @@ module Commander
|
|
14
14
|
attr_reader :commands
|
15
15
|
|
16
16
|
##
|
17
|
-
#
|
18
|
-
|
19
|
-
attr_reader :options
|
17
|
+
# The global Slop Options
|
18
|
+
attr_reader :global_slop
|
20
19
|
|
21
20
|
##
|
22
21
|
# Hash of help formatter aliases.
|
@@ -33,8 +32,8 @@ module Commander
|
|
33
32
|
|
34
33
|
def initialize(*inputs)
|
35
34
|
@program, @commands, @default_command, \
|
36
|
-
@
|
37
|
-
|
35
|
+
@global_slop, @aliases, @args = inputs.map(&:dup)
|
36
|
+
|
38
37
|
@commands['help'] ||= Command.new('help').tap do |c|
|
39
38
|
c.syntax = "#{program(:name)} help [command]"
|
40
39
|
c.description = 'Display global or [command] help documentation'
|
@@ -49,15 +48,58 @@ module Commander
|
|
49
48
|
|
50
49
|
##
|
51
50
|
# Run command parsing and execution process
|
52
|
-
|
51
|
+
INBUILT_ERRORS = [
|
52
|
+
OptionParser::InvalidOption,
|
53
|
+
Command::CommandUsageError,
|
54
|
+
InvalidCommandError
|
55
|
+
]
|
53
56
|
|
54
57
|
def run
|
55
58
|
require_program :version, :description
|
56
59
|
|
57
|
-
|
58
|
-
|
60
|
+
# Determine where the arguments/ options start
|
61
|
+
remaining_args = if alias? command_name_from_args
|
62
|
+
@aliases[command_name_from_args.to_s] + args_without_command_name
|
63
|
+
else
|
64
|
+
args_without_command_name
|
65
|
+
end
|
59
66
|
|
60
|
-
|
67
|
+
# Combines the global and command options into a single parser
|
68
|
+
global_opts = global_slop.options
|
69
|
+
command_opts = active_command? ? active_command.slop.options : []
|
70
|
+
opts = [*global_opts, *command_opts]
|
71
|
+
parser = Slop::Parser.new(opts)
|
72
|
+
|
73
|
+
# Parsers the arguments/opts and fetches the config
|
74
|
+
parser.parse(remaining_args)
|
75
|
+
opts = OpenStruct.new parser.parse(remaining_args).to_h
|
76
|
+
remaining_args = parser.arguments
|
77
|
+
config = program(:config).dup
|
78
|
+
|
79
|
+
if opts.version
|
80
|
+
# Return the version
|
81
|
+
say version
|
82
|
+
exit 0
|
83
|
+
elsif opts.help && active_command?
|
84
|
+
# Return help for the active_command
|
85
|
+
run_help_command([active_command!.name])
|
86
|
+
elsif active_command?
|
87
|
+
# Run the active_command
|
88
|
+
active_command.run!(remaining_args, opts, config)
|
89
|
+
else
|
90
|
+
# Return generic help
|
91
|
+
run_help_command('')
|
92
|
+
end
|
93
|
+
rescue => original
|
94
|
+
error = original
|
95
|
+
if INBUILT_ERRORS.include?(error.class)
|
96
|
+
error = InternalCallableError.new(error.message) do
|
97
|
+
$stderr.puts "\nUsage:\n\n"
|
98
|
+
name = active_command? ? active_command.name : :error
|
99
|
+
run_help_command([name])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
raise error
|
61
103
|
end
|
62
104
|
|
63
105
|
##
|
@@ -100,20 +142,39 @@ module Commander
|
|
100
142
|
@aliases.include? name.to_s
|
101
143
|
end
|
102
144
|
|
103
|
-
##
|
104
|
-
# Check if a command _name_ exists.
|
105
|
-
|
106
|
-
def command_exists?(name)
|
107
|
-
@commands[name.to_s]
|
108
|
-
end
|
109
|
-
|
110
145
|
#:stopdoc:
|
111
146
|
|
112
147
|
##
|
113
148
|
# Get active command within arguments passed to this runner.
|
149
|
+
# It will try an run the default if arguments have been provided
|
150
|
+
# It can not run a default command that is flags-only
|
151
|
+
# This is to provide consistent behaviour to --help
|
152
|
+
#
|
114
153
|
|
115
154
|
def active_command
|
116
|
-
@__active_command ||=
|
155
|
+
@__active_command ||= begin
|
156
|
+
if named_command = command(command_name_from_args)
|
157
|
+
named_command
|
158
|
+
elsif default_command? && flagless_args_string.length > 0
|
159
|
+
default_command
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def active_command!
|
165
|
+
active_command.tap { |c| require_valid_command(c) }
|
166
|
+
end
|
167
|
+
|
168
|
+
def active_command?
|
169
|
+
active_command ? true : false
|
170
|
+
end
|
171
|
+
|
172
|
+
def default_command
|
173
|
+
@__default_command ||= command(@default_command)
|
174
|
+
end
|
175
|
+
|
176
|
+
def default_command?
|
177
|
+
default_command ? true : false
|
117
178
|
end
|
118
179
|
|
119
180
|
##
|
@@ -121,15 +182,20 @@ module Commander
|
|
121
182
|
# Supports multi-word commands, using the largest possible match.
|
122
183
|
|
123
184
|
def command_name_from_args
|
124
|
-
@__command_name_from_args ||=
|
185
|
+
@__command_name_from_args ||= valid_command_names_from(*@args.dup).sort.last
|
186
|
+
end
|
187
|
+
|
188
|
+
def flagless_args_string
|
189
|
+
@flagless_args_string ||= @args.reject { |value| value =~ /^-/ }.join ' '
|
125
190
|
end
|
126
191
|
|
127
192
|
##
|
128
193
|
# Returns array of valid command names found within _args_.
|
129
194
|
|
130
195
|
def valid_command_names_from(*args)
|
131
|
-
|
132
|
-
|
196
|
+
commands.keys.find_all do |name|
|
197
|
+
name if flagless_args_string =~ /^#{name}(?![[:graph:]])/
|
198
|
+
end
|
133
199
|
end
|
134
200
|
|
135
201
|
##
|
@@ -145,7 +211,7 @@ module Commander
|
|
145
211
|
def args_without_command_name
|
146
212
|
removed = []
|
147
213
|
parts = command_name_from_args.split rescue []
|
148
|
-
@args.
|
214
|
+
@args.reject do |arg|
|
149
215
|
removed << arg if parts.include?(arg) && !removed.include?(arg)
|
150
216
|
end
|
151
217
|
end
|
@@ -155,37 +221,17 @@ module Commander
|
|
155
221
|
|
156
222
|
def help_formatter_alias_defaults
|
157
223
|
{
|
158
|
-
compact: HelpFormatter::TerminalCompact,
|
159
224
|
}
|
160
225
|
end
|
161
226
|
|
162
|
-
##
|
163
|
-
# Limit commands to those which are subcommands of the one that is active
|
164
|
-
def limit_commands_to_subcommands(command)
|
165
|
-
commands.select! do |other_sym, _|
|
166
|
-
other = other_sym.to_s
|
167
|
-
# Do not match sub-sub commands (matches for a second space)
|
168
|
-
if /\A#{command.name}\s.*\s/.match?(other)
|
169
|
-
false
|
170
|
-
# Do match regular sub commands
|
171
|
-
elsif /\A#{command.name}\s/.match?(other)
|
172
|
-
true
|
173
|
-
# Do not match any other commands
|
174
|
-
else
|
175
|
-
false
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
227
|
##
|
181
228
|
# Creates default commands such as 'help' which is
|
182
229
|
# essentially the same as using the --help switch.
|
183
230
|
def run_help_command(args)
|
184
231
|
UI.enable_paging if program(:help_paging)
|
185
|
-
@help_commands = @commands.
|
232
|
+
@help_commands = @commands.reject { |_, v| v.hidden(false) }.to_h
|
186
233
|
if args.empty? || args[0] == :error
|
187
|
-
@help_options =
|
188
|
-
@help_commands.reject! { |k, v| !!v.hidden }
|
234
|
+
@help_options = []
|
189
235
|
old_wrap = $terminal.wrap_at
|
190
236
|
$terminal.wrap_at = nil
|
191
237
|
program(:nobanner, true) if args[0] == :error
|
@@ -194,54 +240,17 @@ module Commander
|
|
194
240
|
else
|
195
241
|
command = command args.join(' ')
|
196
242
|
require_valid_command command
|
197
|
-
|
198
|
-
limit_commands_to_subcommands(command)
|
199
|
-
say help_formatter.render_subcommand(command)
|
200
|
-
else
|
201
|
-
say help_formatter.render_command(command)
|
202
|
-
end
|
243
|
+
say help_formatter.render_command(command)
|
203
244
|
end
|
204
245
|
end
|
205
246
|
|
206
247
|
##
|
207
248
|
# Raises InvalidCommandError when a _command_ is not found.
|
208
249
|
|
209
|
-
def require_valid_command(command
|
250
|
+
def require_valid_command(command)
|
210
251
|
fail InvalidCommandError, 'invalid command', caller if command.nil?
|
211
252
|
end
|
212
253
|
|
213
|
-
##
|
214
|
-
# Removes global _options_ from _args_. This prevents an invalid
|
215
|
-
# option error from occurring when options are parsed
|
216
|
-
# again for the command.
|
217
|
-
|
218
|
-
def remove_global_options(options, args)
|
219
|
-
# TODO: refactor with flipflop, please TJ ! have time to refactor me !
|
220
|
-
options.each do |option|
|
221
|
-
switches = option[:switches].dup
|
222
|
-
next if switches.empty?
|
223
|
-
|
224
|
-
if (switch_has_arg = switches.any? { |s| s =~ /[ =]/ })
|
225
|
-
switches.map! { |s| s[0, s.index('=') || s.index(' ') || s.length] }
|
226
|
-
end
|
227
|
-
|
228
|
-
switches = expand_optionally_negative_switches(switches)
|
229
|
-
|
230
|
-
past_switch, arg_removed = false, false
|
231
|
-
args.delete_if do |arg|
|
232
|
-
if switches.any? { |s| s == arg }
|
233
|
-
arg_removed = !switch_has_arg
|
234
|
-
past_switch = true
|
235
|
-
elsif past_switch && !arg_removed && arg !~ /^-/
|
236
|
-
arg_removed = true
|
237
|
-
else
|
238
|
-
arg_removed = true
|
239
|
-
false
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
254
|
# expand switches of the style '--[no-]blah' into both their
|
246
255
|
# '--blah' and '--no-blah' variants, so that they can be
|
247
256
|
# properly detected and removed
|
@@ -256,41 +265,6 @@ module Commander
|
|
256
265
|
end
|
257
266
|
end
|
258
267
|
|
259
|
-
##
|
260
|
-
# Parse global command options.
|
261
|
-
|
262
|
-
def parse_global_options
|
263
|
-
parser = options.inject(OptionParser.new) do |options, option|
|
264
|
-
options.on(*option[:args], &global_option_proc(option[:switches], &option[:proc]))
|
265
|
-
end
|
266
|
-
|
267
|
-
options = @args.dup
|
268
|
-
begin
|
269
|
-
parser.parse!(options)
|
270
|
-
rescue OptionParser::InvalidOption => e
|
271
|
-
# Remove the offending args and retry.
|
272
|
-
options = options.reject { |o| e.args.include?(o) }
|
273
|
-
retry
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
##
|
278
|
-
# Returns a proc allowing for commands to inherit global options.
|
279
|
-
# This functionality works whether a block is present for the global
|
280
|
-
# option or not, so simple switches such as --verbose can be used
|
281
|
-
# without a block, and used throughout all commands.
|
282
|
-
|
283
|
-
def global_option_proc(switches, &block)
|
284
|
-
lambda do |value|
|
285
|
-
unless active_command.nil?
|
286
|
-
active_command.proxy_options << [Runner.switch_to_sym(switches.last), value]
|
287
|
-
end
|
288
|
-
if block && !value.nil?
|
289
|
-
instance_exec(value, &block)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
268
|
##
|
295
269
|
# Raises a CommandError when the program any of the _keys_ are not present, or empty.
|
296
270
|
|
@@ -325,18 +299,6 @@ module Commander
|
|
325
299
|
switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
|
326
300
|
end
|
327
301
|
|
328
|
-
##
|
329
|
-
# Run the active command.
|
330
|
-
|
331
|
-
def run_active_command
|
332
|
-
require_valid_command
|
333
|
-
if alias? command_name_from_args
|
334
|
-
active_command.run(*(@aliases[command_name_from_args.to_s] + args_without_command_name))
|
335
|
-
else
|
336
|
-
active_command.run(*args_without_command_name)
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
302
|
def say(*args) #:nodoc:
|
341
303
|
$terminal.say(*args)
|
342
304
|
end
|