query
On this page

writeStringReferencesToFile

pkgs.writeStringReferencesToFile

Docs pulled from | This Revision | about 1 hour ago


Extract a string's references to derivations and paths (its context) and write them to a text file, removing the input string itself from the dependency graph. This is useful when you want to make a derivation depend on the string's references, but not its contents (to avoid unnecessary rebuilds, for example).

Note that this only works as intended on Nix >= 2.3.

Inputs

string

1. Function argument


Noogle detected

Implementation

The following is the current implementation of this function.

writeStringReferencesToFile =
    string:
    /**
      The basic operation this performs is to copy the string context
      from `string` to a second string and wrap that string in a
      derivation. However, that alone is not enough, since nothing in the
      string refers to the output paths of the derivations/paths in its
      context, meaning they'll be considered build-time dependencies and
      removed from the wrapper derivation's closure. Putting the
      necessary output paths in the new string is however not very
      straightforward - the attrset returned by `getContext` contains
      only references to derivations' .drv-paths, not their output
      paths. In order to "convert" them, we try to extract the
      corresponding paths from the original string using regex.
    */
    let
      # Taken from https://github.com/NixOS/nix/blob/130284b8508dad3c70e8160b15f3d62042fc730a/src/libutil/hash.cc#L84
      nixHashChars = "0123456789abcdfghijklmnpqrsvwxyz";
      context = builtins.getContext string;
      derivations = lib.filterAttrs (n: v: v ? outputs) context;
      # Objects copied from outside of the store, such as paths and
      # `builtins.fetch*`ed ones
      sources = lib.attrNames (lib.filterAttrs (n: v: v ? path) context);
      packages = lib.mapAttrs' (name: value: {
        inherit value;
        name = lib.head (builtins.match "${builtins.storeDir}/[${nixHashChars}]+-(.*)\\.drv" name);
      }) derivations;
      # The syntax of output paths differs between outputs named `out`
      # and other, explicitly named ones. For explicitly named ones,
      # the output name is suffixed as `-name`, but `out` outputs
      # aren't suffixed at all, and thus aren't easily distinguished
      # from named output paths. Therefore, we find all the named ones
      # first so we can use them to remove false matches when looking
      # for `out` outputs (see the definition of `outputPaths`).
      namedOutputPaths = lib.flatten (
        lib.mapAttrsToList (
          name: value:
          (map (
            output:
            lib.filter lib.isList (
              builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name}-${output})" string
            )
          ) (lib.remove "out" value.outputs))
        ) packages
      );
      # Only `out` outputs
      outputPaths = lib.flatten (
        lib.mapAttrsToList (
          name: value:
          if lib.elem "out" value.outputs then
            lib.filter (
              x:
              lib.isList x
              &&
                # If the matched path is in `namedOutputPaths`,
                # it's a partial match of an output path where
                # the output name isn't `out`
                lib.all (o: !lib.hasPrefix (lib.head x) o) namedOutputPaths
            ) (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name})" string)
          else
            [ ]
        ) packages
      );
      allPaths = lib.concatStringsSep "\n" (lib.unique (sources ++ namedOutputPaths ++ outputPaths));
      allPathsWithContext = builtins.appendContext allPaths context;
    in
    if builtins ? getContext then
      writeText "string-references" allPathsWithContext
    else
      writeDirectReferencesToFile (writeText "string-file" string);