Files
nixpkgs/pkgs/build-support/replace-vars/replace-vars-with.nix
NAHO c8d4dabc43 pkgs: remove optional builtins prefixes from prelude functions
Remove optional builtins prefixes from prelude functions by running:

    builtins=(
      abort
      baseNameOf
      break
      derivation
      derivationStrict
      dirOf
      false
      fetchGit
      fetchMercurial
      fetchTarball
      fetchTree
      fromTOML
      import
      isNull
      map
      null
      placeholder
      removeAttrs
      scopedImport
      throw
      toString
      true
    )

    fd \
      --type file \
      . \
      pkgs \
      --exec-batch sed --in-place --regexp-extended "
        s/\<builtins\.($(
          printf '%s\n' "${builtins[@]}" |
            paste --delimiter '|' --serial -
        ))\>/\1/g
      "

    nix fmt
2025-10-04 19:02:37 +02:00

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
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
)