-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlua-helper.bash.in
348 lines (308 loc) · 12.3 KB
/
lua-helper.bash.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!/bin/bash
# source this script to provide read-access to global config variables exported from your lua script
# Copyright (c) 2016-2017 DarkCaster, MIT License, see https://github.com/DarkCaster/Bash-Lua-Helper for more info
#TODO: store all generated stuff not in temporary plain-text files, but somewhere else
lua_helper_dir="$( cd "$( dirname "$BASH_SOURCE" )" && pwd )"
lua_temp_dir=""
lua_startup_params=()
lua_startup_param_cnt=0
lua_params_shift=0
lua_result_name="cfg"
lua_export_list_name="cfg_list"
lua_add_param() {
lua_startup_params[$lua_startup_param_cnt]="$@"
lua_startup_param_cnt=$((lua_startup_param_cnt+1))
}
lua_helper_log_error () {
>&2 echo "$@"
}
lua_helper_teardown () {
[[ ! -z $lua_temp_dir ]] && rm -rf "$lua_temp_dir"
true
}
lua_helper_showusage () {
lua_helper_log_error ""
lua_helper_log_error "usage: . lua-helper.sh.in <main lua script> <options>"
lua_helper_log_error ""
lua_helper_log_error "mandatory options:"
lua_helper_log_error "-e <name> global variable from lua script to export (if variable is a table, this will export all fields recursively)"
lua_helper_log_error " you can pass multiple -e options"
lua_helper_log_error ""
lua_helper_log_error "other options:"
lua_helper_log_error "-b <pre script> lua script, that will be executed in context of loader.lua, just before main script"
lua_helper_log_error "-a <post script> lua script, that will be executed in context of loader.lua, after main script."
lua_helper_log_error " this script will have access to all global variables and context changes that main script has made"
lua_helper_log_error "-o <string> add extra user string to loader.extra table (indexed by number starting from 1). multiple options can be selected"
lua_helper_log_error "-w <dir> non default work directory. will be stored at loader.workdir. by default, config file base directory will be used"
lua_helper_log_error "-r <associative array name> name of associative array, that will contain all exported variables from lua script. by default will be used name \"cfg\""
lua_helper_log_error "-l <variable name> custom variable name that will contain list (multiline) of all exported variables. by default will be used name \"cfg_list\""
lua_helper_log_error "-x terminate command list for this script. all command line parameters after this option will be transferred to your lua config file,"
lua_helper_log_error " and will be stored in loader.args table starting from index 1"
lua_helper_log_error "-t <temp directory> manually set base directory for temporary files that lua-helper create while exporting selected lua variables."
lua_helper_log_error " this directory will be automatically detected if omited: it will probe XDG_RUNTIME_DIR, /tmp, and will use one that mounted on tmpfs"
lua_helper_log_error "-h show this help"
lua_helper_log_error ""
lua_helper_log_error "options to override lua binary detection logic."
lua_helper_log_error "by default, only supported lua versions at standard paths will be used."
lua_helper_log_error "for now it will search and use lua with versions from 5.2.0 to 5.3.999"
lua_helper_log_error "-y <version> enforce min lua version. if this option passed without Y option, it will not enforce max lua version (and print warning)"
lua_helper_log_error "-Y <version> enforce max lua version. if this option passed without y option, it will not enforce min lua version (and print warning)"
lua_helper_log_error "-z <path to lua binary> enforce path to lua binary, do not perform automatic search for lua binary."
lua_helper_teardown
exit 100
}
lua_helper_check_bad_chars () {
local target="$1"
local msg_pre="$2"
# used conventions from here: https://www.lua.org/pil/1.3.html
# but letters restricted to latin
if [[ ! -z $target && $target =~ ^[a-zA-Z_][a-zA-Z_0-9.]*$ ]]; then
return 0
else
lua_helper_log_error "$msg_pre contain characters restricted for use with lua"
lua_helper_teardown
exit 1
fi
}
lua_helper_check_bad_chars_bash () {
local target="$1"
local msg_pre="$2"
if [[ ! -z $target && $target =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]]; then
return 0
else
lua_helper_log_error "$msg_pre may only contain letters, numbers or underscores, and not start with number"
lua_helper_teardown
exit 1
fi
}
lua_config_script="$1"
[[ -z $lua_config_script ]] && lua_helper_showusage
[[ ! -e $lua_config_script ]] && lua_helper_log_error "main config file not found" && lua_helper_showusage
lua_config_script=`realpath -s "$lua_config_script"`
lua_workdir=`dirname "$lua_config_script"`
lua_add_param "-c"
lua_add_param "$lua_config_script"
shift 1
lua_binary=""
lua_min_version=""
lua_act_version=""
lua_helper_parseopts () {
local lua_pre_script=""
local lua_post_script=""
local optname
while getopts ":e:b:a:o:w:r:l:t:y:Y:z:hx" optname
do
case "$optname" in
"e")
lua_helper_check_bad_chars "$OPTARG" "exported global variable"
lua_add_param "-e"
lua_add_param "$OPTARG"
;;
"b")
[[ ! -z $lua_pre_script ]] && lua_helper_log_error "multiple -b options detected" && lua_helper_showusage
lua_pre_script="$OPTARG"
[[ ! -e $lua_pre_script ]] && lua_helper_log_error "pre script not found" && lua_helper_showusage
lua_add_param "-pre"
lua_add_param "$OPTARG"
;;
"a")
[[ ! -z $lua_post_script ]] && lua_helper_log_error "multiple -a options detected" && lua_helper_showusage
lua_post_script="$OPTARG"
[[ ! -e $lua_post_script ]] && lua_helper_log_error "post script not found" && lua_helper_showusage
lua_add_param "-post"
lua_add_param "$OPTARG"
;;
"o")
lua_add_param "-ext"
lua_add_param "$OPTARG"
;;
"w")
lua_workdir="$OPTARG"
;;
"r")
lua_helper_check_bad_chars_bash "$OPTARG" "result associative array name"
lua_result_name="$OPTARG"
;;
"l")
lua_helper_check_bad_chars_bash "$OPTARG" "export list variable name"
lua_export_list_name="$OPTARG"
;;
"t")
lua_temp_dir="$OPTARG"
[[ -z $lua_temp_dir || ! -d $lua_temp_dir ]] && lua_helper_log_error "incorrect base temp directory provided: $lua_temp_dir" && lua_temp_dir="" && lua_helper_showusage
;;
"y")
lua_min_version="$OPTARG"
;;
"Y")
lua_max_version="$OPTARG"
;;
"z")
lua_binary="$OPTARG"
;;
"x")
break
;;
"h")
lua_helper_showusage
;;
"?")
lua_helper_log_error "Unknown option $OPTARG"
lua_helper_showusage
;;
":")
lua_helper_log_error "No argument given for option $OPTARG"
lua_helper_showusage
;;
*)
# Should not occur
lua_helper_log_error "Unknown error while processing options"
lua_helper_showusage
;;
esac
done
lua_params_shift=$((OPTIND-1))
[[ -z $lua_workdir ]] && lua_helper_log_error "workdir is empty string" && lua_helper_showusage
lua_add_param "-w"
lua_add_param "$lua_workdir"
}
lua_helper_parseopts "$@"
shift $lua_params_shift
#temp directory
if [[ -z $lua_temp_dir ]]; then
#detect temp directory
for target in "$TMPDIR" "/tmp" "$XDG_RUNTIME_DIR"
do
[[ -z "$target" || ! -d $target || -z `2>/dev/null df -P -t tmpfs "$target"` ]] && continue
lua_temp_dir="$target"
break
done
[[ -z $lua_temp_dir ]] && lua_temp_dir="/tmp"
fi
#create real cache dir
lua_temp_dir=`2>/dev/null mktemp -d -p "$lua_temp_dir" -t "lua-helper-XXXXXX"`
[[ -z $lua_temp_dir ]] && lua_helper_log_error "Failed to create temp directory!" && exit 1
#create meta and data dir
mkdir "$lua_temp_dir/meta"
[[ $? != 0 ]] && lua_helper_log_error "Failed to create $lua_temp_dir/meta directory!" && exit 1
mkdir "$lua_temp_dir/data"
[[ $? != 0 ]] && lua_helper_log_error "Failed to create $lua_temp_dir/data directory!" && exit 1
lua_add_param "-t"
lua_add_param "$lua_temp_dir"
lua_add_param "--"
lua_probe_version() {
local lua_binary="$1"
local min_version=( $2 )
local max_version=( $3 )
[[ `2>&1 "$lua_binary" -v` =~ ^"Lua"[[:space:]]([0-9]*)"."([0-9]*)"."([0-9]*).*$ ]] && lua_act_version=( "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" ) || return 1
local cnt="-1"
for act_num in "${lua_act_version[@]}"
do
cnt=$((cnt+1))
[[ $act_num -ge ${min_version[$cnt]} && $act_num -le ${max_version[$cnt]} ]] && continue || return 1
done
return 0
}
lua_probe_binary() {
local hints=( $1 )
local min_version="$2"
local max_version="$3"
[[ ! -z $lua_binary ]] && hints=( "$lua_binary" ) && lua_binary=""
[[ $min_version =~ ^([0-9]*)"."([0-9]*)"."([0-9]*)$ ]] && min_version="${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]}" || min_version=""
[[ -z $min_version ]] && lua_helper_log_error "incorrect minimum version string! (it must be a 3 numbers delimited with dots, for example 5.2.0 or 5.3.1)" && exit 1
[[ $max_version =~ ^([0-9]*)"."([0-9]*)"."([0-9]*)$ ]] && max_version="${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]}" || max_version=""
[[ -z $max_version ]] && lua_helper_log_error "incorrect maximum version string! (it must be a 3 numbers delimited with dots, for example 5.2.0 or 5.3.1)" && exit 1
for hint in "${hints[@]}"
do
hint=`2>/dev/null which "$hint"`
#debug
#echo "probing lua binary: $hint"
if [[ ! -z $hint ]] && lua_probe_version "$hint" "$min_version" "$max_version"; then
lua_binary="$hint"
break
fi
done
}
if [[ -z $lua_min_version && -z $lua_max_version ]]; then
lua_min_version="5.1.0"
lua_max_version="5.4.999"
elif [[ -z $lua_min_version && ! -z $lua_max_version ]]; then
lua_min_version="0.0.0"
lua_helper_log_error "restricting lua max version only, it may not work as intended if your lua interpreter is too old"
elif [[ ! -z $lua_min_version && -z $lua_max_version ]]; then
lua_max_version="999.999.999"
lua_helper_log_error "restricting lua min version only, it may not work as intended if your lua interpreter is too new and not tested!"
fi
if [[ ! -z $lua_binary ]]; then
lua_helper_log_error "probing enforced lua binary at $lua_binary"
lua_hint="$lua_binary"
lua_binary=""
lua_probe_binary "$lua_hint" "$lua_min_version" "$lua_max_version"
else
lua_probe_binary "lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51" "$lua_min_version" "$lua_max_version"
fi
[[ -z $lua_binary ]] && lua_helper_log_error "failed to detect lua interpreter with proper version!" && exit 1
#debug
#echo "using lua binary: $lua_binary"
"$lua_binary" "$lua_helper_dir/loader.lua" -ver "${lua_act_version[@]}" "${lua_startup_params[@]}" "$@"
if [[ $? != 0 ]]; then
lua_helper_log_error "loader.lua script failed"
lua_helper_teardown
exit 1
fi
#create result associative array and fill it with global variables exported from lua config.
#see example.bash for usage details
declare -A "$lua_result_name"
#create associative array with metadata
declare -A "${lua_result_name}_meta"
#create list (multiline variable) with all exported variables names
declare -r "$lua_export_list_name"="`ls -1 \"$lua_temp_dir/data\"`"
if [[ ! -z ${!lua_export_list_name} ]]; then
while read target
do
#should not occur, if you not touching anything inside loader.tmpdir from lua scripts, so it is disabled
#lua_helper_check_bad_chars "$target" "filename with exported variable contents \"$target\""
IFS= read -d '' -r "$lua_result_name[$target]" < "$lua_temp_dir/data/$target"
IFS= read -d '' -r "${lua_result_name}_meta[$target]" < "$lua_temp_dir/meta/$target"
done <<< "${!lua_export_list_name}"
fi
lua_helper_teardown
#create helper function to check variable availability
eval 'check_lua_export() {
[[ ! -z "${'${lua_result_name}_meta'[$@]}" ]]
}'
# following line will fix highlight bug in atom editor
#### eval '''
eval 'get_lua_table_start() {
[[ "${'${lua_result_name}_meta'[$@]}" =~ ^table:(.*):(.*) ]] && echo "${BASH_REMATCH[1]}" || echo "0"
}'
# following line will fix highlight bug in atom editor
#### eval '''
eval 'get_lua_table_end() {
[[ "${'${lua_result_name}_meta'[$@]}" =~ ^table:(.*):(.*) ]] && echo "${BASH_REMATCH[2]}" || echo "0"
}'
# following line will fix highlight bug in atom editor
#### eval '''
#perform environment cleanup
unset -f lua_helper_parseopts
unset -f lua_helper_check_bad_chars
unset -f lua_helper_check_bad_chars_bash
unset -f lua_helper_showusage
unset -f lua_helper_teardown
unset -f lua_helper_log_error
unset -f lua_add_param
unset -f lua_probe_version
unset -f lua_probe_binary
unset lua_helper_dir
unset lua_temp_dir
unset lua_startup_params
unset lua_startup_param_cnt
unset lua_params_shift
unset lua_result_name
unset lua_export_list_name
unset lua_config_script
unset lua_workdir
unset lua_binary
unset lua_min_version
unset lua_max_version
unset lua_act_version