Skip to content

Commit b3fb9af

Browse files
replaceVarsWith: init (#360771)
2 parents aeaec7c + 4ce241c commit b3fb9af

15 files changed

Lines changed: 281 additions & 182 deletions

File tree

nixos/modules/installer/tools/tools.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ let
4343
manPage = ./manpages/nixos-version.8;
4444
};
4545

46-
nixos-install = pkgs.nixos-install.override { nix = config.nix.package; };
46+
nixos-install = pkgs.nixos-install.override { };
4747
nixos-rebuild = pkgs.nixos-rebuild.override { nix = config.nix.package; };
4848
nixos-rebuild-ng = pkgs.nixos-rebuild-ng.override {
4949
nix = config.nix.package;

pkgs/build-support/replace-vars/default.nix

Lines changed: 0 additions & 86 deletions
This file was deleted.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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+
59+
let
60+
# We use `--replace-fail` instead of `--subst-var-by` so that if the thing isn't there, we fail.
61+
subst-var-by =
62+
name: value:
63+
lib.optionals (value != null) [
64+
"--replace-fail"
65+
(lib.escapeShellArg "@${name}@")
66+
(lib.escapeShellArg value)
67+
];
68+
69+
substitutions = lib.concatLists (lib.mapAttrsToList subst-var-by replacements);
70+
71+
left-overs = map ({ name, ... }: name) (
72+
builtins.filter ({ value, ... }: value == null) (lib.attrsToList replacements)
73+
);
74+
75+
optionalAttrs =
76+
if (builtins.intersectAttrs attrs forcedAttrs == { }) then
77+
builtins.removeAttrs attrs [ "replacements" ]
78+
else
79+
throw "Passing any of ${builtins.concatStringsSep ", " (builtins.attrNames forcedAttrs)} to replaceVarsWith is not supported.";
80+
81+
forcedAttrs = {
82+
doCheck = true;
83+
dontUnpack = true;
84+
preferLocalBuild = true;
85+
allowSubstitutes = false;
86+
87+
buildPhase = ''
88+
runHook preBuild
89+
90+
target=$out
91+
if test -n "$dir"; then
92+
target=$out/$dir/$name
93+
mkdir -p $out/$dir
94+
fi
95+
96+
substitute "$src" "$target" ${lib.concatStringsSep " " substitutions}
97+
98+
if test -n "$isExecutable"; then
99+
chmod +x $target
100+
fi
101+
102+
runHook postBuild
103+
'';
104+
105+
# Look for Nix identifiers surrounded by `@` that aren't substituted.
106+
checkPhase =
107+
let
108+
lookahead =
109+
if builtins.length left-overs == 0 then "" else "(?!${builtins.concatStringsSep "|" left-overs}@)";
110+
regex = lib.escapeShellArg "@${lookahead}[a-zA-Z_][0-9A-Za-z_'-]*@";
111+
in
112+
''
113+
runHook preCheck
114+
if grep -Pqe ${regex} "$out"; then
115+
echo The following look like unsubstituted Nix identifiers that remain in "$out":
116+
grep -Poe ${regex} "$out"
117+
echo Use the more precise '`substitute`' function if this check is in error.
118+
exit 1
119+
fi
120+
runHook postCheck
121+
'';
122+
};
123+
in
124+
125+
stdenvNoCC.mkDerivation (
126+
{
127+
name = baseNameOf (toString src);
128+
}
129+
// optionalAttrs
130+
// forcedAttrs
131+
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{ replaceVarsWith }:
2+
3+
/**
4+
`replaceVars` 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+
# Example
27+
28+
```nix
29+
{ replaceVars }:
30+
31+
replaceVars ./greeting.txt { world = "hello"; }
32+
```
33+
34+
See `../../test/replace-vars/default.nix` for tests of this function.
35+
*/
36+
src: replacements: replaceVarsWith { inherit src replacements; }

pkgs/by-name/de/deterministic-uname/deterministic-uname.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#! @shell@
1+
#! @runtimeShell@
22

33
set -o errexit
44
set -o nounset

pkgs/by-name/de/deterministic-uname/package.nix

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,46 @@
1-
# expr and script based on our lsb_release
21
{ stdenv
32
, lib
4-
, substituteAll
3+
, replaceVarsWith
54
, coreutils
65
, getopt
6+
, runtimeShell
77
, modDirVersion ? ""
88
, forPlatform ? stdenv.buildPlatform
99
}:
1010

11-
substituteAll {
11+
replaceVarsWith {
1212
name = "uname";
1313

1414
src = ./deterministic-uname.sh;
1515

1616
dir = "bin";
1717
isExecutable = true;
1818

19-
inherit coreutils getopt;
20-
21-
uSystem = if forPlatform.uname.system != null then forPlatform.uname.system else "unknown";
22-
inherit (forPlatform.uname) processor;
23-
24-
# uname -o
25-
# maybe add to lib/systems/default.nix uname attrset
26-
# https://github.com/coreutils/coreutils/blob/7fc84d1c0f6b35231b0b4577b70aaa26bf548a7c/src/uname.c#L373-L374
27-
# https://stackoverflow.com/questions/61711186/where-does-host-operating-system-in-uname-c-comes-from
28-
# https://github.com/coreutils/gnulib/blob/master/m4/host-os.m4
29-
operatingSystem =
30-
if forPlatform.isLinux
31-
then "GNU/Linux"
32-
else if forPlatform.isDarwin
33-
then "Darwin" # darwin isn't in host-os.m4 so where does this come from?
34-
else if forPlatform.isFreeBSD
35-
then "FreeBSD"
36-
else "unknown";
37-
38-
# in os-specific/linux module packages
39-
# --replace '$(shell uname -r)' "${kernel.modDirVersion}" \
40-
# is a common thing to do.
41-
modDirVersion = if modDirVersion != "" then modDirVersion else "unknown";
19+
replacements = {
20+
inherit coreutils getopt runtimeShell;
21+
22+
uSystem = if forPlatform.uname.system != null then forPlatform.uname.system else "unknown";
23+
inherit (forPlatform.uname) processor;
24+
25+
# uname -o
26+
# maybe add to lib/systems/default.nix uname attrset
27+
# https://github.com/coreutils/coreutils/blob/7fc84d1c0f6b35231b0b4577b70aaa26bf548a7c/src/uname.c#L373-L374
28+
# https://stackoverflow.com/questions/61711186/where-does-host-operating-system-in-uname-c-comes-from
29+
# https://github.com/coreutils/gnulib/blob/master/m4/host-os.m4
30+
operatingSystem =
31+
if forPlatform.isLinux
32+
then "GNU/Linux"
33+
else if forPlatform.isDarwin
34+
then "Darwin" # darwin isn't in host-os.m4 so where does this come from?
35+
else if forPlatform.isFreeBSD
36+
then "FreeBSD"
37+
else "unknown";
38+
39+
# in os-specific/linux module packages
40+
# --replace '$(shell uname -r)' "${kernel.modDirVersion}" \
41+
# is a common thing to do.
42+
modDirVersion = if modDirVersion != "" then modDirVersion else "unknown";
43+
};
4244

4345
meta = with lib; {
4446
description = "Print certain system information (hardcoded with lib/system values)";
Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
{
2-
replaceVars,
3-
runCommand,
2+
replaceVarsWith,
43
lib,
54
runtimeShell,
65
coreutils,
76
getopt,
87
}:
98

10-
runCommand "lsb_release"
11-
{
12-
meta = with lib; {
13-
description = "Prints certain LSB (Linux Standard Base) and Distribution information";
14-
mainProgram = "lsb_release";
15-
license = [ licenses.mit ];
16-
maintainers = with maintainers; [ primeos ];
17-
platforms = platforms.linux;
18-
};
19-
}
20-
''
21-
install -Dm 555 ${
22-
replaceVars ./lsb_release.sh {
23-
inherit runtimeShell coreutils getopt;
24-
}
25-
} $out/bin/lsb_release
26-
''
9+
replaceVarsWith {
10+
name = "lsb_release";
11+
12+
src = ./lsb_release.sh;
13+
14+
dir = "bin";
15+
isExecutable = true;
16+
17+
replacements = {
18+
inherit coreutils getopt runtimeShell;
19+
};
20+
21+
meta = with lib; {
22+
description = "Prints certain LSB (Linux Standard Base) and Distribution information";
23+
mainProgram = "lsb_release";
24+
license = [ licenses.mit ];
25+
maintainers = with maintainers; [ primeos ];
26+
platforms = platforms.linux;
27+
};
28+
}

0 commit comments

Comments
 (0)