summary refs log tree commit diff
path: root/pkgs/build-support/trivial-builders.nix
diff options
context:
space:
mode:
authortalyz <kim.lindberger@gmail.com>2021-10-15 17:22:37 +0200
committerYuka <yuka@yuka.dev>2021-10-28 12:55:01 +0200
commitaa22fa9c0b6329e7d557be363c13508a8d46487d (patch)
tree24ad1feddfa314aead42131e4721c9b9b64a3e36 /pkgs/build-support/trivial-builders.nix
parentaf9f6d9a2aeb279408bcbb90db16ef3f727e2601 (diff)
downloadnixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar.gz
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar.bz2
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar.lz
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar.xz
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.tar.zst
nixpkgs-aa22fa9c0b6329e7d557be363c13508a8d46487d.zip
trivial-builders: Add writeStringReferencesToFile
Add writeStringReferencesToFile, a builder which extracts a string's
references to derivations and paths and writes 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 content (to avoid unnecessary rebuilds, for
example).
Diffstat (limited to 'pkgs/build-support/trivial-builders.nix')
-rw-r--r--pkgs/build-support/trivial-builders.nix82
1 files changed, 82 insertions, 0 deletions
diff --git a/pkgs/build-support/trivial-builders.nix b/pkgs/build-support/trivial-builders.nix
index f06d2136b8c..58cdeb269d5 100644
--- a/pkgs/build-support/trivial-builders.nix
+++ b/pkgs/build-support/trivial-builders.nix
@@ -465,6 +465,88 @@ rec {
     '';
 
 
+  /*
+   * 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.
+   */
+  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);
+
+
   /* Print an error message if the file with the specified name and
    * hash doesn't exist in the Nix store. This function should only
    * be used by non-redistributable software with an unfree license