1# Assert that FILE exists and is executable
2#
3# assertExecutable FILE
4assertExecutable() {
5 local file="$1"
6 [[ -f "$file" && -x "$file" ]] || \
7 die "Cannot wrap '$file' because it is not an executable file"
8}
9
10# construct an executable file that wraps the actual executable
11# makeWrapper EXECUTABLE ARGS
12
13# ARGS:
14# --argv0 NAME : set name of executed process to NAME
15# (otherwise it’s called …-wrapped)
16# --set VAR VAL : add VAR with value VAL to the executable’s
17# environment
18# --set-default VAR VAL : like --set, but only adds VAR if not already set in
19# the environment
20# --unset VAR : remove VAR from the environment
21# --run COMMAND : run command before the executable
22# The command can push extra flags to a magic list
23# variable extraFlagsArray, which are then added to
24# the invocation of the executable
25# --add-flags FLAGS : add FLAGS to invocation of executable
26
27# --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP
28# --suffix
29# --suffix-each ENV SEP VALS : like --suffix, but VALS is a list
30# --prefix-contents ENV SEP FILES : like --suffix-each, but contents of FILES
31# are read first and used as VALS
32# --suffix-contents
33makeWrapper() {
34 local original="$1"
35 local wrapper="$2"
36 local params varName value command separator n fileNames
37 local argv0 flagsBefore flags
38
39 assertExecutable "$original"
40
41 mkdir -p "$(dirname "$wrapper")"
42
43 echo "#! $SHELL -e" > "$wrapper"
44
45 params=("$@")
46 for ((n = 2; n < ${#params[*]}; n += 1)); do
47 p="${params[$n]}"
48
49 if [[ "$p" == "--set" ]]; then
50 varName="${params[$((n + 1))]}"
51 value="${params[$((n + 2))]}"
52 n=$((n + 2))
53 echo "export $varName=${value@Q}" >> "$wrapper"
54 elif [[ "$p" == "--set-default" ]]; then
55 varName="${params[$((n + 1))]}"
56 value="${params[$((n + 2))]}"
57 n=$((n + 2))
58 echo "export $varName=\${$varName-${value@Q}}" >> "$wrapper"
59 elif [[ "$p" == "--unset" ]]; then
60 varName="${params[$((n + 1))]}"
61 n=$((n + 1))
62 echo "unset $varName" >> "$wrapper"
63 elif [[ "$p" == "--run" ]]; then
64 command="${params[$((n + 1))]}"
65 n=$((n + 1))
66 echo "$command" >> "$wrapper"
67 elif [[ ("$p" == "--suffix") || ("$p" == "--prefix") ]]; then
68 varName="${params[$((n + 1))]}"
69 separator="${params[$((n + 2))]}"
70 value="${params[$((n + 3))]}"
71 n=$((n + 3))
72 if test -n "$value"; then
73 if test "$p" = "--suffix"; then
74 echo "export $varName=\$$varName\${$varName:+${separator@Q}}${value@Q}" >> "$wrapper"
75 else
76 echo "export $varName=${value@Q}\${$varName:+${separator@Q}}\$$varName" >> "$wrapper"
77 fi
78 fi
79 elif [[ "$p" == "--suffix-each" ]]; then
80 varName="${params[$((n + 1))]}"
81 separator="${params[$((n + 2))]}"
82 values="${params[$((n + 3))]}"
83 n=$((n + 3))
84 for value in $values; do
85 echo "export $varName=\$$varName\${$varName:+$separator}${value@Q}" >> "$wrapper"
86 done
87 elif [[ ("$p" == "--suffix-contents") || ("$p" == "--prefix-contents") ]]; then
88 varName="${params[$((n + 1))]}"
89 separator="${params[$((n + 2))]}"
90 fileNames="${params[$((n + 3))]}"
91 n=$((n + 3))
92 for fileName in $fileNames; do
93 contents="$(cat "$fileName")"
94 if test "$p" = "--suffix-contents"; then
95 echo "export $varName=\$$varName\${$varName:+$separator}${contents@Q}" >> "$wrapper"
96 else
97 echo "export $varName=${contents@Q}\${$varName:+$separator}\$$varName" >> "$wrapper"
98 fi
99 done
100 elif [[ "$p" == "--add-flags" ]]; then
101 flags="${params[$((n + 1))]}"
102 n=$((n + 1))
103 flagsBefore="$flagsBefore $flags"
104 elif [[ "$p" == "--argv0" ]]; then
105 argv0="${params[$((n + 1))]}"
106 n=$((n + 1))
107 else
108 die "makeWrapper doesn't understand the arg $p"
109 fi
110 done
111
112 # Note: extraFlagsArray is an array containing additional flags
113 # that may be set by --run actions.
114 # Silence warning about unexpanded extraFlagsArray:
115 # shellcheck disable=SC2016
116 echo exec ${argv0:+-a \"$argv0\"} \""$original"\" \
117 "$flagsBefore" '"${extraFlagsArray[@]}"' '"$@"' >> "$wrapper"
118
119 chmod +x "$wrapper"
120}
121
122addSuffix() {
123 suffix="$1"
124 shift
125 for name in "$@"; do
126 echo "$name$suffix"
127 done
128}
129
130filterExisting() {
131 for fn in "$@"; do
132 if test -e "$fn"; then
133 echo "$fn"
134 fi
135 done
136}
137
138# Syntax: wrapProgram <PROGRAM> <MAKE-WRAPPER FLAGS...>
139wrapProgram() {
140 local prog="$1"
141 local hidden
142
143 assertExecutable "$prog"
144
145 hidden="$(dirname "$prog")/.$(basename "$prog")"-wrapped
146 while [ -e "$hidden" ]; do
147 hidden="${hidden}_"
148 done
149 mv "$prog" "$hidden"
150 # Silence warning about unexpanded $0:
151 # shellcheck disable=SC2016
152 makeWrapper "$hidden" "$prog" --argv0 '$0' "${@:2}"
153}