-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmerge-shell.sh
executable file
·106 lines (92 loc) · 3.42 KB
/
merge-shell.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
#!/bin/sh
VERSION=0.2.1
# our annotations only support ASCII
# the dot lines only support ASCII as well
export LC_ALL=C
if [ $# != 1 ]; then
cat <<EOF
usage: $0 <shell_script>
version: ${VERSION}
merge the specified shell script with its sub-scripts
scripts sourced immediately after a '# @MERGE' comment are merged, producing
one easily-deployable big script
this allows for modular shell script development:
- no need to open up a big script just to edit some small thing
- sub-scripts can be organized into directories
- script behaves (almost) exactly the same during development (without merging)
and after deployment / installation (after being merged and deployed)
notes on merged script:
- shebang and the empty line after it will be removed from sourced script
- the first empty line after the shebang will be removed
more annotations are available:
- @HEREDOC and @HEREDOC-END to wrap a here-document
- @MULTILINE and @MULTILINE-END to wrap a multi-line string
EOF
exit 1
fi
mergeshell() {
if [ "$3" -eq 0 ]; then
CHECK_SHEBANG=false
CHECK_EMPTY_LINE=false
else
CHECK_SHEBANG=true
CHECK_EMPTY_LINE=false
fi
if [ "$(tail -c 1 "$1")" != "$(printf '\n')" ]; then
echo "Warning: input file $1: no newline at end of file, last line in file will not be recognized" >&2
fi
MERGE=false
HEREDOC=false
MULTILINE=false
while IFS= read -r LINE; do
if "${CHECK_SHEBANG}" && expr "${LINE}" : '^#!.*$' >/dev/null; then
CHECK_SHEBANG=false
CHECK_EMPTY_LINE=true
elif "${CHECK_EMPTY_LINE}" && [ -z "${LINE}" ]; then
CHECK_EMPTY_LINE=false
else
CHECK_SHEBANG=false
CHECK_EMPTY_LINE=false
ANNOTATION="$(expr "${LINE}" : '^[[:space:]]*#[[:space:]]\{1,\}@\(MERGE\|HEREDOC\|HEREDOC-END\|MULTILINE\|MULTILINE-END\)[[:space:]]*$')"
if [ "${ANNOTATION}" = 'HEREDOC-END' ]; then
MERGE=false
HEREDOC=false
elif [ "${ANNOTATION}" = 'MULTILINE-END' ]; then
MERGE=false
MULTILINE=false
elif "${HEREDOC}"; then
MERGE=false
printf '%s%s\n' "${HEREDOC_INDENT}" "${LINE}"
HEREDOC_INDENT=
elif "${MULTILINE}"; then
MERGE=false
printf '%s%s\n' "${MULTILINE_INDENT}" "${LINE}"
MULTILINE_INDENT=
elif [ "${ANNOTATION}" = 'MERGE' ]; then
MERGE=true
elif "${MERGE}" && FILE="$(expr "${LINE}" : '^[[:space:]]*\.[[:space:]]\{1,\}\([[:alnum:]/_\.][[:alnum:]/_\.\-]\{1,\}\)[[:space:]]*$')"; then
MERGE=false
export FILE
export INDENT="$2""$(expr "${LINE}" : '^\([[:space:]]*\)\..*$')"
export LEVEL=$(($3 + 1))
(mergeshell "${FILE}" "${INDENT}" "${LEVEL}")
elif [ "${ANNOTATION}" = 'HEREDOC' ]; then
MERGE=false
HEREDOC=true
HEREDOC_INDENT="$2"
elif [ "${ANNOTATION}" = 'MULTILINE' ]; then
MERGE=false
MULTILINE=true
MULTILINE_INDENT="$2"
elif [ -z "${LINE}" ]; then
MERGE=false
echo
else
MERGE=false
printf '%s%s\n' "$2" "${LINE}"
fi
fi
done <"$1"
true
}
(mergeshell "$1" '' 0)