commander-openflighthpc 1.0.0.pre.alpha1
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 +7 -0
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +44 -0
- data/.rubocop_todo.yml +77 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +51 -0
- data/Manifest +38 -0
- data/README.md +492 -0
- data/Rakefile +13 -0
- data/bin/commander +104 -0
- data/commander-openflighthpc.gemspec +32 -0
- data/lib/commander.rb +36 -0
- data/lib/commander/blank.rb +7 -0
- data/lib/commander/command.rb +263 -0
- data/lib/commander/configure.rb +14 -0
- data/lib/commander/core_ext.rb +2 -0
- data/lib/commander/core_ext/array.rb +24 -0
- data/lib/commander/core_ext/object.rb +8 -0
- data/lib/commander/delegates.rb +27 -0
- data/lib/commander/help_formatters.rb +52 -0
- data/lib/commander/help_formatters/base.rb +24 -0
- data/lib/commander/help_formatters/terminal.rb +24 -0
- data/lib/commander/help_formatters/terminal/command_help.erb +35 -0
- data/lib/commander/help_formatters/terminal/help.erb +36 -0
- data/lib/commander/help_formatters/terminal/subcommand_help.erb +23 -0
- data/lib/commander/help_formatters/terminal_compact.rb +11 -0
- data/lib/commander/help_formatters/terminal_compact/command_help.erb +26 -0
- data/lib/commander/help_formatters/terminal_compact/help.erb +29 -0
- data/lib/commander/help_formatters/terminal_compact/subcommand_help.erb +15 -0
- data/lib/commander/import.rb +5 -0
- data/lib/commander/methods.rb +11 -0
- data/lib/commander/patches/decimal-integer.rb +17 -0
- data/lib/commander/patches/help_formatter_binding.rb +15 -0
- data/lib/commander/patches/implicit-short-tags.rb +75 -0
- data/lib/commander/patches/option_defaults.rb +23 -0
- data/lib/commander/patches/validate_inputs.rb +76 -0
- data/lib/commander/platform.rb +7 -0
- data/lib/commander/runner.rb +493 -0
- data/lib/commander/user_interaction.rb +551 -0
- data/lib/commander/version.rb +3 -0
- data/spec/command_spec.rb +157 -0
- data/spec/configure_spec.rb +37 -0
- data/spec/core_ext/array_spec.rb +18 -0
- data/spec/core_ext/object_spec.rb +19 -0
- data/spec/help_formatters/terminal_compact_spec.rb +69 -0
- data/spec/help_formatters/terminal_spec.rb +67 -0
- data/spec/methods_spec.rb +61 -0
- data/spec/patches/validate_inputs_spec.rb +84 -0
- data/spec/runner_spec.rb +672 -0
- data/spec/spec_helper.rb +79 -0
- data/spec/ui_spec.rb +30 -0
- metadata +183 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Commander
|
2
|
+
def configure(*configuration_opts, &configuration_block)
|
3
|
+
configuration_module = Module.new
|
4
|
+
configuration_module.extend Commander::Methods
|
5
|
+
|
6
|
+
configuration_module.class_exec(*configuration_opts, &configuration_block)
|
7
|
+
|
8
|
+
configuration_module.class_exec do
|
9
|
+
run!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module_function :configure
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Array
|
2
|
+
##
|
3
|
+
# Split _string_ into an array. Used in
|
4
|
+
# conjunction with Highline's #ask, or #ask_for_array
|
5
|
+
# methods, which must respond to #parse.
|
6
|
+
#
|
7
|
+
# This method allows escaping of whitespace. For example
|
8
|
+
# the arguments foo bar\ baz will become ['foo', 'bar baz']
|
9
|
+
#
|
10
|
+
# === Example
|
11
|
+
#
|
12
|
+
# # ask invokes Array#parse
|
13
|
+
# list = ask 'Favorite cookies:', Array
|
14
|
+
#
|
15
|
+
# # or use ask_for_CLASS
|
16
|
+
# list = ask_for_array 'Favorite cookies: '
|
17
|
+
#
|
18
|
+
|
19
|
+
def self.parse(string)
|
20
|
+
# Using reverse + lookahead to work around Ruby 1.8's lack of lookbehind
|
21
|
+
# TODO: simplify now that we don't support Ruby 1.8
|
22
|
+
string.reverse.split(/\s(?!\\)/).reverse.map { |s| s.reverse.gsub('\\ ', ' ') }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Commander
|
2
|
+
module Delegates
|
3
|
+
%w(
|
4
|
+
add_command
|
5
|
+
command
|
6
|
+
program
|
7
|
+
error_handler
|
8
|
+
run!
|
9
|
+
global_option
|
10
|
+
alias_command
|
11
|
+
default_command
|
12
|
+
always_trace!
|
13
|
+
never_trace!
|
14
|
+
silent_trace!
|
15
|
+
).each do |meth|
|
16
|
+
eval <<-END, binding, __FILE__, __LINE__
|
17
|
+
def #{meth}(*args, &block)
|
18
|
+
::Commander::Runner.instance.#{meth}(*args, &block)
|
19
|
+
end
|
20
|
+
END
|
21
|
+
end
|
22
|
+
|
23
|
+
def defined_commands(*args, &block)
|
24
|
+
::Commander::Runner.instance.commands(*args, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Commander
|
2
|
+
module HelpFormatter
|
3
|
+
autoload :Base, 'commander/help_formatters/base'
|
4
|
+
autoload :Terminal, 'commander/help_formatters/terminal'
|
5
|
+
autoload :TerminalCompact, 'commander/help_formatters/terminal_compact'
|
6
|
+
|
7
|
+
class Context
|
8
|
+
def initialize(target)
|
9
|
+
@target = target
|
10
|
+
end
|
11
|
+
|
12
|
+
# NOTE: `get_binding` has been stubbed! This version will be ignored
|
13
|
+
# See patch for actual version
|
14
|
+
prepend Patches::HelpFormatterBinding
|
15
|
+
def get_binding
|
16
|
+
@target.instance_eval { binding }.tap do |bind|
|
17
|
+
decorate_binding(bind)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# No-op, override in subclasses.
|
22
|
+
def decorate_binding(_bind)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ProgramContext < Context
|
27
|
+
def decorate_binding(bind)
|
28
|
+
bind.eval("max_command_length = #{max_command_length(bind)}")
|
29
|
+
bind.eval("max_aliases_length = #{max_aliases_length(bind)}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def max_command_length(bind)
|
33
|
+
max_key_length(bind.eval('@commands'))
|
34
|
+
end
|
35
|
+
|
36
|
+
def max_aliases_length(bind)
|
37
|
+
max_key_length(bind.eval('@aliases'))
|
38
|
+
end
|
39
|
+
|
40
|
+
def max_key_length(hash, default = 20)
|
41
|
+
longest = hash.keys.max_by(&:size)
|
42
|
+
longest ? longest.size : default
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module_function
|
47
|
+
|
48
|
+
def indent(amount, text)
|
49
|
+
text.to_s.gsub("\n", "\n" + (' ' * amount))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Commander
|
2
|
+
##
|
3
|
+
# = Help Formatter
|
4
|
+
#
|
5
|
+
# Commander's help formatters control the output when
|
6
|
+
# either the help command, or --help switch are called.
|
7
|
+
# The default formatter is Commander::HelpFormatter::Terminal.
|
8
|
+
|
9
|
+
module HelpFormatter
|
10
|
+
class Base
|
11
|
+
def initialize(runner)
|
12
|
+
@runner = runner
|
13
|
+
end
|
14
|
+
|
15
|
+
def render
|
16
|
+
'Implement global help here'
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_command(command)
|
20
|
+
"Implement help for #{command.name} here"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Commander
|
4
|
+
module HelpFormatter
|
5
|
+
class Terminal < Base
|
6
|
+
def render
|
7
|
+
template(:help).result(ProgramContext.new(@runner).get_binding)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_command(command)
|
11
|
+
template(:command_help).result(Context.new(command).get_binding)
|
12
|
+
end
|
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
|
+
def template(name)
|
20
|
+
ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal', "#{name}.erb")), nil, '-')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<% if !@syntax -%>
|
2
|
+
<%= $terminal.color "NAME", :bold %>:
|
3
|
+
|
4
|
+
<%= @name %>
|
5
|
+
<% else -%>
|
6
|
+
<%= $terminal.color "SYNOPSIS", :bold %>:
|
7
|
+
|
8
|
+
<%= @syntax -%>
|
9
|
+
|
10
|
+
<% end -%>
|
11
|
+
|
12
|
+
<%= $terminal.color "DESCRIPTION", :bold %>:
|
13
|
+
|
14
|
+
<%= Commander::HelpFormatter.indent 4, (@description || @summary || 'No description.') -%>
|
15
|
+
|
16
|
+
<% unless @examples.empty? -%>
|
17
|
+
|
18
|
+
<%= $terminal.color "EXAMPLES", :bold %>:
|
19
|
+
<% for description, command in @examples -%>
|
20
|
+
|
21
|
+
# <%= description %>
|
22
|
+
<%= command %>
|
23
|
+
<% end -%>
|
24
|
+
<% end -%>
|
25
|
+
<% unless @options.empty? -%>
|
26
|
+
|
27
|
+
<%= $terminal.color "OPTIONS", :bold %>:
|
28
|
+
<% for option in @options -%>
|
29
|
+
|
30
|
+
<%= option[:switches].join ', ' %>
|
31
|
+
<%= Commander::HelpFormatter.indent 8, option[:description] %><% if option[:default] %>
|
32
|
+
<%= $terminal.color "Default", :bold %>: <%= option[:default] %><% end %>
|
33
|
+
<% end -%>
|
34
|
+
<% end -%>
|
35
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<%= $terminal.color "NAME", :bold %>:
|
2
|
+
|
3
|
+
<%= program :name %>
|
4
|
+
|
5
|
+
<%= $terminal.color "DESCRIPTION", :bold %>:
|
6
|
+
|
7
|
+
<%= Commander::HelpFormatter.indent 4, program(:description) %>
|
8
|
+
|
9
|
+
<%= $terminal.color "COMMANDS", :bold %>:
|
10
|
+
<% for name, command in @help_commands.sort -%>
|
11
|
+
<% unless alias? name %>
|
12
|
+
<%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] -%>
|
13
|
+
<% end -%>
|
14
|
+
<% end %>
|
15
|
+
<% unless @aliases.empty? %>
|
16
|
+
<%= $terminal.color "ALIASES", :bold %>:
|
17
|
+
<% for alias_name, args in @aliases.sort %>
|
18
|
+
<%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
<% unless @help_options.empty? -%>
|
22
|
+
<%= $terminal.color "GLOBAL OPTIONS", :bold %>:
|
23
|
+
<% for option in @help_options -%>
|
24
|
+
|
25
|
+
<%= option[:switches].join ', ' %>
|
26
|
+
<%= option[:description] %>
|
27
|
+
<% end -%>
|
28
|
+
<% end -%>
|
29
|
+
<% if program :help -%>
|
30
|
+
<% for title, body in program(:help) %>
|
31
|
+
<%= $terminal.color title.to_s.upcase, :bold %>:
|
32
|
+
|
33
|
+
<%= body %>
|
34
|
+
<% end -%>
|
35
|
+
<% end -%>
|
36
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<% if !cmd.syntax %>
|
2
|
+
<%= $terminal.color "NAME", :bold %>:
|
3
|
+
|
4
|
+
<%= cmd.name %>
|
5
|
+
<% else -%>
|
6
|
+
<%= $terminal.color "SYNOPSIS", :bold %>:
|
7
|
+
|
8
|
+
<%= cmd.syntax -%>
|
9
|
+
|
10
|
+
<% end -%>
|
11
|
+
|
12
|
+
<%= $terminal.color "DESCRIPTION", :bold %>:
|
13
|
+
|
14
|
+
<%= Commander::HelpFormatter.indent 4, (cmd.description || cmd.summary || 'No description.') -%>
|
15
|
+
|
16
|
+
|
17
|
+
<%= $terminal.color "SUBCOMMANDS", :bold %>:
|
18
|
+
<% for name, command in @commands.sort -%>
|
19
|
+
<% unless alias? name %>
|
20
|
+
<%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] -%>
|
21
|
+
<% end -%>
|
22
|
+
<% end %>
|
23
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%= @name %>
|
2
|
+
<% if @syntax -%>
|
3
|
+
|
4
|
+
Usage: <%= @syntax %>
|
5
|
+
<% end -%>
|
6
|
+
<% if @description || @summary -%>
|
7
|
+
|
8
|
+
<%= @description || @summary %>
|
9
|
+
<% end -%>
|
10
|
+
<% unless @examples.empty? -%>
|
11
|
+
|
12
|
+
Examples:
|
13
|
+
<% for description, command in @examples -%>
|
14
|
+
|
15
|
+
# <%= description %>
|
16
|
+
<%= command %>
|
17
|
+
<% end -%>
|
18
|
+
<% end -%>
|
19
|
+
<% unless @options.empty? -%>
|
20
|
+
|
21
|
+
Options:
|
22
|
+
<% for option in @options -%>
|
23
|
+
<%= "%-20s %s" % [option[:switches].join(', '), option[:description]] %><% if option[:default] %> <%= option[:default] %><% end %>
|
24
|
+
<% end -%>
|
25
|
+
<% end -%>
|
26
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<%= program :name %>
|
2
|
+
|
3
|
+
<%= program :description %>
|
4
|
+
|
5
|
+
Commands:
|
6
|
+
<% for name, command in @help_commands.sort -%>
|
7
|
+
<% unless alias? name -%>
|
8
|
+
<%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] %>
|
9
|
+
<% end -%>
|
10
|
+
<% end -%>
|
11
|
+
<% unless @aliases.empty? %>
|
12
|
+
Aliases:
|
13
|
+
<% for alias_name, args in @aliases.sort -%>
|
14
|
+
<%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] %>
|
15
|
+
<% end -%>
|
16
|
+
<% end %>
|
17
|
+
<% unless @help_options.empty? -%>
|
18
|
+
Global Options:
|
19
|
+
<% for option in @help_options -%>
|
20
|
+
<%= "%-20s %s" % [option[:switches].join(', '), option[:description]] -%>
|
21
|
+
<% end -%>
|
22
|
+
<% end -%>
|
23
|
+
<% if program :help -%>
|
24
|
+
<% for title, body in program(:help) %>
|
25
|
+
<%= title %>:
|
26
|
+
<%= body %>
|
27
|
+
<% end %>
|
28
|
+
<% end -%>
|
29
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= cmd.name %>
|
2
|
+
<% if cmd.syntax -%>
|
3
|
+
|
4
|
+
Usage: <%= cmd.syntax %>
|
5
|
+
<% end -%>
|
6
|
+
<% if cmd.description || cmd.summary -%>
|
7
|
+
|
8
|
+
<%= cmd.description || cmd.summary %>
|
9
|
+
<% end -%>
|
10
|
+
|
11
|
+
<% for name, command in @commands.sort -%>
|
12
|
+
<% unless alias? name -%>
|
13
|
+
<%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] %>
|
14
|
+
<% end -%>
|
15
|
+
<% end -%>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Patches the underling OptionParser DecimalInteger type so that it doesn't
|
2
|
+
# convert numbers starting with a '0' as if they are an Octal number
|
3
|
+
module Commander
|
4
|
+
module Patches
|
5
|
+
module DecimalInteger
|
6
|
+
decimal = '\d+(?:_\d+)*'
|
7
|
+
DecimalInteger = /\A[-+]?#{decimal}\z/io
|
8
|
+
::OptionParser::accept(DecimalInteger, DecimalInteger) {|s,|
|
9
|
+
begin
|
10
|
+
Integer(s, 10)
|
11
|
+
rescue ArgumentError
|
12
|
+
raise ::OptionParser::InvalidArgument, s
|
13
|
+
end if s
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Commander
|
2
|
+
module Patches
|
3
|
+
module HelpFormatterBinding
|
4
|
+
def get_binding(additional = {})
|
5
|
+
bnd = @target.instance_eval { binding }.tap do |bind|
|
6
|
+
decorate_binding(bind)
|
7
|
+
end
|
8
|
+
additional.each do |k, v|
|
9
|
+
bnd.local_variable_set(k, v)
|
10
|
+
end
|
11
|
+
bnd
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Patches the underling ruby OptionParser to prevent it from automatically
|
2
|
+
# generating short tags for options
|
3
|
+
module Commander
|
4
|
+
module Patches
|
5
|
+
module ImplicitShortTags
|
6
|
+
def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
|
7
|
+
opt, arg, val, rest = nil
|
8
|
+
nonopt ||= proc {|a| throw :terminate, a}
|
9
|
+
argv.unshift(arg) if arg = catch(:terminate) {
|
10
|
+
while arg = argv.shift
|
11
|
+
case arg
|
12
|
+
# long option
|
13
|
+
when /\A--([^=]*)(?:=(.*))?/m
|
14
|
+
opt, rest = $1, $2
|
15
|
+
opt.tr!('_', '-')
|
16
|
+
begin
|
17
|
+
sw, = complete(:long, opt, true)
|
18
|
+
rescue ::OptionParser::ParseError
|
19
|
+
raise $!.set_option(arg, true)
|
20
|
+
end
|
21
|
+
begin
|
22
|
+
opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
|
23
|
+
val = cb.call(val) if cb
|
24
|
+
setter.call(sw.switch_name, val) if setter
|
25
|
+
rescue ::OptionParser::ParseError
|
26
|
+
raise $!.set_option(arg, rest)
|
27
|
+
end
|
28
|
+
|
29
|
+
# short option
|
30
|
+
when /\A-(.)((=).*|.+)?/m
|
31
|
+
eq, rest, opt = $3, $2, $1
|
32
|
+
has_arg, val = eq, rest
|
33
|
+
begin
|
34
|
+
sw, = search(:short, opt)
|
35
|
+
unless sw
|
36
|
+
sw, = complete(:short, opt)
|
37
|
+
# short option matched.
|
38
|
+
val = arg.sub(/\A-/, '')
|
39
|
+
has_arg = true
|
40
|
+
end
|
41
|
+
rescue ::OptionParser::ParseError
|
42
|
+
raise $!.set_option(arg, true)
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
|
46
|
+
raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
|
47
|
+
argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
|
48
|
+
val = cb.call(val) if cb
|
49
|
+
setter.call(sw.switch_name, val) if setter
|
50
|
+
rescue ::OptionParser::ParseError
|
51
|
+
raise $!.set_option(arg, arg.length > 2)
|
52
|
+
end
|
53
|
+
|
54
|
+
# non-option argument
|
55
|
+
else
|
56
|
+
catch(:prune) do
|
57
|
+
visit(:each_option) do |sw0|
|
58
|
+
sw = sw0
|
59
|
+
sw.block.call(arg) if ::OptionParser::Switch === sw and sw.match_nonswitch?(arg)
|
60
|
+
end
|
61
|
+
nonopt.call(arg)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
nil
|
67
|
+
}
|
68
|
+
|
69
|
+
visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
|
70
|
+
|
71
|
+
argv
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|