benry-actionrunner 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|