-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruntime.sh
252 lines (222 loc) · 7.72 KB
/
runtime.sh
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
#!/usr/bin/env bash
source "$makesh_lib_dir"/message.sh
source "$makesh_lib_dir"/parseopts.sh
source "$makesh_lib_dir"/lib.sh
# Generates a completion script for the current makesh file.
# The completion is only valid when used in the same directory as the script.
_completion() {
cat <<EOF
# Run this in your terminal:
# source <(./$(basename "$0") --completion)
_makesh() {
local cur prev words cword
_init_completion -s || return
_targets=\$(sed -nE "s/^make::(.*)\(\)\s+\{$/\1/p" "$(basename "$0")")
_options="--completion --help --list --update --version --force \$_targets"
COMPREPLY=( \$(compgen -W "\$_options" -- "\$cur") )
if [ "\$prev" = "--force" ] || [ "\$prev" = "--help" ]; then
COMPREPLY=( \$(compgen -W "\$_targets" -- "\$cur") )
fi
}
complete -o default -F _makesh $(basename "$0")
EOF
}
# Prints script usage and defined targets
_usage() {
local _targets
_targets=$(compgen -A "function" | sed -nE "s/^make::(.*)$/\1/p" | sort | tr '\n' ' ')
cat <<EOF
./$(basename "$0") - makesh-enabled build script
Usage: $0 [options] <target>
Targets: $_targets
Options:
-f
--force <N>
force the target to run even if files have already been built.
Can be called multiple (N) times and will set \$makesh_force to N, e.g.:
./$(basename "$0") -fffff
Or, using the long flag:
./$(basename "$0") --force 5
-l, --list
shows a list of all defined targets and their help message, if present.
-u, --update
update makesh to the latest commit (updates git submodules).
-c, --completion
generates Bash completion commands for the current terminal.
Requires bash-completion to be installed.
The output needs to be sourced manually:
source <(./$(basename "$0") --completion)
-v, --version
prints the current version and other informations on makesh.
-h, --help
display this help message or target-specific help (--help <target>).
EOF
}
# Shows help/documentation for a specific target
# Documentation syntax (ignore first #):
# #:(<target name>) <documentation>
# #:(<target name>) <other line of documentation>
_target_help() {
local _help
# Get line with a specific comment and use it as documentation
# Look for lines starting with `#:(<target>)`
_help=$(sed -nE "s/^#:\(($1)\)\s+(.*)$/\2/p" "$makesh_script")
msg::msg "make::%s" "$1"
# Print all lines with plain()
IFS=$'\n'; for _line in $_help; do
msg::plain "%s" "$_line"
done
}
# Lists targets and their help comments
_target_list() {
msg::msg "Listing targets"
_targets=$(compgen -A "function" | sed -nE "s/^make::(.*)$/\1/p")
for _target in $_targets; do
_target_help "$_target"
done
}
# Returns true if the given function exists in the current scope
_is_func() {
declare -F -- "$1" >/dev/null
}
# Prints formatted version information
_version() {
msg::msg "Version"
local _tag
pushd "$makesh_lib_dir" >/dev/null || exit 1
if _tag=$(git describe --exact-match 2>/dev/null); then
msg::msg2 "Version: $_tag"
fi
msg::plain "%-10sr%s.%s" "Revision:" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
msg::plain "%-10s%s" "Commit:" "$(git rev-parse HEAD)"
msg::plain "%-10s%s" "Date:" "$(git show -s --format="%ci")"
msg::plain "%-10s%s" "Branch:" "$(git rev-parse --abbrev-ref HEAD)"
popd >/dev/null || exit 1
}
{
# Colors
msg::colorize
# Root is bad
if [ "$EUID" = 0 ]; then
msg::die "Don't run this script as root!"
fi
# Parse command line options
OPT_SHORT="cfh?luv"
OPT_LONG=("completion" "force:" "help?" "list" "update" "version")
if ! lib::parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then
msg::die "Error parsing command line. Use --help to see CLI usage."
fi
set -- "${OPTRET[@]}"
unset OPT_SHORT OPT_LONG OPTRET
declare \
makesh_completion \
makesh_help \
makesh_list \
makesh_update \
makesh_version
while true; do
case "$1" in
-c|--completion) makesh_completion=1 ;;
-f) (( makesh_force++ )) ;;
--force) shift; makesh_force="$1" ;;
-h|--help) makesh_help=1 ;;
-l|--list) makesh_list=1 ;;
-u|--update) makesh_update=1 ;;
-v|--version) makesh_version=1 ;;
--) shift; break 2 ;;
esac
shift
done
# Exit if --force was given anything other than a number
case $makesh_force in
''|*[!0-9]*) msg::die "Invalid value passed to --force: %s" "$makesh_force" ;;
esac
# No targets were passed from command line
if [ "$#" = 0 ]; then
# Generate completion script
if (( makesh_completion )); then
_completion
exit 0
fi
# Show version information
if (( makesh_version )); then
_version
exit 0
fi
# Allow calling just --help
if (( makesh_help )); then
_usage
exit 0
fi
# Show the target list
if (( makesh_list )); then
_target_list
exit 0
fi
# Update git submodules if --update was used
if (( makesh_update )); then
_submodule="$(basename "$makesh_lib_dir")"
msg::msg "Updating makesh (submodule \"$_submodule\")"
git submodule sync "$_submodule" && \
git submodule update --remote --progress "$_submodule"
exit 0
fi
# Suppose a make::all target exists. Set $1 to "all" to run it later
set -- "all" "$@"
# If make::all does not exist after all, print help and exit
if ! _is_func make::all; then
msg::error "Target not specified (and default target make::all not defined)!"
_usage
exit 1
fi
fi
# Special targets
case "$1" in
# "help" is not a target but we know what the user meant
# (unless make::help actually exists)
help)
if ! _is_func make::help; then
msg::error "Target 'help' does not exist (use --help)! Showing help anyways."
_usage
exit 1
fi
;;
# Special case for make::clean, clean cache unless explicitly disabled.
# Will also always run without errors, even if make::clean does not exist
clean)
# If a make::clean target does not exist, create one
if ! _is_func make::clean; then
# shellcheck disable=SC2317
make::clean() {
(( makesh_enable_cache_autoclean )) && lib::clean_cache
}
else
# Otherwise, just clean the cache before running it
(( makesh_enable_cache_autoclean )) && lib::clean_cache
fi
;;
# Catch-all for normal targets
*)
# Exit if target does not exist (checks if function is defined)
if ! _is_func make::"$1"; then
msg::error "Unknown target: $1"
# Give a tip if the given command line argument starts with "make::"
[[ $1 = make::* ]] && msg::plain "Did you mean '%s'?" "${1#"make::"}"
exit 1
fi
;;
esac
# Show help for target if --help <target> was used
if (( makesh_help )); then
_target_help "$1"
exit 0
fi
# Run the actual target
if (( makesh_force )); then
msg::msg "Running target make::$1 with %d force" "$makesh_force"
else
msg::msg "Running target make::$1"
fi
make::"$1"
exit 0
}