substitute: Deprecate `replacements`, introduce `replacementsList`

Also:
- Add tests
- Treewide update
- Improve docs

authored by Silvan Mosberger and committed by Silvan Mosberger cd5dc76d 0151be1b

+160 -12
+1 -1
nixos/modules/system/boot/systemd/coredump.nix
··· 52 # See: https://github.com/NixOS/nixpkgs/issues/213408 53 pkgs.substitute { 54 src = "${systemd}/example/sysctl.d/50-coredump.conf"; 55 - replacements = [ 56 "--replace" 57 "${systemd}" 58 "${pkgs.symlinkJoin { name = "systemd"; paths = [ systemd ]; }}"
··· 52 # See: https://github.com/NixOS/nixpkgs/issues/213408 53 pkgs.substitute { 54 src = "${systemd}/example/sysctl.d/50-coredump.conf"; 55 + substitutions = [ 56 "--replace" 57 "${systemd}" 58 "${pkgs.symlinkJoin { name = "systemd"; paths = [ systemd ]; }}"
+50 -6
pkgs/build-support/substitute/substitute.nix
··· 1 - { stdenvNoCC }: 2 3 args: 4 5 - # This is a wrapper around `substitute` in the stdenv. 6 - # The `replacements` attribute should be a list of list of arguments 7 - # to `substitute`, such as `[ "--replace" "sourcetext" "replacementtext" ]` 8 - stdenvNoCC.mkDerivation ({ 9 name = if args ? name then args.name else baseNameOf (toString args.src); 10 builder = ./substitute.sh; 11 inherit (args) src; 12 preferLocalBuild = true; 13 allowSubstitutes = false; 14 - } // args // { replacements = args.replacements; })
··· 1 + { lib, stdenvNoCC }: 2 + /* 3 + This is a wrapper around `substitute` in the stdenv. 4 + 5 + Attribute arguments: 6 + - `name` (optional): The name of the resulting derivation 7 + - `src`: The path to the file to substitute 8 + - `substitutions`: The list of substitution arguments to pass 9 + See https://nixos.org/manual/nixpkgs/stable/#fun-substitute 10 + - `replacements`: Deprecated version of `substitutions` 11 + that doesn't support spaces in arguments. 12 + 13 + Example: 14 15 + ```nix 16 + { substitute }: 17 + substitute { 18 + src = ./greeting.txt; 19 + substitutions = [ 20 + "--replace" 21 + "world" 22 + "paul" 23 + ]; 24 + } 25 + ``` 26 + 27 + See ../../test/substitute for tests 28 + */ 29 args: 30 31 + let 32 name = if args ? name then args.name else baseNameOf (toString args.src); 33 + deprecationReplacement = lib.pipe args.replacements [ 34 + lib.toList 35 + (map (lib.splitString " ")) 36 + lib.concatLists 37 + (lib.concatMapStringsSep " " lib.strings.escapeNixString) 38 + ]; 39 + optionalDeprecationWarning = 40 + # substitutions is only available starting 24.05. 41 + # TODO: Remove support for replacements sometime after the next release 42 + lib.warnIf (args ? replacements && lib.isInOldestRelease 2405) '' 43 + pkgs.substitute: For "${name}", `replacements` is used, which is deprecated since it doesn't support arguments with spaces. Use `substitutions` instead: 44 + substitutions = [ ${deprecationReplacement} ];''; 45 + in 46 + optionalDeprecationWarning 47 + stdenvNoCC.mkDerivation ({ 48 + inherit name; 49 builder = ./substitute.sh; 50 inherit (args) src; 51 preferLocalBuild = true; 52 allowSubstitutes = false; 53 + } // args // lib.optionalAttrs (args ? substitutions) { 54 + substitutions = 55 + assert lib.assertMsg (lib.isList args.substitutions) '' 56 + pkgs.substitute: For "${name}", `substitutions` is passed, which is expected to be a list, but it's a ${builtins.typeOf args.substitutions} instead.''; 57 + lib.escapeShellArgs args.substitutions; 58 + })
+7 -1
pkgs/build-support/substitute/substitute.sh
··· 8 mkdir -p $out/$dir 9 fi 10 11 - substitute $src $target $replacements 12 13 if test -n "$isExecutable"; then 14 chmod +x $target
··· 8 mkdir -p $out/$dir 9 fi 10 11 + substitutionsList=($replacements) 12 + 13 + if [[ -v substitutions ]]; then 14 + eval "substitutionsList+=($substitutions)" 15 + fi 16 + 17 + substitute $src $target "${substitutionsList[@]}" 18 19 if test -n "$isExecutable"; then 20 chmod +x $target
+1 -1
pkgs/development/libraries/science/math/libamplsolver/default.nix
··· 12 patches = [ 13 (substitute { 14 src = ./libamplsolver-sharedlib.patch; 15 - replacements = [ "--replace" "@sharedlibext@" "${stdenv.hostPlatform.extensions.sharedLibrary}" ]; 16 }) 17 ]; 18
··· 12 patches = [ 13 (substitute { 14 src = ./libamplsolver-sharedlib.patch; 15 + substitutions = [ "--replace" "@sharedlibext@" "${stdenv.hostPlatform.extensions.sharedLibrary}" ]; 16 }) 17 ]; 18
+1 -1
pkgs/development/tools/misc/binutils/2.38/default.nix
··· 91 # this patch is from debian: 92 # https://sources.debian.org/data/main/b/binutils/2.38-3/debian/patches/mips64-default-n64.diff 93 (if stdenv.targetPlatform.isMusl 94 - then substitute { src = ./mips64-default-n64.patch; replacements = [ "--replace" "gnuabi64" "muslabi64" ]; } 95 else ./mips64-default-n64.patch) 96 # On PowerPC, when generating assembly code, GCC generates a `.machine` 97 # custom instruction which instructs the assembler to generate code for this
··· 91 # this patch is from debian: 92 # https://sources.debian.org/data/main/b/binutils/2.38-3/debian/patches/mips64-default-n64.diff 93 (if stdenv.targetPlatform.isMusl 94 + then substitute { src = ./mips64-default-n64.patch; substitutions = [ "--replace" "gnuabi64" "muslabi64" ]; } 95 else ./mips64-default-n64.patch) 96 # On PowerPC, when generating assembly code, GCC generates a `.machine` 97 # custom instruction which instructs the assembler to generate code for this
+1 -1
pkgs/development/tools/misc/binutils/default.nix
··· 105 # this patch is from debian: 106 # https://sources.debian.org/data/main/b/binutils/2.38-3/debian/patches/mips64-default-n64.diff 107 (if stdenv.targetPlatform.isMusl 108 - then substitute { src = ./mips64-default-n64.patch; replacements = [ "--replace" "gnuabi64" "muslabi64" ]; } 109 else ./mips64-default-n64.patch) 110 # This patch fixes a bug in 2.40 on MinGW, which breaks DXVK when cross-building from Darwin. 111 # See https://sourceware.org/bugzilla/show_bug.cgi?id=30079
··· 105 # this patch is from debian: 106 # https://sources.debian.org/data/main/b/binutils/2.38-3/debian/patches/mips64-default-n64.diff 107 (if stdenv.targetPlatform.isMusl 108 + then substitute { src = ./mips64-default-n64.patch; substitutions = [ "--replace" "gnuabi64" "muslabi64" ]; } 109 else ./mips64-default-n64.patch) 110 # This patch fixes a bug in 2.40 on MinGW, which breaks DXVK when cross-building from Darwin. 111 # See https://sourceware.org/bugzilla/show_bug.cgi?id=30079
+1 -1
pkgs/games/shattered-pixel-dungeon/summoning-pixel-dungeon.nix
··· 18 19 patches = [(substitute { 20 src = ./disable-git-version.patch; 21 - replacements = [ "--subst-var-by" "version" version ]; 22 })]; 23 24 depsHash = "sha256-0P/BcjNnbDN25DguRcCyzPuUG7bouxEx1ySodIbSwvg=";
··· 18 19 patches = [(substitute { 20 src = ./disable-git-version.patch; 21 + substitutions = [ "--subst-var-by" "version" version ]; 22 })]; 23 24 depsHash = "sha256-0P/BcjNnbDN25DguRcCyzPuUG7bouxEx1ySodIbSwvg=";
+2
pkgs/test/default.nix
··· 177 auto-patchelf-hook = callPackage ./auto-patchelf-hook { }; 178 179 systemd = callPackage ./systemd { }; 180 }
··· 177 auto-patchelf-hook = callPackage ./auto-patchelf-hook { }; 178 179 systemd = callPackage ./systemd { }; 180 + 181 + substitute = recurseIntoAttrs (callPackage ./substitute { }); 182 }
+96
pkgs/test/substitute/default.nix
···
··· 1 + { substitute, testers, runCommand }: 2 + let 3 + # Ofborg doesn't allow any traces on stderr, 4 + # so mock `lib` to not trace warnings, 5 + # because substitute gives a deprecation warning 6 + substituteSilent = substitute.override (prevArgs: { 7 + lib = prevArgs.lib.extend (finalLib: prevLib: { 8 + trivial = prevLib.trivial // { 9 + warn = msg: value: value; 10 + }; 11 + }); 12 + }); 13 + in { 14 + 15 + substitutions = testers.testEqualContents { 16 + assertion = "substitutions-spaces"; 17 + actual = substitute { 18 + src = builtins.toFile "source" '' 19 + Hello world! 20 + ''; 21 + substitutions = [ 22 + "--replace-fail" 23 + "Hello world!" 24 + "Yo peter!" 25 + ]; 26 + }; 27 + expected = builtins.toFile "expected" '' 28 + Yo peter! 29 + ''; 30 + }; 31 + 32 + legacySingleReplace = testers.testEqualContents { 33 + assertion = "substitute-single-replace"; 34 + actual = substituteSilent { 35 + src = builtins.toFile "source" '' 36 + Hello world! 37 + ''; 38 + replacements = [ 39 + "--replace-fail" "world" "paul" 40 + ]; 41 + }; 42 + expected = builtins.toFile "expected" '' 43 + Hello paul! 44 + ''; 45 + }; 46 + 47 + legacyString = testers.testEqualContents { 48 + assertion = "substitute-string"; 49 + actual = substituteSilent { 50 + src = builtins.toFile "source" '' 51 + Hello world! 52 + ''; 53 + # Not great that this works at all, but is supported 54 + replacements = "--replace-fail world string"; 55 + }; 56 + expected = builtins.toFile "expected" '' 57 + Hello string! 58 + ''; 59 + }; 60 + 61 + legacySingleArg = testers.testEqualContents { 62 + assertion = "substitute-single-arg"; 63 + actual = substituteSilent { 64 + src = builtins.toFile "source" '' 65 + Hello world! 66 + ''; 67 + # Not great that this works at all, but is supported 68 + replacements = [ 69 + "--replace-fail world list" 70 + ]; 71 + }; 72 + expected = builtins.toFile "expected" '' 73 + Hello list! 74 + ''; 75 + }; 76 + 77 + legacyVar = testers.testEqualContents { 78 + assertion = "substitute-var"; 79 + actual = substituteSilent { 80 + src = builtins.toFile "source" '' 81 + @greeting@ @name@! 82 + ''; 83 + # Not great that this works at all, but is supported 84 + replacements = [ 85 + "--subst-var name" 86 + "--subst-var-by greeting Yo" 87 + ]; 88 + name = "peter"; 89 + }; 90 + expected = builtins.toFile "expected" '' 91 + Yo peter! 92 + ''; 93 + }; 94 + 95 + 96 + }