benry-actionrunner 0.1.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 +7 -0
- data/CHANGES.md +8 -0
- data/MIT-LICENSE +21 -0
- data/README.md +764 -0
- data/benry-actionrunner.gemspec +38 -0
- data/bin/arun +7 -0
- data/lib/benry/actionrunner.rb +556 -0
- data/test/app_test.rb +425 -0
- data/test/brownie_test.rb +206 -0
- data/test/help_test.rb +33 -0
- data/test/main_test.rb +322 -0
- data/test/run_all.rb +6 -0
- data/test/shared.rb +92 -0
- metadata +105 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "benry-actionrunner"
|
5
|
+
spec.version = "$Release: 0.1.0 $".split()[1]
|
6
|
+
spec.author = "kwatch"
|
7
|
+
spec.email = "kwatch@gmail.com"
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.homepage = "https://kwatch.github.io/benry-ruby/benry-actionrunner.html"
|
10
|
+
spec.summary = "Action runner or Task runner, like Rake or Gulp."
|
11
|
+
spec.description = <<-"END"
|
12
|
+
Benry-ActionRunner is a Action runner or Task runner, like Rake or Gulp.
|
13
|
+
|
14
|
+
Compared to Rake, actions of Benry-ActionRunner can take their own options and arguments.
|
15
|
+
For example, `arun hello --lang=fr Alice` runs `hello` action with an option `--lang=fr` and an argument `Alice`.
|
16
|
+
|
17
|
+
Benry-ActionRunner is also an example application of Benry-CmdApp framework.
|
18
|
+
|
19
|
+
See #{spec.homepage} for details.
|
20
|
+
END
|
21
|
+
spec.license = "MIT"
|
22
|
+
spec.files = Dir[
|
23
|
+
"README.md", "MIT-LICENSE", "CHANGES.md",
|
24
|
+
"#{spec.name}.gemspec",
|
25
|
+
"lib/**/*.rb", "test/**/*.rb", "bin/*",
|
26
|
+
#"doc/*.html", "doc/css/*.css",
|
27
|
+
]
|
28
|
+
#spec.executables = []
|
29
|
+
spec.bindir = "bin"
|
30
|
+
spec.require_path = "lib"
|
31
|
+
spec.test_file = "test/run_all.rb"
|
32
|
+
#spec.extra_rdoc_files = ["README.md", "CHANGES.md"]
|
33
|
+
|
34
|
+
spec.required_ruby_version = ">= 2.3"
|
35
|
+
spec.add_runtime_dependency "benry-cmdapp" , "~> 1"
|
36
|
+
spec.add_runtime_dependency "benry-unixcommand" , "~> 1"
|
37
|
+
spec.add_development_dependency "oktest" , "~> 1"
|
38
|
+
end
|
data/bin/arun
ADDED
@@ -0,0 +1,556 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
###
|
5
|
+
### $Release: 0.1.0 $
|
6
|
+
### $Copyright: copyright(c) 2023 kwatch@gmail.com $
|
7
|
+
### $License: MIT License $
|
8
|
+
###
|
9
|
+
|
10
|
+
|
11
|
+
require 'benry/cmdapp'
|
12
|
+
require 'benry/unixcommand'
|
13
|
+
|
14
|
+
|
15
|
+
#$DRYRUN_MODE = false
|
16
|
+
|
17
|
+
|
18
|
+
module Benry::ActionRunner
|
19
|
+
|
20
|
+
|
21
|
+
VERSION = "$Release: 0.1.0 $".split()[1]
|
22
|
+
DOCUMENT_URL = "https://kwatch.github.io/benry-ruby/benry-actionrunner.html"
|
23
|
+
DEFAULT_FILENAME = "Actionfile.rb"
|
24
|
+
|
25
|
+
|
26
|
+
class Action < Benry::CmdApp::Action
|
27
|
+
include Benry::UnixCommand
|
28
|
+
|
29
|
+
#def prompt()
|
30
|
+
# return "[#{CONFIG.app_command}]$ "
|
31
|
+
#end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
app_desc = "Action runner (or task runner), much better than Rake"
|
37
|
+
CONFIG = Benry::CmdApp::Config.new(app_desc, VERSION).tap do |config|
|
38
|
+
action_file = DEFAULT_FILENAME
|
39
|
+
command = File.basename($0)
|
40
|
+
config.app_command = command
|
41
|
+
#config.app_detail = nil
|
42
|
+
x = command
|
43
|
+
example = <<END
|
44
|
+
$ #{x} -h | less # print help message
|
45
|
+
$ #{x} -g # generate action file ('#{action_file}')
|
46
|
+
$ less #{action_file} # confirm action file
|
47
|
+
$ #{x} # list actions (or: `#{x} -l`)
|
48
|
+
$ #{x} -h hello # show help message for 'hello' action
|
49
|
+
$ #{x} hello Alice # run 'hello' action with arguments
|
50
|
+
Hello, Alice!
|
51
|
+
$ #{x} hello Alice -l fr # run 'hello' action with args and options
|
52
|
+
Bonjour, Alice!
|
53
|
+
$ #{x} : # list prefixes of actions (or '::', ':::')
|
54
|
+
$ #{x} xxxx: # list actions starting with 'xxxx:'
|
55
|
+
END
|
56
|
+
config.help_postamble = {
|
57
|
+
"Example:" => example,
|
58
|
+
"Document:" => " #{DOCUMENT_URL}\n",
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
GLOBAL_OPTION_SCHEMA = Benry::CmdApp::GLOBAL_OPTION_SCHEMA_CLASS.new(nil).tap do |schema|
|
64
|
+
topics = ["action", "actions", "alias", "aliases",
|
65
|
+
"category", "categories", "abbrev", "abbrevs",
|
66
|
+
"category1", "categories1", "category2", "categories2",
|
67
|
+
"category3", "categories3", "category4", "categories4",
|
68
|
+
"metadata"]
|
69
|
+
schema.add(:help , "-h, --help", "print help message (of action if specified)")
|
70
|
+
schema.add(:version , "-V" , "print version")
|
71
|
+
schema.add(:list , "-l" , "list actions")
|
72
|
+
schema.add(:topic , "-L <topic>", "topic list (actions|aliases|prefixes|abbrevs)", enum: topics)
|
73
|
+
schema.add(:all , "-a" , "list all actions/options including hidden ones")
|
74
|
+
schema.add(:file , "-f <file>" , "actionfile name (default: '#{DEFAULT_FILENAME}')")
|
75
|
+
schema.add(:search , "-u" , "search for actionfile in parent or upper dir")
|
76
|
+
schema.add(:chdir , "-w" , "change current dir to where action file exists")
|
77
|
+
schema.add(:searchdir, "-s" , "same as '-up'", hidden: true)
|
78
|
+
schema.add(:generate , "-g" , "generate actionfile ('#{DEFAULT_FILENAME}') with example code")
|
79
|
+
schema.add(:verbose , "-v" , "verbose mode")
|
80
|
+
schema.add(:quiet , "-q" , "quiet mode")
|
81
|
+
schema.add(:color , "-c" , "enable color mode")
|
82
|
+
schema.add(:nocolor , "-C" , "disable color mode")
|
83
|
+
schema.add(:debug , "-D" , "debug mode")
|
84
|
+
schema.add(:trace , "-T" , "trace mode")
|
85
|
+
schema.add(:dryrun , "-X" , "dry-run mode (not run; just echoback)")
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
module ApplicationHelpBuilderModule
|
90
|
+
def section_options(*args, **kwargs)
|
91
|
+
#; [!xsfzi] adds '--<name>=<value>' to help message.
|
92
|
+
arr = ["--<name>=<value>", "set a global variable (value can be in JSON format)"]
|
93
|
+
s = super
|
94
|
+
s += (@config.format_option % arr) + "\n"
|
95
|
+
return s
|
96
|
+
end
|
97
|
+
end
|
98
|
+
Benry::CmdApp::APPLICATION_HELP_BUILDER_CLASS.prepend(ApplicationHelpBuilderModule)
|
99
|
+
|
100
|
+
|
101
|
+
class GlobalOptionParser < Benry::CmdApp::GLOBAL_OPTION_PARSER_CLASS
|
102
|
+
|
103
|
+
def initialize(schema, &callback)
|
104
|
+
super
|
105
|
+
@callback = callback
|
106
|
+
end
|
107
|
+
|
108
|
+
def handle_unknown_long_option(optstr, name, value)
|
109
|
+
return super if value == nil
|
110
|
+
return super if @callback == nil
|
111
|
+
@callback.call(name, value, optstr)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def self.main(argv=ARGV)
|
118
|
+
#; [!wmcup] handles '$ACRIONRUNNER_OPTION' value.
|
119
|
+
envstr = ENV["ACTIONRUNNER_OPTION"]
|
120
|
+
if envstr && ! envstr.empty?
|
121
|
+
argv = envstr.split() + argv
|
122
|
+
end
|
123
|
+
app = MainApplication.new(CONFIG, GLOBAL_OPTION_SCHEMA)
|
124
|
+
status_code = app.main(argv)
|
125
|
+
#; [!hujvl] returns status code.
|
126
|
+
return status_code
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
class MainApplication < Benry::CmdApp::Application
|
131
|
+
|
132
|
+
def initialize(*args, **kwargs)
|
133
|
+
super
|
134
|
+
@flag_search = false # true when '-s' option specified
|
135
|
+
@flag_chdir = false # true when '-w' option specified
|
136
|
+
@action_file = DEFAULT_FILENAME # ex: 'Actionfile.rb'
|
137
|
+
@global_vars = {} # names and values of global vars
|
138
|
+
@_loaded = false # true when action file loaded
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
def parse_global_options(args)
|
144
|
+
#; [!bpedh] parses `--<name>=<val>` as global variables.
|
145
|
+
@global_vars = {}
|
146
|
+
parser = GlobalOptionParser.new(@option_schema) do |name, value, _optstr|
|
147
|
+
@global_vars[name] = value
|
148
|
+
end
|
149
|
+
#; [!0tz4j] stops parsing options when any argument found.
|
150
|
+
global_opts = parser.parse(args, all: false) # raises OptionError
|
151
|
+
#; [!gkp9b] returns global options.
|
152
|
+
return global_opts
|
153
|
+
end
|
154
|
+
|
155
|
+
def toggle_global_options(global_opts) # override
|
156
|
+
#; [!3kdds] global option '-C' sets `$COLOR_mode = false`.
|
157
|
+
global_opts[:color] = false if global_opts[:nocolor]
|
158
|
+
super
|
159
|
+
d = global_opts
|
160
|
+
#; [!1882x] global option '-u' sets instance var.
|
161
|
+
#; [!bokge] global option '-w' sets instance var.
|
162
|
+
@flag_search = true if d[:search] || d[:searchdir]
|
163
|
+
@flag_chdir = true if d[:chdir] || d[:searchdir]
|
164
|
+
#; [!4sk24] global option '-f' changes filename.
|
165
|
+
@action_file = d[:file] if d[:file]
|
166
|
+
#; [!9u400] sets `$BENRY_ECHOBACK = true` if option `-v` specified.
|
167
|
+
#; [!jp2mw] sets `$BENRY_ECHOBACK = false` if option `-q` specified.
|
168
|
+
$BENRY_ECHOBACK = true if d[:verbose]
|
169
|
+
$BENRY_ECHOBACK = false if d[:quiet]
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
|
173
|
+
def handle_global_options(global_opts, args) # override
|
174
|
+
#; [!psrmp] loads action file (if exists) before displaying help message.
|
175
|
+
if global_opts[:help]
|
176
|
+
load_action_file(required: false)
|
177
|
+
return super
|
178
|
+
end
|
179
|
+
#; [!9wfaw] loads action file before listing actions by '-l' or '-L' option.
|
180
|
+
#; [!qanx2] option '-l' and '-L' requires action file.
|
181
|
+
if global_opts[:list] || global_opts[:topic]
|
182
|
+
load_action_file(required: true)
|
183
|
+
return super
|
184
|
+
end
|
185
|
+
#; [!7995e] option '-g' generates action file.
|
186
|
+
if global_opts[:generate]
|
187
|
+
generate_action_file()
|
188
|
+
return 0
|
189
|
+
end
|
190
|
+
#; [!k5nuk] option '-h' or '--help' prints help message.
|
191
|
+
#; [!dmxt2] option '-V' prints version number.
|
192
|
+
#; [!i4qm5] option '-v' sets `$VERBOSE_MODE = true`.
|
193
|
+
#; [!5nwnv] option '-q' sets `$QUIET_MODE = true`.
|
194
|
+
#; [!klxkr] option '-c' sets `$COLOR_MODE = true`.
|
195
|
+
#; [!kqbwd] option '-C' sets `$COLOR_MODE = false`.
|
196
|
+
#; [!oce46] option '-D' sets `$DEBUG_MODE = true`.
|
197
|
+
#; [!mq5ko] option '-T' enables trace mode.
|
198
|
+
#; [!jwah3] option '-X' sets `$DRYRUN_MODE = true`.
|
199
|
+
return super
|
200
|
+
end
|
201
|
+
|
202
|
+
def handle_action(args, global_opts)
|
203
|
+
#; [!qdrui] loads action file before performing actions.
|
204
|
+
#; [!4992c] raises error if action specified but action file not exist.
|
205
|
+
load_action_file(required: (args[0] != "help"))
|
206
|
+
return super
|
207
|
+
end
|
208
|
+
|
209
|
+
def skip_backtrace?(bt) # override
|
210
|
+
#; [!k8ddu] ignores backtrace of 'actionrunner.rb'.
|
211
|
+
#; [!89mz3] ignores backtrace of 'kernel_require.rb'.
|
212
|
+
#; [!ttt98] ignores backtrace of 'arun'.
|
213
|
+
return true if bt.include?(__FILE__)
|
214
|
+
return true if bt.include?('/core_ext/kernel_require.rb')
|
215
|
+
return true if bt.include?('/arun:')
|
216
|
+
#; [!z72yj] not ignore backtrace of others.
|
217
|
+
return false
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def load_action_file(required: true)
|
223
|
+
#; [!nx22j] returns false if action file already loaded.
|
224
|
+
return false if @_loaded
|
225
|
+
#; [!aov55] loads action file if exists.
|
226
|
+
filename = @action_file or raise "** internal error"
|
227
|
+
brownie = Brownie.new(@config)
|
228
|
+
filepath = brownie.search_and_load_action_file(filename, @flag_search, @flag_chdir)
|
229
|
+
#; [!ssmww] raises error when `required: true` and action file not exist.
|
230
|
+
filepath != nil || ! required or
|
231
|
+
raise Benry::CmdApp::CommandError,
|
232
|
+
"Action file ('#{filename}') not found." \
|
233
|
+
" Create it by `#{@config.app_command} -g` command firstly."
|
234
|
+
#; [!vwtwe] it is AFTER loading action file to set global variables.
|
235
|
+
brownie.populate_global_variables(@global_vars)
|
236
|
+
@global_vars.clear()
|
237
|
+
#; [!8i55a] prevents to load action file more than once.
|
238
|
+
@_loaded = true
|
239
|
+
#; [!f68yv] returns true if action file loaded successfully.
|
240
|
+
return true
|
241
|
+
end
|
242
|
+
|
243
|
+
def generate_action_file(quiet: $QUIET_MODE)
|
244
|
+
#; [!dta7r] generates action file.
|
245
|
+
filename = @action_file or raise "** internal error"
|
246
|
+
brownie = Brownie.new(@config)
|
247
|
+
content = brownie.render_action_file_content(filename)
|
248
|
+
#; [!tmlqt] prints action file content if filename is '-'.
|
249
|
+
#; [!ymrjh] prints action file content if stdout is not a tty.
|
250
|
+
if filename == "-" || ! $stdout.tty?
|
251
|
+
print content
|
252
|
+
#; [!9e3c0] returns nil if action file is not generated.
|
253
|
+
return nil
|
254
|
+
end
|
255
|
+
#; [!685cq] raises error if action file already exist.
|
256
|
+
! File.exist?(filename) or
|
257
|
+
raise Benry::CmdApp::CommandError,
|
258
|
+
"Action file ('#{filename}') already exists." \
|
259
|
+
" If you want to generate a new one, delete it first."
|
260
|
+
File.write(filename, content, encoding: 'utf-8')
|
261
|
+
#; [!n09pl] reports result if action file generated successfully.
|
262
|
+
#; [!iq0p2] reports nothing if option '-q' specified.
|
263
|
+
puts "[OK] Action file '#{filename}' generated." unless quiet
|
264
|
+
#; [!bf60l] returns action file name if generated.
|
265
|
+
return filename
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
class Brownie
|
272
|
+
|
273
|
+
def initialize(config)
|
274
|
+
@config = config
|
275
|
+
end
|
276
|
+
|
277
|
+
def search_and_load_action_file(filename, flag_search, flag_chdir, _pwd: Dir.pwd())
|
278
|
+
#; [!c9e1h] if action file exists in current dir, load it regardless of options.
|
279
|
+
#; [!m5oj7] if action file exists in parent dir, find and load it if option '-s' specified.
|
280
|
+
if File.exist?(filename) ; dir = "."
|
281
|
+
elsif flag_search ; dir = _search_dir_where_file_exist(filename, _pwd)
|
282
|
+
else ; dir = nil
|
283
|
+
end
|
284
|
+
#; [!079xs] returns nil if action file not found.
|
285
|
+
#; [!7simq] changes current dir to where action file exists if option '-w' specified.
|
286
|
+
#; [!dg2qv] action file can has directory path.
|
287
|
+
if dir == nil ; return nil
|
288
|
+
elsif dir == "." ; fpath = filename
|
289
|
+
elsif flag_chdir ; fpath = filename ; _chdir(dir)
|
290
|
+
else ; fpath = File.join(dir, filename)
|
291
|
+
end
|
292
|
+
#; [!d987b] loads action file if exists.
|
293
|
+
abspath = File.absolute_path(fpath)
|
294
|
+
require abspath
|
295
|
+
#; [!x9xxl] returns absolute path of action file if exists.
|
296
|
+
return abspath
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
|
301
|
+
def _search_dir_where_file_exist(filename, dir=Dir.pwd(), max=20)
|
302
|
+
n = -1
|
303
|
+
found = while (n += 1) < max
|
304
|
+
break true if File.exist?(File.join(dir, filename))
|
305
|
+
parent = File.dirname(dir)
|
306
|
+
break false if parent == dir
|
307
|
+
dir = parent
|
308
|
+
end
|
309
|
+
return nil unless found
|
310
|
+
return "." if n == 0
|
311
|
+
return ".." if n == 1
|
312
|
+
return ("../" * n).chomp("/")
|
313
|
+
end
|
314
|
+
|
315
|
+
def _chdir(dir)
|
316
|
+
Action.new(@config).instance_eval { cd(dir) }
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
|
320
|
+
public
|
321
|
+
|
322
|
+
def populate_global_variables(global_vars)
|
323
|
+
#; [!cr2ph] sets global variables.
|
324
|
+
#; [!3kow3] normalizes global variable names.
|
325
|
+
#; [!03x7t] decodes JSON string into Ruby object.
|
326
|
+
#; [!1ol4a] print global variables if debug mode is on.
|
327
|
+
global_vars.each do |name, str|
|
328
|
+
var = name.gsub(/[^\w]/, '_')
|
329
|
+
val = _decode_value(str)
|
330
|
+
eval "$#{var} = #{val.inspect}"
|
331
|
+
_debug_global_var(var, val) if $DEBUG_MODE
|
332
|
+
end
|
333
|
+
nil
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def _decode_value(str)
|
339
|
+
#; [!omxyf] decodes string as JSON format.
|
340
|
+
require 'json' unless defined?(JSON)
|
341
|
+
return JSON.load(str)
|
342
|
+
rescue JSON::ParserError
|
343
|
+
#; [!tvwvn] returns string as it is if failed to parse as JSON.
|
344
|
+
return str
|
345
|
+
end
|
346
|
+
|
347
|
+
def _debug_global_var(var, val)
|
348
|
+
#; [!05l5f] prints var name and it's value.
|
349
|
+
#; [!7lwvz] colorizes output if color mode enabled.
|
350
|
+
msg = "[DEBUG] $#{var} = #{val.inspect}"
|
351
|
+
msg = @config.deco_debug % msg if Benry::CmdApp::Util.color_mode?
|
352
|
+
puts msg
|
353
|
+
$stdout.flush()
|
354
|
+
end
|
355
|
+
|
356
|
+
public
|
357
|
+
|
358
|
+
def render_action_file_content(filename)
|
359
|
+
#; [!oc03q] returns content of action file.
|
360
|
+
#content = DATA.read()
|
361
|
+
content = File.read(__FILE__, encoding: 'utf-8').split(/\n__END__\n/)[-1]
|
362
|
+
content = content.gsub('%COMMAND%', @config.app_command)
|
363
|
+
content = content.gsub('%ACTIONFILE%', filename)
|
364
|
+
return content
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
module Export
|
371
|
+
|
372
|
+
CONFIG = Benry::ActionRunner::CONFIG
|
373
|
+
Action = Benry::ActionRunner::Action
|
374
|
+
|
375
|
+
module_function
|
376
|
+
|
377
|
+
def define_alias(alias_name, action_name, tag: nil, important: nil, hidden: nil)
|
378
|
+
return Benry::CmdApp.define_alias(alias_name, action_name, tag: tag, important: important, hidden: hidden)
|
379
|
+
end
|
380
|
+
|
381
|
+
def undef_alias(alias_name)
|
382
|
+
return Benry::CmdApp.undef_alias(alias_name)
|
383
|
+
end
|
384
|
+
|
385
|
+
def undef_action(action_name)
|
386
|
+
return Benry::CmdApp.undef_action(action_name)
|
387
|
+
end
|
388
|
+
|
389
|
+
def define_abbrev(abbrev, prefix)
|
390
|
+
return Benry::CmdApp.define_abbrev(abbrev, prefix)
|
391
|
+
end
|
392
|
+
|
393
|
+
def undef_abbrev(abbrev)
|
394
|
+
return Benry::CmdApp.undef_abbrev(abbrev)
|
395
|
+
end
|
396
|
+
|
397
|
+
def current_app()
|
398
|
+
return Benry::CmdApp.current_app()
|
399
|
+
end
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
|
404
|
+
end
|
405
|
+
|
406
|
+
|
407
|
+
if __FILE__ == $0
|
408
|
+
exit Benry::ActionRunner.main()
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
__END__
|
413
|
+
# -*- coding: utf-8 -*-
|
414
|
+
# frozen_string_literal: true
|
415
|
+
|
416
|
+
|
417
|
+
##
|
418
|
+
## @(#) Action file for '%COMMAND%' command.
|
419
|
+
##
|
420
|
+
## Example:
|
421
|
+
##
|
422
|
+
## $ %COMMAND% -h | less # print help message
|
423
|
+
## $ %COMMAND% -g # generate action file ('%ACTIONFILE%')
|
424
|
+
## $ less %ACTIONFILE% # confirm action file
|
425
|
+
## $ %COMMAND% # list actions (or: `%COMMAND% -l`)
|
426
|
+
##
|
427
|
+
## $ %COMMAND% -h hello # show help message for 'hello' action
|
428
|
+
## $ %COMMAND% hello Alice # run 'hello' action with arguments
|
429
|
+
## Hello, Alice!
|
430
|
+
## $ %COMMAND% hello -l fr # run 'hello' action with options
|
431
|
+
## Bonjour, world!
|
432
|
+
##
|
433
|
+
## $ %COMMAND% : # list prefixes of actions (or '::', ':::', etc)
|
434
|
+
## $ %COMMAND% git: # list actions filtered by prefix "git:"
|
435
|
+
## $ %COMMAND% git # run 'git' action (or alias)
|
436
|
+
##
|
437
|
+
|
438
|
+
|
439
|
+
require 'benry/actionrunner'
|
440
|
+
|
441
|
+
include Benry::ActionRunner::Export
|
442
|
+
|
443
|
+
|
444
|
+
##
|
445
|
+
## Define actions
|
446
|
+
##
|
447
|
+
class MyAction < Action
|
448
|
+
|
449
|
+
@action.("print greeting message")
|
450
|
+
@option.(:lang, "-l, --lang=<lang>", "language (en/fr/it)")
|
451
|
+
def hello(name="world", lang: "en")
|
452
|
+
case lang
|
453
|
+
when "en" ; puts "Hello, #{name}!"
|
454
|
+
when "fr" ; puts "Bonjour, #{name}!"
|
455
|
+
when "it" ; puts "Chao, #{name}!"
|
456
|
+
else
|
457
|
+
raise "#{lang}: Unknown language."
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
@action.("delete garbage files (and product files too if '-a')")
|
462
|
+
@option.(:all, "-a, --all", "delete product files, too")
|
463
|
+
def clean(all: false)
|
464
|
+
rm :rf, GARBAGE_FILES if ! GARBAGE_FILES.empty?
|
465
|
+
rm :rf, PRODUCT_FILES if ! PRODUCT_FILES.empty? && all == true
|
466
|
+
end
|
467
|
+
|
468
|
+
end
|
469
|
+
|
470
|
+
GARBAGE_FILES = ["*~", "*.tmp"] # will be deleted by `arun clean`
|
471
|
+
PRODUCT_FILES = ["*.gem"] # will be deleted by `arun clean --all`
|
472
|
+
|
473
|
+
|
474
|
+
##
|
475
|
+
## Define action with prefix ('git:')
|
476
|
+
##
|
477
|
+
class GitAction < Action
|
478
|
+
#prefix "git:"
|
479
|
+
#prefix "git:", action: "status:here" # rename 'git:status:here' action to 'git'
|
480
|
+
category "git:", alias_for: "status:here" # define 'git' as an alias of 'git:status:here' action
|
481
|
+
|
482
|
+
@action.("show status in compact format")
|
483
|
+
def status(*files)
|
484
|
+
sys "git status -sb #{files.join(' ')}"
|
485
|
+
end
|
486
|
+
|
487
|
+
@action.("show status of current directory")
|
488
|
+
def status__here() # method name 'x__y__z' => action name 'x:y:z'
|
489
|
+
sys "git status -sb ."
|
490
|
+
end
|
491
|
+
|
492
|
+
@action.("put changes of files into staging area")
|
493
|
+
@option.(:interactive, "-i", "select changes interactively")
|
494
|
+
def stage(file, *files, interactive: false)
|
495
|
+
opts = []
|
496
|
+
opts << " -i" if interactive
|
497
|
+
sys "git add#{opts.join(' ')} #{file.join(' ')}"
|
498
|
+
end
|
499
|
+
|
500
|
+
@action.("show changes in staging area")
|
501
|
+
def staged()
|
502
|
+
sys "git diff --cached"
|
503
|
+
end
|
504
|
+
|
505
|
+
@action.("remove changes from staging area")
|
506
|
+
def unstage()
|
507
|
+
sys "git reset HEAD"
|
508
|
+
end
|
509
|
+
|
510
|
+
end
|
511
|
+
|
512
|
+
|
513
|
+
##
|
514
|
+
## Example of aliases
|
515
|
+
##
|
516
|
+
define_alias "stage" , "git:stage"
|
517
|
+
define_alias "staged" , "git:staged"
|
518
|
+
define_alias "unstage" , "git:unstage"
|
519
|
+
|
520
|
+
|
521
|
+
##
|
522
|
+
## More example
|
523
|
+
##
|
524
|
+
$project = "example"
|
525
|
+
$release = "1.0.0"
|
526
|
+
|
527
|
+
class BuildAction < Action
|
528
|
+
category "build:", action: "all"
|
529
|
+
#prefix "build:", alias_of: "all"
|
530
|
+
|
531
|
+
def target_name()
|
532
|
+
return "#{$project}-#{$release}"
|
533
|
+
end
|
534
|
+
|
535
|
+
## hidden action
|
536
|
+
@action.("prepare directory", hidden: true) # hidden action
|
537
|
+
def prepare()
|
538
|
+
dir = target_name()
|
539
|
+
mkdir dir unless File.directory?(dir)
|
540
|
+
end
|
541
|
+
|
542
|
+
@action.("create zip file")
|
543
|
+
def zip_() # last '_' char avoids to override existing method
|
544
|
+
run_once "prepare" # run prerequisite action only once
|
545
|
+
dir = target_name()
|
546
|
+
store "README.md", "Rakefile.rb", "lib/**/*", "test/**/*", to: dir
|
547
|
+
sys "zip -r #{dir}.zip #{dir}"
|
548
|
+
sys "unzip -l #{dir}.zip"
|
549
|
+
end
|
550
|
+
|
551
|
+
@action.("create all")
|
552
|
+
def all()
|
553
|
+
run_once "zip" # run prerequisite action only once
|
554
|
+
end
|
555
|
+
|
556
|
+
end
|