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