lol

makeWrapper: --add-flag and --append-flag arguments (#400649)

authored by

Naïm Camille Favier and committed by
GitHub
9c4a331e e8a88209

+97 -41
+4 -1
doc/stdenv/stdenv.chapter.md
··· 1141 1141 1142 1142 If dependencies should be resolved at runtime, use `--suffix` to append fallback values to `PATH`. 1143 1143 1144 - There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh` for the `makeWrapper` implementation and in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper/make-binary-wrapper.sh` for the `makeBinaryWrapper` implementation. 1144 + There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh` for the `makeWrapper` implementation and in `nixpkgs/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh` for the `makeBinaryWrapper` implementation. 1145 1145 1146 1146 `wrapProgram` is a convenience function you probably want to use most of the time, implemented by both `makeWrapper` and `makeBinaryWrapper`. 1147 1147 1148 1148 Using the `makeBinaryWrapper` implementation is usually preferred, as it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less <path-to-wrapper>` - by scrolling past the binary data you should be able to see the shell command that generated the executable and there see the environment variables that were injected into the wrapper. 1149 + 1150 + However, `makeWrapper` is more flexible and implements more arguments. 1151 + Use `makeWrapper` if you need the wrapper to use shell features (e.g. look up environment variables) at runtime. 1149 1152 1150 1153 ### `remove-references-to -t` \<storepath\> [ `-t` \<storepath\> ... ] \<file\> ... {#fun-remove-references-to} 1151 1154
+12 -2
pkgs/build-support/setup-hooks/make-wrapper.sh
··· 22 22 # --unset VAR : remove VAR from the environment 23 23 # --chdir DIR : change working directory (use instead of --run "cd DIR") 24 24 # --run COMMAND : run command before the executable 25 - # --add-flags ARGS : prepend ARGS to the invocation of the executable 25 + # --add-flag ARG : prepend the single argument ARG to the invocation of the executable 26 26 # (that is, *before* any arguments passed on the command line) 27 - # --append-flags ARGS : append ARGS to the invocation of the executable 27 + # --append-flag ARG : append the single argument ARG to the invocation of the executable 28 28 # (that is, *after* any arguments passed on the command line) 29 + # --add-flags ARGS : prepend ARGS verbatim to the Bash-interpreted invocation of the executable 30 + # --append-flags ARGS : append ARGS verbatim to the Bash-interpreted invocation of the executable 29 31 30 32 # --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP 31 33 # --suffix ··· 164 166 contents="$(cat "$fileName")" 165 167 addValue "$p" "$varName" "$separator" "$contents" 166 168 done 169 + elif [[ "$p" == "--add-flag" ]]; then 170 + flags=${params[n + 1]@Q} 171 + n=$((n + 1)) 172 + flagsBefore="${flagsBefore-} $flags" 173 + elif [[ "$p" == "--append-flag" ]]; then 174 + flags=${params[n + 1]@Q} 175 + n=$((n + 1)) 176 + flagsAfter="${flagsAfter-} $flags" 167 177 elif [[ "$p" == "--add-flags" ]]; then 168 178 flags="${params[$((n + 1))]}" 169 179 n=$((n + 1))
+34 -25
pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh
··· 25 25 # the environment 26 26 # --unset VAR : remove VAR from the environment 27 27 # --chdir DIR : change working directory (use instead of --run "cd DIR") 28 - # --add-flags ARGS : prepend ARGS to the invocation of the executable 28 + # --add-flag ARG : prepend the single argument ARG to the invocation of the executable 29 29 # (that is, *before* any arguments passed on the command line) 30 - # --append-flags ARGS : append ARGS to the invocation of the executable 30 + # --append-flag ARG : append the single argument ARG to the invocation of the executable 31 31 # (that is, *after* any arguments passed on the command line) 32 + # --add-flags ARGS : prepend the whitespace-separated list of arguments ARGS to the invocation of the executable 33 + # --append-flags ARGS : append the whitespace-separated list of arguments ARGS to the invocation of the executable 32 34 33 35 # --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP 34 36 # --suffix ··· 86 88 # makeCWrapper EXECUTABLE ARGS 87 89 # ARGS: same as makeWrapper 88 90 makeCWrapper() { 89 - local argv0 inherit_argv0 n params cmd main flagsBefore flagsAfter flags executable length 91 + local argv0 inherit_argv0 n params cmd main flags executable length 90 92 local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf 91 - local resolve_path 93 + local flagsBefore=() flagsAfter=() 92 94 executable=$(escapeStringLiteral "$1") 93 95 params=("$@") 94 96 length=${#params[*]} ··· 147 149 n=$((n + 1)) 148 150 [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' 149 151 ;; 152 + --add-flag) 153 + flagsBefore+=("${params[n + 1]}") 154 + uses_assert=1 155 + n=$((n + 1)) 156 + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' 157 + ;; 158 + --append-flag) 159 + flagsAfter+=("${params[n + 1]}") 160 + uses_assert=1 161 + n=$((n + 1)) 162 + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' 163 + ;; 150 164 --add-flags) 151 - flags="${params[n + 1]}" 152 - flagsBefore="$flagsBefore $flags" 165 + read -ra flags <<< "${params[n + 1]}" 166 + flagsBefore+=("${flags[@]}") 153 167 uses_assert=1 154 168 n=$((n + 1)) 155 169 [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' 156 170 ;; 157 171 --append-flags) 158 - flags="${params[n + 1]}" 159 - flagsAfter="$flagsAfter $flags" 172 + read -ra flags <<< "${params[n + 1]}" 173 + flagsAfter+=("${flags[@]}") 160 174 uses_assert=1 161 175 n=$((n + 1)) 162 176 [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ··· 182 196 ;; 183 197 esac 184 198 done 185 - [[ -z "$flagsBefore" && -z "$flagsAfter" ]] || main="$main"${main:+$'\n'}$(addFlags "$flagsBefore" "$flagsAfter")$'\n'$'\n' 199 + (( ${#flagsBefore[@]} + ${#flagsAfter[@]} > 0 )) && main="$main"${main:+$'\n'}$(addFlags flagsBefore flagsAfter)$'\n'$'\n' 186 200 [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n' 187 201 [ -z "$resolve_argv0" ] || main="${main}argv[0] = resolve_argv0(argv[0]);"$'\n' 188 202 main="${main}return execv(\"${executable}\", argv);"$'\n' ··· 203 217 } 204 218 205 219 addFlags() { 206 - local n flag before after var 220 + local n flag var 207 221 208 - # Disable file globbing, since bash will otherwise try to find 209 - # filenames matching the the value to be prefixed/suffixed if 210 - # it contains characters considered wildcards, such as `?` and 211 - # `*`. We want the value as is, except we also want to split 212 - # it on on the separator; hence we can't quote it. 213 - local reenableGlob=0 214 - if [[ ! -o noglob ]]; then 215 - reenableGlob=1 216 - fi 217 - set -o noglob 218 - # shellcheck disable=SC2086 219 - before=($1) after=($2) 220 - if (( reenableGlob )); then 221 - set +o noglob 222 - fi 222 + local -n before=$1 223 + local -n after=$2 223 224 224 225 var="argv_tmp" 225 226 printf '%s\n' "char **$var = calloc(${#before[@]} + argc + ${#after[@]} + 1, sizeof(*$var));" ··· 432 433 shift 3 433 434 ;; 434 435 --chdir) 436 + formatArgsLine 1 "$@" 437 + shift 1 438 + ;; 439 + --add-flag) 440 + formatArgsLine 1 "$@" 441 + shift 1 442 + ;; 443 + --append-flag) 435 444 formatArgsLine 1 "$@" 436 445 shift 1 437 446 ;;
+11 -7
pkgs/test/make-binary-wrapper/add-flags/add-flags.c
··· 3 3 #include <assert.h> 4 4 5 5 int main(int argc, char **argv) { 6 - char **argv_tmp = calloc(6 + argc + 2 + 1, sizeof(*argv_tmp)); 6 + char **argv_tmp = calloc(9 + argc + 3 + 1, sizeof(*argv_tmp)); 7 7 assert(argv_tmp != NULL); 8 8 argv_tmp[0] = argv[0]; 9 9 argv_tmp[1] = "-x"; 10 10 argv_tmp[2] = "-y"; 11 11 argv_tmp[3] = "-z"; 12 12 argv_tmp[4] = "-abc"; 13 - argv_tmp[5] = "-g"; 14 - argv_tmp[6] = "*.txt"; 13 + argv_tmp[5] = "test var here"; 14 + argv_tmp[6] = "-g"; 15 + argv_tmp[7] = "*.txt"; 16 + argv_tmp[8] = "-a"; 17 + argv_tmp[9] = "*"; 15 18 for (int i = 1; i < argc; ++i) { 16 - argv_tmp[6 + i] = argv[i]; 19 + argv_tmp[9 + i] = argv[i]; 17 20 } 18 - argv_tmp[6 + argc + 0] = "-foo"; 19 - argv_tmp[6 + argc + 1] = "-bar"; 20 - argv_tmp[6 + argc + 2] = NULL; 21 + argv_tmp[9 + argc + 0] = "-foo"; 22 + argv_tmp[9 + argc + 1] = "-bar"; 23 + argv_tmp[9 + argc + 2] = "test var 2 here"; 24 + argv_tmp[9 + argc + 3] = NULL; 21 25 argv = argv_tmp; 22 26 23 27 argv[0] = "/send/me/flags";
+4 -1
pkgs/test/make-binary-wrapper/add-flags/add-flags.cmdline
··· 1 1 --append-flags "-foo -bar" \ 2 2 --add-flags "-x -y -z" \ 3 3 --add-flags -abc \ 4 - --add-flags "-g *.txt" 4 + --add-flag 'test var here' \ 5 + --add-flags "-g *.txt" \ 6 + --add-flags "-a *" \ 7 + --append-flag 'test var 2 here'
+4
pkgs/test/make-binary-wrapper/add-flags/add-flags.env
··· 4 4 -y 5 5 -z 6 6 -abc 7 + test var here 7 8 -g 8 9 *.txt 10 + -a 11 + * 9 12 -foo 10 13 -bar 14 + test var 2 here
+28 -5
pkgs/test/make-wrapper/default.nix
··· 28 28 echo "VAR=$VAR" 29 29 ''; 30 30 wrappedBinaryArgs = writeShellScript "wrapped-args" '' 31 - echo "$@" 31 + printf '%s\n' "$@" 32 32 ''; 33 33 34 34 mkWrapperBinary = ··· 46 46 makeWrapper "${wrapped}" "$out/bin/${name}" ${lib.escapeShellArgs args} 47 47 ''; 48 48 49 + mkArgTest = cmd: toExpect: mkTest cmd (builtins.concatStringsSep "\n" toExpect); 49 50 mkTest = cmd: toExpect: '' 50 51 output="$(${cmd})" 51 - if [[ "$output" != '${toExpect}' ]]; then 52 - echo "test failed: the output of ${cmd} was '$output', expected '${toExpect}'" 52 + if [[ "$output" != ${lib.escapeShellArg toExpect} ]]; then 53 + echo "test failed: the output of ${cmd} was '$output', expected ${lib.escapeShellArg toExpect}" 53 54 echo "the wrapper contents:" 54 55 for i in ${cmd}; do 55 56 if [[ $i =~ ^test- ]]; then ··· 119 120 "abc" 120 121 "--append-flags" 121 122 "xyz" 123 + ]; 124 + wrapped = wrappedBinaryArgs; 125 + }) 126 + (mkWrapperBinary { 127 + name = "test-arg"; 128 + args = [ 129 + "--add-flag" 130 + "abc 'aaaaa' jkhhjk" 131 + "--append-flag" 132 + "xyz ggg" 122 133 ]; 123 134 wrapped = wrappedBinaryArgs; 124 135 }) ··· 225 236 + mkTest "VAR=foo test-unset" "VAR=" 226 237 227 238 # --add-flags and --append-flags work 228 - + mkTest "test-args" "abc xyz" 239 + + mkArgTest "test-args" [ 240 + "abc" 241 + "xyz" 242 + ] 243 + # --add-flag and --append-flag work 244 + + mkArgTest "test-arg" [ 245 + "abc 'aaaaa' jkhhjk" 246 + "xyz ggg" 247 + ] 229 248 # given flags are kept 230 - + mkTest "test-args foo" "abc foo xyz" 249 + + mkArgTest "test-args foo" [ 250 + "abc" 251 + "foo" 252 + "xyz" 253 + ] 231 254 232 255 # --run works 233 256 + mkTest "test-run" "bar\nVAR="