From c67f885fe4cf70856b9f0052c1ce48f1abfcfe95 Mon Sep 17 00:00:00 2001 From: talyz Date: Mon, 28 Jun 2021 14:16:04 +0200 Subject: [PATCH 1/2] makeWrapper: Don't readd existing values in prefix/suffix When prefixing or suffixing list variables, check that the value or values aren't already part of the list. If this is the case when suffixing, the list won't be touched at all. When prefixing, however, the last matching instance of the value will be moved to the beginning of the list. Any remaining duplicates of the value will be left as-is. Co-authored-by: Vincenzo Mantova --- .../build-support/setup-hooks/make-wrapper.sh | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/pkgs/build-support/setup-hooks/make-wrapper.sh b/pkgs/build-support/setup-hooks/make-wrapper.sh index 903e17c3b2e5..604096135c20 100644 --- a/pkgs/build-support/setup-hooks/make-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-wrapper.sh @@ -36,6 +36,58 @@ makeWrapper() { assertExecutable "$original" + # Write wrapper code which adds `value` to the beginning or end of + # the list variable named by `varName`, depending on the `mode` + # specified. + # + # A value which is already part of the list will not be added + # again. If this is the case and the `suffix` mode is used, the + # list won't be touched at all. The `prefix` mode will however + # move the last matching instance of the value to the beginning + # of the list. Any remaining duplicates of the value will be left + # as-is. + addValue() { + local mode="$1" # `prefix` or `suffix` to add to the beginning or end respectively + local varName="$2" # name of list variable to add to + local separator="$3" # character used to separate elements of list + local value="$4" # one value, or multiple values separated by `separator`, to add to list + if test -n "$value"; then + local old_ifs=$IFS + IFS=$separator + + if [[ "$mode" == '--prefix'* ]]; then + # Keep the order of the components as written when + # prefixing; normally, they would be added in the + # reverse order. + local tmp= + for v in $value; do + tmp=$v${tmp:+$separator}$tmp + done + value="$tmp" + fi + for v in $value; do + { + echo "$varName=\${$varName:+${separator@Q}\$$varName${separator@Q}}" # add separators on both ends unless empty + if [[ "$mode" == '--prefix'* ]]; then # -- in prefix mode -- + echo "$varName=\${$varName/${separator@Q}${v@Q}${separator@Q}/${separator@Q}}" # remove the first instance of the value (if any) + echo "$varName=${v@Q}\$$varName" # prepend the value + elif [[ "$mode" == '--suffix'* ]]; then # -- in suffix mode -- + echo "if [[ \$$varName != *${separator@Q}${v@Q}${separator@Q}* ]]; then" # if the value isn't already in the list + echo " $varName=\$$varName${v@Q}" # append the value + echo "fi" + else + echo "unknown mode $mode!" 1>&2 + exit 1 + fi + echo "$varName=\${$varName#${separator@Q}}" # remove leading separator + echo "$varName=\${$varName%${separator@Q}}" # remove trailing separator + echo "export $varName" + } >> "$wrapper" + done + IFS=$old_ifs + fi + } + mkdir -p "$(dirname "$wrapper")" echo "#! @shell@ -e" > "$wrapper" @@ -67,28 +119,14 @@ makeWrapper() { separator="${params[$((n + 2))]}" value="${params[$((n + 3))]}" n=$((n + 3)) - if test -n "$value"; then - if test "$p" = "--suffix"; then - echo "export $varName=\$$varName\${$varName:+${separator@Q}}${value@Q}" >> "$wrapper" - else - echo "export $varName=${value@Q}\${$varName:+${separator@Q}}\$$varName" >> "$wrapper" - fi - fi - elif [[ "$p" == "--prefix-each" ]]; then + addValue "$p" "$varName" "$separator" "$value" + elif [[ ("$p" == "--suffix-each") || ("$p" == "--prefix-each") ]]; then varName="${params[$((n + 1))]}" separator="${params[$((n + 2))]}" values="${params[$((n + 3))]}" n=$((n + 3)) for value in $values; do - echo "export $varName=${value@Q}\${$varName:+${separator@Q}}\$$varName" >> "$wrapper" - done - elif [[ "$p" == "--suffix-each" ]]; then - varName="${params[$((n + 1))]}" - separator="${params[$((n + 2))]}" - values="${params[$((n + 3))]}" - n=$((n + 3)) - for value in $values; do - echo "export $varName=\$$varName\${$varName:+$separator}${value@Q}" >> "$wrapper" + addValue "$p" "$varName" "$separator" "$value" done elif [[ ("$p" == "--suffix-contents") || ("$p" == "--prefix-contents") ]]; then varName="${params[$((n + 1))]}" @@ -97,11 +135,7 @@ makeWrapper() { n=$((n + 3)) for fileName in $fileNames; do contents="$(cat "$fileName")" - if test "$p" = "--suffix-contents"; then - echo "export $varName=\$$varName\${$varName:+$separator}${contents@Q}" >> "$wrapper" - else - echo "export $varName=${contents@Q}\${$varName:+$separator}\$$varName" >> "$wrapper" - fi + addValue "$p" "$varName" "$separator" "$contents" done elif [[ "$p" == "--add-flags" ]]; then flags="${params[$((n + 1))]}" From be2aa01de789b490c7f6880b57e8d837fc2c8203 Mon Sep 17 00:00:00 2001 From: talyz Date: Tue, 22 Jun 2021 23:05:38 +0200 Subject: [PATCH 2/2] tests: Add test for makeWrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Janne Heß --- pkgs/test/default.nix | 2 + pkgs/test/make-wrapper/default.nix | 136 +++++++++++++++++++++++++++++ pkgs/top-level/all-packages.nix | 10 ++- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 pkgs/test/make-wrapper/default.nix diff --git a/pkgs/test/default.nix b/pkgs/test/default.nix index b7980c478c66..4110327946d9 100644 --- a/pkgs/test/default.nix +++ b/pkgs/test/default.nix @@ -67,4 +67,6 @@ with pkgs; writers = callPackage ../build-support/writers/test.nix {}; dhall = callPackage ./dhall { }; + + makeWrapper = callPackage ./make-wrapper {}; } diff --git a/pkgs/test/make-wrapper/default.nix b/pkgs/test/make-wrapper/default.nix new file mode 100644 index 000000000000..6e70945ee194 --- /dev/null +++ b/pkgs/test/make-wrapper/default.nix @@ -0,0 +1,136 @@ +{ lib +, writeText +, writeCBin +, writeShellScript +, makeWrapper +, runCommand +, which +, ... +}: + +let + # Testfiles + foofile = writeText "foofile" "foo"; + barfile = writeText "barfile" "bar"; + + # Wrapped binaries + wrappedArgv0 = writeCBin "wrapped-argv0" '' + #include + #include + + void main(int argc, char** argv) { + printf("argv0=%s", argv[0]); + exit(0); + } + ''; + wrappedBinaryVar = writeShellScript "wrapped-var" '' + echo "VAR=$VAR" + ''; + wrappedBinaryArgs = writeShellScript "wrapped-args" '' + echo "$@" + ''; + + mkWrapperBinary = { name, args, wrapped ? wrappedBinaryVar }: runCommand name + { + nativeBuildInputs = [ makeWrapper ]; + } '' + mkdir -p $out/bin + makeWrapper "${wrapped}" "$out/bin/${name}" ${lib.escapeShellArgs args} + ''; + + mkTest = cmd: toExpect: '' + output="$(${cmd})" + if [[ "$output" != '${toExpect}' ]]; then + echo "test failed: the output of ${cmd} was '$output', expected '${toExpect}'" + echo "the wrapper contents:" + for i in ${cmd}; do + if [[ $i =~ ^test- ]]; then + cat $(which $i) + fi + done + exit 1 + fi + ''; +in +runCommand "make-wrapper-test" +{ + nativeBuildInputs = [ + which + (mkWrapperBinary { name = "test-argv0"; args = [ "--argv0" "foo" ]; wrapped = "${wrappedArgv0}/bin/wrapped-argv0"; }) + (mkWrapperBinary { name = "test-set"; args = [ "--set" "VAR" "abc" ]; }) + (mkWrapperBinary { name = "test-set-default"; args = [ "--set-default" "VAR" "abc" ]; }) + (mkWrapperBinary { name = "test-unset"; args = [ "--unset" "VAR" ]; }) + (mkWrapperBinary { name = "test-run"; args = [ "--run" "echo bar" ]; }) + (mkWrapperBinary { name = "test-run-and-set"; args = [ "--run" "export VAR=foo" "--set" "VAR" "bar" ]; }) + (mkWrapperBinary { name = "test-args"; args = [ "--add-flags" "abc" ]; wrapped = wrappedBinaryArgs; }) + (mkWrapperBinary { name = "test-prefix"; args = [ "--prefix" "VAR" ":" "abc" ]; }) + (mkWrapperBinary { name = "test-suffix"; args = [ "--suffix" "VAR" ":" "abc" ]; }) + (mkWrapperBinary { name = "test-prefix-and-suffix"; args = [ "--prefix" "VAR" ":" "foo" "--suffix" "VAR" ":" "bar" ]; }) + (mkWrapperBinary { name = "test-prefix-multi"; args = [ "--prefix" "VAR" ":" "abc:foo:foo" ]; }) + (mkWrapperBinary { name = "test-suffix-each"; args = [ "--suffix-each" "VAR" ":" "foo bar:def" ]; }) + (mkWrapperBinary { name = "test-prefix-each"; args = [ "--prefix-each" "VAR" ":" "foo bar:def" ]; }) + (mkWrapperBinary { name = "test-suffix-contents"; args = [ "--suffix-contents" "VAR" ":" "${foofile} ${barfile}" ]; }) + (mkWrapperBinary { name = "test-prefix-contents"; args = [ "--prefix-contents" "VAR" ":" "${foofile} ${barfile}" ]; }) + ]; +} + ( + # --argv0 works + mkTest "test-argv0" "argv0=foo" + + # --set works + + mkTest "test-set" "VAR=abc" + # --set overwrites the variable + + mkTest "VAR=foo test-set" "VAR=abc" + # --set-default works + + mkTest "test-set-default" "VAR=abc" + # --set-default doesn"t overwrite the variable + + mkTest "VAR=foo test-set-default" "VAR=foo" + # --unset works + + mkTest "VAR=foo test-unset" "VAR=" + + # --add-flags works + + mkTest "test-args" "abc" + # given flags are appended + + mkTest "test-args foo" "abc foo" + + # --run works + + mkTest "test-run" "bar\nVAR=" + # --run & --set works + + mkTest "test-run-and-set" "VAR=bar" + + # --prefix works + + mkTest "VAR=foo test-prefix" "VAR=abc:foo" + # sets variable if not set yet + + mkTest "test-prefix" "VAR=abc" + # prepends value only once + + mkTest "VAR=abc test-prefix" "VAR=abc" + # Moves value to the front if it already existed + + mkTest "VAR=foo:abc test-prefix" "VAR=abc:foo" + + mkTest "VAR=abc:foo:bar test-prefix-multi" "VAR=abc:foo:bar" + # Doesn't overwrite parts of the string + + mkTest "VAR=test:abcde:test test-prefix" "VAR=abc:test:abcde:test" + # Only append the value once when given multiple times in a parameter + # to makeWrapper + + mkTest "test-prefix" "VAR=abc" + + + # --suffix works + + mkTest "VAR=foo test-suffix" "VAR=foo:abc" + # sets variable if not set yet + + mkTest "test-suffix" "VAR=abc" + # adds the same value only once + + mkTest "VAR=abc test-suffix" "VAR=abc" + + mkTest "VAR=abc:foo test-suffix" "VAR=abc:foo" + # --prefix in combination with --suffix + + mkTest "VAR=abc test-prefix-and-suffix" "VAR=foo:abc:bar" + + # --suffix-each works + + mkTest "VAR=abc test-suffix-each" "VAR=abc:foo:bar:def" + # --prefix-each works + + mkTest "VAR=abc test-prefix-each" "VAR=bar:def:foo:abc" + # --suffix-contents works + + mkTest "VAR=abc test-suffix-contents" "VAR=abc:foo:bar" + # --prefix-contents works + + mkTest "VAR=abc test-prefix-contents" "VAR=bar:foo:abc" + + "touch $out" + ) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index cbb6be6c25b6..067e782cc365 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -715,8 +715,14 @@ with pkgs; makeInitrd = callPackage ../build-support/kernel/make-initrd.nix; # Args intentionally left out - makeWrapper = makeSetupHook { deps = [ dieHook ]; substitutions = { shell = targetPackages.runtimeShell; }; } - ../build-support/setup-hooks/make-wrapper.sh; + makeWrapper = makeSetupHook + { deps = [ dieHook ]; + substitutions = { + shell = targetPackages.runtimeShell; + passthru.tests = tests.makeWrapper; + }; + } + ../build-support/setup-hooks/make-wrapper.sh; makeBinaryWrapper = let f = { cc, sanitizers }: let