Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ lib, stdenvNoCC }:
2
3/**
4 `replaceVarsWith` is a wrapper around the [bash function `substitute`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute)
5 in the stdenv. It allows for terse replacement of names in the specified path, while checking
6 for common mistakes such as naming a replacement that does nothing or forgetting a variable which
7 needs to be replaced.
8
9 As with the [`--subst-var-by`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute-subst-var-by)
10 flag, names are encoded as `@name@` in the provided file at the provided path.
11
12 Any unmatched variable names in the file at the provided path will cause a build failure.
13
14 By default, any remaining text that matches `@[A-Za-z_][0-9A-Za-z_'-]@` in the output after replacement
15 has occurred will cause a build failure. Variables can be excluded from this check by passing "null" for them.
16
17 # Inputs
18
19 `src` ([Store Path](https://nixos.org/manual/nix/latest/store/store-path.html#store-path) String)
20 : The file in which to replace variables.
21
22 `replacements` (AttrsOf String)
23 : Each entry in this set corresponds to a `--subst-var-by` entry in [`substitute`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute) or
24 null to keep it unchanged.
25
26 `dir` (String)
27 : Sub directory in $out to store the result in. Commonly set to "bin".
28
29 `isExecutable` (Boolean)
30 : Whether to mark the output file as executable.
31
32 Most arguments supported by mkDerivation are also supported, with some exceptions for which
33 an error will be thrown.
34
35 # Example
36
37 ```nix
38 { replaceVarsWith }:
39
40 replaceVarsWith {
41 src = ./my-setup-hook.sh;
42 replacements = { world = "hello"; };
43 dir = "bin";
44 isExecutable = true;
45 }
46 ```
47
48 See `../../test/replace-vars/default.nix` for tests of this function. Also see `replaceVars` for a short
49 version with src and replacements only.
50*/
51{
52 src,
53 replacements,
54 dir ? null,
55 isExecutable ? false,
56 ...
57}@attrs:
58
59let
60 # We use `--replace-fail` instead of `--subst-var-by` so that if the thing isn't there, we fail.
61 subst-var-by = name: value: [
62 "--replace-fail"
63 (lib.escapeShellArg "@${name}@")
64 (lib.escapeShellArg (lib.defaultTo "@${name}@" value))
65 ];
66
67 substitutions = lib.concatLists (lib.mapAttrsToList subst-var-by replacements);
68
69 left-overs = map ({ name, ... }: name) (
70 builtins.filter ({ value, ... }: value == null) (lib.attrsToList replacements)
71 );
72
73 optionalAttrs =
74 if (builtins.intersectAttrs attrs forcedAttrs == { }) then
75 builtins.removeAttrs attrs [ "replacements" ]
76 else
77 throw "Passing any of ${builtins.concatStringsSep ", " (builtins.attrNames forcedAttrs)} to replaceVarsWith is not supported.";
78
79 forcedAttrs = {
80 doCheck = true;
81 dontUnpack = true;
82 preferLocalBuild = true;
83 allowSubstitutes = false;
84
85 buildPhase = ''
86 runHook preBuild
87
88 target=$out
89 if test -n "$dir"; then
90 target=$out/$dir/$name
91 mkdir -p $out/$dir
92 fi
93
94 substitute "$src" "$target" ${lib.concatStringsSep " " substitutions}
95
96 if test -n "$isExecutable"; then
97 chmod +x $target
98 fi
99
100 runHook postBuild
101 '';
102
103 # Look for Nix identifiers surrounded by `@` that aren't substituted.
104 checkPhase =
105 let
106 lookahead =
107 if builtins.length left-overs == 0 then "" else "(?!${builtins.concatStringsSep "|" left-overs}@)";
108 regex = lib.escapeShellArg "@${lookahead}[a-zA-Z_][0-9A-Za-z_'-]*@";
109 in
110 ''
111 runHook preCheck
112 if grep -Pqe ${regex} "$target"; then
113 echo The following look like unsubstituted Nix identifiers that remain in "$target":
114 grep -Poe ${regex} "$target"
115 echo Use the more precise '`substitute`' function if this check is in error.
116 exit 1
117 fi
118 runHook postCheck
119 '';
120 };
121in
122
123stdenvNoCC.mkDerivation (
124 {
125 name = baseNameOf (toString src);
126 }
127 // optionalAttrs
128 // forcedAttrs
129)