runfile 0.12.0.pre.rc1 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +112 -28
- data/bin/runn +5 -0
- data/examples/default-action/runfile +9 -0
- data/examples/default-action-2/runfile +11 -0
- data/examples/default-action-2/server.runfile +6 -0
- data/examples/different-name/runfile.rb +8 -0
- data/examples/example/runfile +10 -0
- data/examples/example-multiline/runfile +16 -0
- data/examples/execute/runfile +14 -0
- data/examples/execute/server.runfile +11 -0
- data/examples/full/runfile +24 -0
- data/examples/import/more_tasks/spec.runfile +7 -0
- data/examples/import/runfile +10 -0
- data/examples/import/tasks/server.runfile +13 -0
- data/examples/minimal/runfile +4 -0
- data/examples/multiple-runfiles/runfile +11 -0
- data/examples/multiple-runfiles/server.runfile +13 -0
- data/examples/named-only/deploy.runfile +7 -0
- data/examples/named-only/server.runfile +11 -0
- data/examples/naval-fate/runfile +47 -0
- data/examples/shortcut/runfile +31 -0
- data/lib/runfile/action.rb +40 -14
- data/lib/runfile/concerns/dsl.rb +132 -0
- data/lib/runfile/concerns/inspectable.rb +13 -0
- data/lib/runfile/concerns/renderable.rb +16 -0
- data/lib/runfile/entrypoint.rb +50 -0
- data/lib/runfile/exceptions.rb +13 -0
- data/lib/runfile/gem_finder.rb +29 -0
- data/lib/runfile/initiator.rb +87 -0
- data/lib/runfile/meta.rb +65 -0
- data/lib/runfile/runner.rb +10 -173
- data/lib/runfile/templates/runfile +13 -0
- data/lib/runfile/userfile.rb +111 -0
- data/lib/runfile/version.rb +2 -2
- data/lib/runfile/views/initiator.gtx +28 -0
- data/lib/runfile/views/userfile.gtx +93 -0
- data/lib/runfile.rb +13 -10
- metadata +96 -21
- data/bin/run +0 -10
- data/bin/run! +0 -16
- data/lib/runfile/docopt_helper.rb +0 -128
- data/lib/runfile/dsl.rb +0 -90
- data/lib/runfile/refinements.rb +0 -22
- data/lib/runfile/runfile_helper.rb +0 -165
- data/lib/runfile/settings.rb +0 -34
- data/lib/runfile/setup.rb +0 -19
- data/lib/runfile/templates/Runfile +0 -16
- data/lib/runfile/terminal.rb +0 -32
@@ -0,0 +1,132 @@
|
|
1
|
+
module Runfile
|
2
|
+
module DSL
|
3
|
+
# Commands
|
4
|
+
|
5
|
+
attr_reader :default_action
|
6
|
+
|
7
|
+
def action(name = nil, shortcut = nil, &block)
|
8
|
+
current_action.block = block
|
9
|
+
current_action.name = name
|
10
|
+
current_action.shortcut = shortcut if shortcut
|
11
|
+
current_action.prefix = action_prefix if action_prefix
|
12
|
+
|
13
|
+
# if default_action && name
|
14
|
+
# raise SyntaxError, <<~ERROR
|
15
|
+
# Cannot define action nub`#{name}` since a default action was already defined
|
16
|
+
# ERROR
|
17
|
+
# end
|
18
|
+
|
19
|
+
actions[name || :default] = current_action
|
20
|
+
@default_action = current_action unless name
|
21
|
+
@current_action = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def env_var(name, help)
|
25
|
+
env_vars[name] = help
|
26
|
+
end
|
27
|
+
|
28
|
+
def example(text)
|
29
|
+
examples.push text
|
30
|
+
end
|
31
|
+
|
32
|
+
def help(message)
|
33
|
+
current_action.help = message
|
34
|
+
end
|
35
|
+
|
36
|
+
def import(pathspec)
|
37
|
+
imports.push pathspec
|
38
|
+
end
|
39
|
+
|
40
|
+
def import_gem(gem_name, runfile_path, context = nil)
|
41
|
+
if context && !context.is_a?(Hash)
|
42
|
+
raise SyntaxError, <<~ERROR
|
43
|
+
The third argument to nub`import_gem` must be a hash
|
44
|
+
got rb`#{context.inspect}`
|
45
|
+
ERROR
|
46
|
+
end
|
47
|
+
|
48
|
+
path = GemFinder.find gem_name, runfile_path
|
49
|
+
imports.push path
|
50
|
+
contexts[runfile_path] = context if context
|
51
|
+
end
|
52
|
+
|
53
|
+
def option(name, help)
|
54
|
+
options[name] = help
|
55
|
+
end
|
56
|
+
|
57
|
+
def param(name, help)
|
58
|
+
params[name] = help
|
59
|
+
end
|
60
|
+
|
61
|
+
def shortcut(name)
|
62
|
+
current_action.shortcut = name
|
63
|
+
end
|
64
|
+
|
65
|
+
def summary(text = nil)
|
66
|
+
return @summary unless text
|
67
|
+
|
68
|
+
@summary = text
|
69
|
+
end
|
70
|
+
|
71
|
+
def title(text = nil)
|
72
|
+
return @title unless text
|
73
|
+
|
74
|
+
@title = text
|
75
|
+
end
|
76
|
+
|
77
|
+
def usage(message)
|
78
|
+
message = "#{action_prefix} #{message}" if action_prefix
|
79
|
+
current_action.usages.push message
|
80
|
+
end
|
81
|
+
|
82
|
+
def version(text = nil)
|
83
|
+
return @version unless text
|
84
|
+
|
85
|
+
@version = text
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute(command_line)
|
89
|
+
run Shellwords.split(command_line)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Evaluation Artifacts
|
93
|
+
|
94
|
+
def action_prefix
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def contexts
|
99
|
+
@contexts ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def actions
|
103
|
+
@actions ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
def params
|
107
|
+
@params ||= {}
|
108
|
+
end
|
109
|
+
|
110
|
+
def env_vars
|
111
|
+
@env_vars ||= {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def examples
|
115
|
+
@examples ||= []
|
116
|
+
end
|
117
|
+
|
118
|
+
def options
|
119
|
+
@options ||= {}
|
120
|
+
end
|
121
|
+
|
122
|
+
def imports
|
123
|
+
@imports ||= []
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def current_action
|
129
|
+
@current_action ||= Action.new
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Runfile
|
2
|
+
module Renderable
|
3
|
+
include Colsole
|
4
|
+
|
5
|
+
def render(view, context: nil)
|
6
|
+
path = "#{base_view_path}/#{view}.gtx"
|
7
|
+
GTX.render_file path, context: context, filename: path
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def base_view_path
|
13
|
+
@base_view_path ||= ::File.expand_path '../views', __dir__
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Serves as the initial entrypoint when running +run+.
|
3
|
+
class Entrypoint
|
4
|
+
include Inspectable
|
5
|
+
include Renderable
|
6
|
+
include Colsole
|
7
|
+
|
8
|
+
attr_reader :argv
|
9
|
+
|
10
|
+
def initialize(argv = ARGV)
|
11
|
+
@argv = argv
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspectable
|
15
|
+
{ argv: argv }
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
meta.handler(argv).run argv
|
20
|
+
end
|
21
|
+
|
22
|
+
def run!
|
23
|
+
run
|
24
|
+
rescue Runfile::ExitWithUsage => e
|
25
|
+
say e.message
|
26
|
+
1
|
27
|
+
rescue Runfile::UserError => e
|
28
|
+
puts e.backtrace.reverse if ENV['DEBUG']
|
29
|
+
say! "mib` #{e.class} `"
|
30
|
+
say! e.message
|
31
|
+
1
|
32
|
+
rescue Interrupt
|
33
|
+
say! 'm`Goodbye`', replace: true
|
34
|
+
1
|
35
|
+
rescue => e
|
36
|
+
puts e.backtrace.reverse if ENV['DEBUG']
|
37
|
+
origin = e.backtrace_locations.first
|
38
|
+
location = "#{origin.path}:#{origin.lineno}"
|
39
|
+
say! "rib` #{e.class} ` in nu`#{location}`"
|
40
|
+
say! e.message
|
41
|
+
1
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def meta
|
47
|
+
@meta ||= Meta.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Runfile
|
2
|
+
# All exceptions are rescued in bin/run, but using different styling
|
3
|
+
# Note that UserError types are displayed without location and are intended
|
4
|
+
# to be used when location is not important.
|
5
|
+
|
6
|
+
class Error < StandardError; end
|
7
|
+
class UserError < Error; end
|
8
|
+
class ExitWithUsage < Error; end
|
9
|
+
|
10
|
+
class ActionNotFound < UserError; end
|
11
|
+
class GemNotFound < UserError; end
|
12
|
+
class SyntaxError < UserError; end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Finds the path of an installed or bundled gem
|
3
|
+
# Adapted from Rubocop <https://github.com/rubocop/rubocop/blob/master/lib/rubocop/config_loader_resolver.rb#L268>
|
4
|
+
class GemFinder
|
5
|
+
class << self
|
6
|
+
def find(gem_name, file = nil)
|
7
|
+
gem_path = find_gem_path gem_name
|
8
|
+
file ? File.join(gem_path, file) : gem_path
|
9
|
+
rescue Gem::LoadError
|
10
|
+
raise GemNotFound, "Cannot import gem nub`#{gem_name}`\nTry running g`gem install #{gem_name}`"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def find_gem_path(gem_name)
|
16
|
+
if bundler?
|
17
|
+
gem = Bundler.load.specs[gem_name].first
|
18
|
+
gem_path = gem.full_gem_path if gem
|
19
|
+
end
|
20
|
+
|
21
|
+
gem_path || Gem::Specification.find_by_name(gem_name).gem_dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def bundler?
|
25
|
+
defined? Bundler
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Runfile
|
4
|
+
# Creates a new runfile when running +run new+ in a directory without
|
5
|
+
# runfiles.
|
6
|
+
class Initiator
|
7
|
+
include Inspectable
|
8
|
+
include Renderable
|
9
|
+
|
10
|
+
def run(argv = ARGV)
|
11
|
+
Runner.run docopt, argv: argv, version: VERSION do |args|
|
12
|
+
execute_command args
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def execute_command(args)
|
19
|
+
return create_new_file if args['new']
|
20
|
+
|
21
|
+
if args['NAME']
|
22
|
+
create_example args['NAME']
|
23
|
+
else
|
24
|
+
list_examples
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_new_file
|
29
|
+
template = File.expand_path 'templates/runfile', __dir__
|
30
|
+
FileUtils.cp template, '.'
|
31
|
+
say 'Created g`runfile`'
|
32
|
+
say_tip
|
33
|
+
end
|
34
|
+
|
35
|
+
def list_examples
|
36
|
+
say "nu`Available Examples`\n"
|
37
|
+
examples.each { |x| puts " #{x}" }
|
38
|
+
say ''
|
39
|
+
say <<~TIP
|
40
|
+
Run g`run example EXAMPLE` with any of these examples to copy the files
|
41
|
+
to the current directory.
|
42
|
+
|
43
|
+
If you are not sure, try g`run example naval-fate`.
|
44
|
+
TIP
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_example(name)
|
48
|
+
dir = "#{examples_dir}/#{name}"
|
49
|
+
files = Dir["#{dir}/{runfile,*.runfile,*.rb}"]
|
50
|
+
raise UserError, "No such example: nu`#{name}`" if files.empty?
|
51
|
+
|
52
|
+
files.each { |file| safe_copy file }
|
53
|
+
say_tip
|
54
|
+
end
|
55
|
+
|
56
|
+
def say_tip
|
57
|
+
say ''
|
58
|
+
say 'Run g`run` or g`run --help` to see your runfile'
|
59
|
+
say 'Delete the copied files to go back to the initial state'
|
60
|
+
end
|
61
|
+
|
62
|
+
def safe_copy(file)
|
63
|
+
target = File.basename file
|
64
|
+
# This will never happen since if there is a runfile, the initiator will
|
65
|
+
# not be called. Nonetheless, keep it for safety
|
66
|
+
return if File.exist? target
|
67
|
+
|
68
|
+
FileUtils.cp file, '.'
|
69
|
+
say "Copied g`#{target}`"
|
70
|
+
end
|
71
|
+
|
72
|
+
def examples
|
73
|
+
@examples ||= Dir["#{examples_dir}/*"]
|
74
|
+
.select { |f| File.directory? f }
|
75
|
+
.map { |f| File.basename f }
|
76
|
+
.sort
|
77
|
+
end
|
78
|
+
|
79
|
+
def examples_dir
|
80
|
+
@examples_dir ||= File.expand_path '../../examples', __dir__
|
81
|
+
end
|
82
|
+
|
83
|
+
def docopt
|
84
|
+
@docopt ||= render('initiator', context: self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/runfile/meta.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Holds meta information about the state of runfiles in a given directory
|
3
|
+
class Meta
|
4
|
+
include Inspectable
|
5
|
+
|
6
|
+
MASTERFILE_NAMES = %w[runfile Runfile runfile.rb]
|
7
|
+
|
8
|
+
def masterfile_path
|
9
|
+
@masterfile_path ||= begin
|
10
|
+
result = nil
|
11
|
+
|
12
|
+
MASTERFILE_NAMES.each do |name|
|
13
|
+
if File.exist? name
|
14
|
+
result = name
|
15
|
+
break
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def handler(_argv = ARGV)
|
24
|
+
masterfile || dummy || initiator
|
25
|
+
end
|
26
|
+
|
27
|
+
# If there are external files and no masterfile, we will use a dummy empty
|
28
|
+
# runfile as a masterfile to serve as the access point to the named
|
29
|
+
# runfiles
|
30
|
+
def dummy
|
31
|
+
return nil unless external_files.any?
|
32
|
+
|
33
|
+
Userfile.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def initiator
|
37
|
+
Initiator.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def masterfile
|
41
|
+
return nil unless masterfile_path
|
42
|
+
|
43
|
+
@masterfile ||= Userfile.load_file masterfile_path
|
44
|
+
end
|
45
|
+
|
46
|
+
# def title
|
47
|
+
# masterfile&.title
|
48
|
+
# end
|
49
|
+
|
50
|
+
# def summary
|
51
|
+
# masterfile&.summary
|
52
|
+
# end
|
53
|
+
|
54
|
+
def globs
|
55
|
+
@globs ||= (masterfile ? ['*'] + masterfile.imports : ['*'])
|
56
|
+
end
|
57
|
+
|
58
|
+
def external_files
|
59
|
+
@external_files ||= globs
|
60
|
+
.map { |glob| Dir["#{glob}.runfile"].sort }
|
61
|
+
.flatten
|
62
|
+
.to_h { |file| [File.basename(file, '.runfile'), Userfile.load_file(file)] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/runfile/runner.rb
CHANGED
@@ -1,183 +1,20 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require 'docopt'
|
3
|
-
|
4
1
|
module Runfile
|
5
|
-
|
6
|
-
# The Runner class is the main workhorse behind Runfile.
|
7
|
-
# It handles all the Runfile DSL commands and executes the
|
8
|
-
# Runfile with the help of two more specialized classes:
|
9
|
-
# 1. DocoptHelper - for deeper docopt related actions
|
10
|
-
# 2. RunfileHelper - for Runfile creation and system wide search
|
2
|
+
# Executes docopt.
|
11
3
|
class Runner
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
:params, :env_vars
|
18
|
-
|
19
|
-
# Initialize all variables to sensible defaults.
|
20
|
-
def initialize
|
21
|
-
@superspace = nil # used when filename != Runfile
|
22
|
-
@last_usage = nil # dsl: usage
|
23
|
-
@last_help = nil # dsl: help
|
24
|
-
@namespace = nil # dsl: command
|
25
|
-
@actions = {} # dsl: action
|
26
|
-
@options = {} # dsl: option
|
27
|
-
@params = {} # dsl: param
|
28
|
-
@examples = [] # dsl: example
|
29
|
-
@env_vars = {} # dsl: env_var
|
30
|
-
@name = "Runfile" # dsl: name
|
31
|
-
@version = false # dsl: version
|
32
|
-
@summary = false # dsl: summary
|
33
|
-
end
|
34
|
-
|
35
|
-
# Load and execute a Runfile call.
|
36
|
-
def execute(argv, filename='Runfile')
|
37
|
-
@ignore_settings = !filename
|
38
|
-
argv = expand_shortcuts argv
|
39
|
-
filename and File.file?(filename) or handle_no_runfile argv
|
40
|
-
|
41
|
-
begin
|
42
|
-
load settings.helper if settings.helper
|
43
|
-
load filename
|
44
|
-
rescue => ex
|
45
|
-
abort "Runfile error:\n#{ex.message}\n#{ex.backtrace[0]}"
|
46
|
-
end
|
47
|
-
run(*argv)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Add an action to the @actions array, and use the last known
|
51
|
-
# usage and help messages sent by the DSL.
|
52
|
-
def add_action(name, altname = nil, &block)
|
53
|
-
if @last_usage.nil?
|
54
|
-
@last_usage = altname ? "(#{name}|#{altname})" : name
|
55
|
-
end
|
56
|
-
[@namespace, @superspace].each do |prefix|
|
57
|
-
prefix or next
|
58
|
-
name = "#{prefix}_#{name}"
|
59
|
-
@last_usage = "#{prefix} #{last_usage}" unless @last_usage == false
|
60
|
-
end
|
61
|
-
name = name.to_sym
|
62
|
-
@actions[name] = Action.new(block, @last_usage, @last_help)
|
63
|
-
@last_usage = nil
|
64
|
-
@last_help = nil
|
65
|
-
if altname
|
66
|
-
@last_usage = false
|
67
|
-
add_action(altname, nil, &block)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Add an option flag and its help text.
|
72
|
-
def add_option(flag, text, scope = nil)
|
73
|
-
scope ||= 'Options'
|
74
|
-
@options[scope] ||= {}
|
75
|
-
@options[scope][flag] = text
|
76
|
-
end
|
77
|
-
|
78
|
-
# Add a patameter and its help text.
|
79
|
-
def add_param(name, text, scope = nil)
|
80
|
-
scope ||= 'Parameters'
|
81
|
-
@params[scope] ||= {}
|
82
|
-
@params[scope][name] = text
|
83
|
-
end
|
84
|
-
|
85
|
-
# Add env_var command.
|
86
|
-
def add_env_var(name, text, scope = nil)
|
87
|
-
scope ||= 'Environment Variables'
|
88
|
-
@env_vars[scope] ||= {}
|
89
|
-
@env_vars[scope][name] = text
|
90
|
-
end
|
91
|
-
|
92
|
-
# Add example command.
|
93
|
-
def add_example(command)
|
94
|
-
@examples << (@namespace ? "#{@namespace} #{command}" : command)
|
95
|
-
end
|
96
|
-
|
97
|
-
# Run the command. This is a wrapper around docopt. It will
|
98
|
-
# generate the docopt document on the fly, using all the
|
99
|
-
# information collected so far.
|
100
|
-
def run(*argv)
|
101
|
-
begin
|
102
|
-
docopt_exec argv
|
103
|
-
rescue Docopt::Exit => ex
|
104
|
-
puts ex.message
|
105
|
-
exit 2
|
4
|
+
class << self
|
5
|
+
def run(docopt, version: nil, argv: nil)
|
6
|
+
args = call_docopt docopt, argv: argv, version: version
|
7
|
+
yield args if block_given?
|
8
|
+
args
|
106
9
|
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Invoke action from another action. Used by the DSL's #execute
|
110
|
-
# function. Expects to get a single string that looks as if
|
111
|
-
# it was typed in the command prompt.
|
112
|
-
def cross_call(command_string)
|
113
|
-
argv = command_string.split(/\s(?=(?:[^"]|"[^"]*")*$)/)
|
114
|
-
begin
|
115
|
-
docopt_exec argv
|
116
|
-
rescue Docopt::Exit => ex
|
117
|
-
puts "Cross call failed: #{command_string}"
|
118
|
-
abort ex.message
|
119
|
-
end
|
120
|
-
end
|
121
10
|
|
122
11
|
private
|
123
12
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
def docopt_exec(argv)
|
129
|
-
helper = DocoptHelper.new(self)
|
130
|
-
args = helper.args argv
|
131
|
-
action = find_action argv
|
132
|
-
action or abort "Runfile error: Action not found"
|
133
|
-
@actions[action].execute args
|
134
|
-
end
|
135
|
-
|
136
|
-
# Inspect the first three arguments in the argv and look for
|
137
|
-
# a matching action.
|
138
|
-
# We will first look for a_b_c action, then for a_b and
|
139
|
-
# finally for a. This is intended to allow "overloading" of
|
140
|
-
# the command as an action (e.g. also allow a global action
|
141
|
-
# called 'a').
|
142
|
-
# if no command was found, but we have a :global command,
|
143
|
-
# assume this is the requested one (since we will not reach
|
144
|
-
# this point unless the usage pattern matches).
|
145
|
-
def find_action(argv)
|
146
|
-
3.downto(1).each do |count|
|
147
|
-
next unless argv.size >= count
|
148
|
-
action = argv[0..count-1].join('_').to_sym
|
149
|
-
return action if @actions.has_key? action
|
150
|
-
end
|
151
|
-
return :global if @actions.has_key? :global
|
152
|
-
return "#{superspace}_global".to_sym if @superspace and @actions.has_key? "#{superspace}_global".to_sym
|
153
|
-
return false
|
154
|
-
end
|
155
|
-
|
156
|
-
# When `run` is called without a Runfile (or runfile not
|
157
|
-
# found), hand over handling to the RunfileHelper class.
|
158
|
-
# If will either return false if no further handling is needed
|
159
|
-
# on our part, or the name of a runfile to execute.
|
160
|
-
def handle_no_runfile(argv)
|
161
|
-
maker = RunfileHelper.new
|
162
|
-
maker.purge_settings if @ignore_settings
|
163
|
-
runfile = maker.handle argv
|
164
|
-
|
165
|
-
exit 3 unless runfile
|
166
|
-
|
167
|
-
@superspace = argv[0]
|
168
|
-
execute argv, runfile
|
169
|
-
exit
|
170
|
-
end
|
171
|
-
|
172
|
-
def expand_shortcuts(argv)
|
173
|
-
possible_candidate = argv[0]
|
174
|
-
if settings.shortcuts and settings.shortcuts[possible_candidate]
|
175
|
-
shortcut_value = settings.shortcuts[argv[0]]
|
176
|
-
expanded = shortcut_value.split ' '
|
177
|
-
argv.shift
|
178
|
-
argv = expanded + argv
|
13
|
+
def call_docopt(docopt, version: nil, argv: nil)
|
14
|
+
Docopt.docopt docopt, argv: argv, version: version
|
15
|
+
rescue Docopt::Exit => e
|
16
|
+
raise ExitWithUsage, e.message
|
179
17
|
end
|
180
|
-
argv
|
181
18
|
end
|
182
19
|
end
|
183
20
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
title 'Greeter'
|
2
|
+
summary 'A sample runfile'
|
3
|
+
|
4
|
+
usage 'hello [NAME --shout]'
|
5
|
+
help 'Say hello'
|
6
|
+
option '--shout, -s', 'Greet louder'
|
7
|
+
action 'hello' do |args|
|
8
|
+
name = args['NAME'] || 'You...'
|
9
|
+
message = "Hello #{name}"
|
10
|
+
message = "#{message.upcase}!" if args['--shout']
|
11
|
+
|
12
|
+
say "gu`#{message}`"
|
13
|
+
end
|