
This also changes stdenv's substitute --replace-fail to error out when the replacement is the same as the search pattern, but can't be found. This should not cause any problems in existing code, from what I can tell from grepping nixpkgs. The exception for pattern==replacement was previously introduced all the way back in 5ff872aa24983cf3e1cf28bb990042846c1a97ee, but this was apparently only used to make the check for the warning "simpler".
130 lines
3.9 KiB
Nix
130 lines
3.9 KiB
Nix
{ lib, stdenvNoCC }:
|
|
|
|
/**
|
|
`replaceVarsWith` is a wrapper around the [bash function `substitute`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute)
|
|
in the stdenv. It allows for terse replacement of names in the specified path, while checking
|
|
for common mistakes such as naming a replacement that does nothing or forgetting a variable which
|
|
needs to be replaced.
|
|
|
|
As with the [`--subst-var-by`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute-subst-var-by)
|
|
flag, names are encoded as `@name@` in the provided file at the provided path.
|
|
|
|
Any unmatched variable names in the file at the provided path will cause a build failure.
|
|
|
|
By default, any remaining text that matches `@[A-Za-z_][0-9A-Za-z_'-]@` in the output after replacement
|
|
has occurred will cause a build failure. Variables can be excluded from this check by passing "null" for them.
|
|
|
|
# Inputs
|
|
|
|
`src` ([Store Path](https://nixos.org/manual/nix/latest/store/store-path.html#store-path) String)
|
|
: The file in which to replace variables.
|
|
|
|
`replacements` (AttrsOf String)
|
|
: Each entry in this set corresponds to a `--subst-var-by` entry in [`substitute`](https://nixos.org/manual/nixpkgs/stable/#fun-substitute) or
|
|
null to keep it unchanged.
|
|
|
|
`dir` (String)
|
|
: Sub directory in $out to store the result in. Commonly set to "bin".
|
|
|
|
`isExecutable` (Boolean)
|
|
: Whether to mark the output file as executable.
|
|
|
|
Most arguments supported by mkDerivation are also supported, with some exceptions for which
|
|
an error will be thrown.
|
|
|
|
# Example
|
|
|
|
```nix
|
|
{ replaceVarsWith }:
|
|
|
|
replaceVarsWith {
|
|
src = ./my-setup-hook.sh;
|
|
replacements = { world = "hello"; };
|
|
dir = "bin";
|
|
isExecutable = true;
|
|
}
|
|
```
|
|
|
|
See `../../test/replace-vars/default.nix` for tests of this function. Also see `replaceVars` for a short
|
|
version with src and replacements only.
|
|
*/
|
|
{
|
|
src,
|
|
replacements,
|
|
dir ? null,
|
|
isExecutable ? false,
|
|
...
|
|
}@attrs:
|
|
|
|
let
|
|
# We use `--replace-fail` instead of `--subst-var-by` so that if the thing isn't there, we fail.
|
|
subst-var-by = name: value: [
|
|
"--replace-fail"
|
|
(lib.escapeShellArg "@${name}@")
|
|
(lib.escapeShellArg (lib.defaultTo "@${name}@" value))
|
|
];
|
|
|
|
substitutions = lib.concatLists (lib.mapAttrsToList subst-var-by replacements);
|
|
|
|
left-overs = map ({ name, ... }: name) (
|
|
builtins.filter ({ value, ... }: value == null) (lib.attrsToList replacements)
|
|
);
|
|
|
|
optionalAttrs =
|
|
if (builtins.intersectAttrs attrs forcedAttrs == { }) then
|
|
builtins.removeAttrs attrs [ "replacements" ]
|
|
else
|
|
throw "Passing any of ${builtins.concatStringsSep ", " (builtins.attrNames forcedAttrs)} to replaceVarsWith is not supported.";
|
|
|
|
forcedAttrs = {
|
|
doCheck = true;
|
|
dontUnpack = true;
|
|
preferLocalBuild = true;
|
|
allowSubstitutes = false;
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
target=$out
|
|
if test -n "$dir"; then
|
|
target=$out/$dir/$name
|
|
mkdir -p $out/$dir
|
|
fi
|
|
|
|
substitute "$src" "$target" ${lib.concatStringsSep " " substitutions}
|
|
|
|
if test -n "$isExecutable"; then
|
|
chmod +x $target
|
|
fi
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
# Look for Nix identifiers surrounded by `@` that aren't substituted.
|
|
checkPhase =
|
|
let
|
|
lookahead =
|
|
if builtins.length left-overs == 0 then "" else "(?!${builtins.concatStringsSep "|" left-overs}@)";
|
|
regex = lib.escapeShellArg "@${lookahead}[a-zA-Z_][0-9A-Za-z_'-]*@";
|
|
in
|
|
''
|
|
runHook preCheck
|
|
if grep -Pqe ${regex} "$target"; then
|
|
echo The following look like unsubstituted Nix identifiers that remain in "$target":
|
|
grep -Poe ${regex} "$target"
|
|
echo Use the more precise '`substitute`' function if this check is in error.
|
|
exit 1
|
|
fi
|
|
runHook postCheck
|
|
'';
|
|
};
|
|
in
|
|
|
|
stdenvNoCC.mkDerivation (
|
|
{
|
|
name = baseNameOf (toString src);
|
|
}
|
|
// optionalAttrs
|
|
// forcedAttrs
|
|
)
|