pytrainer: unpin python 3.10
[NixPkgs.git] / pkgs / build-support / setup-hooks / make-wrapper.sh
blobcba158bd31ea9949bf663c02d7d4fd5a64806086
1 # Assert that FILE exists and is executable
3 # assertExecutable FILE
4 assertExecutable() {
5 local file="$1"
6 [[ -f "$file" && -x "$file" ]] || \
7 die "Cannot wrap '$file' because it is not an executable file"
10 # construct an executable file that wraps the actual executable
11 # makeWrapper EXECUTABLE OUT_PATH ARGS
13 # ARGS:
14 # --argv0 NAME : set the name of the executed process to NAME
15 # (if unset or empty, defaults to EXECUTABLE)
16 # --inherit-argv0 : the executable inherits argv0 from the wrapper.
17 # (use instead of --argv0 '$0')
18 # --resolve-argv0 : if argv0 doesn't include a / character, resolve it against PATH
19 # --set VAR VAL : add VAR with value VAL to the executable's environment
20 # --set-default VAR VAL : like --set, but only adds VAR if not already set in
21 # the environment
22 # --unset VAR : remove VAR from the environment
23 # --chdir DIR : change working directory (use instead of --run "cd DIR")
24 # --run COMMAND : run command before the executable
25 # --add-flags ARGS : prepend ARGS to the invocation of the executable
26 # (that is, *before* any arguments passed on the command line)
27 # --append-flags ARGS : append ARGS to the invocation of the executable
28 # (that is, *after* any arguments passed on the command line)
30 # --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP
31 # --suffix
32 # --prefix-each ENV SEP VALS : like --prefix, but VALS is a list
33 # --suffix-each ENV SEP VALS : like --suffix, but VALS is a list
34 # --prefix-contents ENV SEP FILES : like --suffix-each, but contents of FILES
35 # are read first and used as VALS
36 # --suffix-contents
37 makeWrapper() { makeShellWrapper "$@"; }
38 makeShellWrapper() {
39 local original="$1"
40 local wrapper="$2"
41 local params varName value command separator n fileNames
42 local argv0 flagsBefore flagsAfter flags
44 assertExecutable "$original"
46 # Write wrapper code which adds `value` to the beginning or end of
47 # the list variable named by `varName`, depending on the `mode`
48 # specified.
50 # A value which is already part of the list will not be added
51 # again. If this is the case and the `suffix` mode is used, the
52 # list won't be touched at all. The `prefix` mode will however
53 # move the last matching instance of the value to the beginning
54 # of the list. Any remaining duplicates of the value will be left
55 # as-is.
56 addValue() {
57 local mode="$1" # `prefix` or `suffix` to add to the beginning or end respectively
58 local varName="$2" # name of list variable to add to
59 local separator="$3" # character used to separate elements of list
60 local value="$4" # one value, or multiple values separated by `separator`, to add to list
62 # Disable file globbing, since bash will otherwise try to find
63 # filenames matching the the value to be prefixed/suffixed if
64 # it contains characters considered wildcards, such as `?` and
65 # `*`. We want the value as is, except we also want to split
66 # it on on the separator; hence we can't quote it.
67 local reenableGlob=0
68 if [[ ! -o noglob ]]; then
69 reenableGlob=1
71 set -o noglob
73 if [[ -n "$value" ]]; then
74 local old_ifs=$IFS
75 IFS=$separator
77 if [[ "$mode" == '--prefix'* ]]; then
78 # Keep the order of the components as written when
79 # prefixing; normally, they would be added in the
80 # reverse order.
81 local tmp=
82 for v in $value; do
83 tmp=$v${tmp:+$separator}$tmp
84 done
85 value="$tmp"
87 for v in $value; do
89 echo "$varName=\${$varName:+${separator@Q}\$$varName${separator@Q}}" # add separators on both ends unless empty
90 if [[ "$mode" == '--prefix'* ]]; then # -- in prefix mode --
91 echo "$varName=\${$varName/${separator@Q}${v@Q}${separator@Q}/${separator@Q}}" # remove the first instance of the value (if any)
92 echo "$varName=${v@Q}\$$varName" # prepend the value
93 elif [[ "$mode" == '--suffix'* ]]; then # -- in suffix mode --
94 echo "if [[ \$$varName != *${separator@Q}${v@Q}${separator@Q}* ]]; then" # if the value isn't already in the list
95 echo " $varName=\$$varName${v@Q}" # append the value
96 echo "fi"
97 else
98 echo "unknown mode $mode!" 1>&2
99 exit 1
101 echo "$varName=\${$varName#${separator@Q}}" # remove leading separator
102 echo "$varName=\${$varName%${separator@Q}}" # remove trailing separator
103 echo "export $varName"
104 } >> "$wrapper"
105 done
106 IFS=$old_ifs
109 if (( reenableGlob )); then
110 set +o noglob
114 mkdir -p "$(dirname "$wrapper")"
116 echo "#! @shell@ -e" > "$wrapper"
118 params=("$@")
119 for ((n = 2; n < ${#params[*]}; n += 1)); do
120 p="${params[$n]}"
122 if [[ "$p" == "--set" ]]; then
123 varName="${params[$((n + 1))]}"
124 value="${params[$((n + 2))]}"
125 n=$((n + 2))
126 echo "export $varName=${value@Q}" >> "$wrapper"
127 elif [[ "$p" == "--set-default" ]]; then
128 varName="${params[$((n + 1))]}"
129 value="${params[$((n + 2))]}"
130 n=$((n + 2))
131 echo "export $varName=\${$varName-${value@Q}}" >> "$wrapper"
132 elif [[ "$p" == "--unset" ]]; then
133 varName="${params[$((n + 1))]}"
134 n=$((n + 1))
135 echo "unset $varName" >> "$wrapper"
136 elif [[ "$p" == "--chdir" ]]; then
137 dir="${params[$((n + 1))]}"
138 n=$((n + 1))
139 echo "cd ${dir@Q}" >> "$wrapper"
140 elif [[ "$p" == "--run" ]]; then
141 command="${params[$((n + 1))]}"
142 n=$((n + 1))
143 echo "$command" >> "$wrapper"
144 elif [[ ("$p" == "--suffix") || ("$p" == "--prefix") ]]; then
145 varName="${params[$((n + 1))]}"
146 separator="${params[$((n + 2))]}"
147 value="${params[$((n + 3))]}"
148 n=$((n + 3))
149 addValue "$p" "$varName" "$separator" "$value"
150 elif [[ ("$p" == "--suffix-each") || ("$p" == "--prefix-each") ]]; then
151 varName="${params[$((n + 1))]}"
152 separator="${params[$((n + 2))]}"
153 values="${params[$((n + 3))]}"
154 n=$((n + 3))
155 for value in $values; do
156 addValue "$p" "$varName" "$separator" "$value"
157 done
158 elif [[ ("$p" == "--suffix-contents") || ("$p" == "--prefix-contents") ]]; then
159 varName="${params[$((n + 1))]}"
160 separator="${params[$((n + 2))]}"
161 fileNames="${params[$((n + 3))]}"
162 n=$((n + 3))
163 for fileName in $fileNames; do
164 contents="$(cat "$fileName")"
165 addValue "$p" "$varName" "$separator" "$contents"
166 done
167 elif [[ "$p" == "--add-flags" ]]; then
168 flags="${params[$((n + 1))]}"
169 n=$((n + 1))
170 flagsBefore="${flagsBefore-} $flags"
171 elif [[ "$p" == "--append-flags" ]]; then
172 flags="${params[$((n + 1))]}"
173 n=$((n + 1))
174 flagsAfter="${flagsAfter-} $flags"
175 elif [[ "$p" == "--argv0" ]]; then
176 argv0="${params[$((n + 1))]}"
177 n=$((n + 1))
178 elif [[ "$p" == "--inherit-argv0" ]]; then
179 # Whichever comes last of --argv0 and --inherit-argv0 wins
180 argv0='$0'
181 elif [[ "$p" == "--resolve-argv0" ]]; then
182 # this is noop in shell wrappers, since bash will always resolve $0
183 resolve_argv0=1
184 else
185 die "makeWrapper doesn't understand the arg $p"
187 done
189 echo exec ${argv0:+-a \"$argv0\"} \""$original"\" \
190 "${flagsBefore-}" '"$@"' "${flagsAfter-}" >> "$wrapper"
192 chmod +x "$wrapper"
195 addSuffix() {
196 suffix="$1"
197 shift
198 for name in "$@"; do
199 echo "$name$suffix"
200 done
203 filterExisting() {
204 for fn in "$@"; do
205 if test -e "$fn"; then
206 echo "$fn"
208 done
211 # Syntax: wrapProgram <PROGRAM> <MAKE-WRAPPER FLAGS...>
212 wrapProgram() { wrapProgramShell "$@"; }
213 wrapProgramShell() {
214 local prog="$1"
215 local hidden
217 assertExecutable "$prog"
219 hidden="$(dirname "$prog")/.$(basename "$prog")"-wrapped
220 while [ -e "$hidden" ]; do
221 hidden="${hidden}_"
222 done
223 mv "$prog" "$hidden"
224 makeShellWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}"