about summary refs log tree commit diff
path: root/lib/fileset/default.nix
diff options
context:
space:
mode:
authorSilvan Mosberger <silvan.mosberger@tweag.io>2023-09-13 23:29:57 +0200
committerSilvan Mosberger <silvan.mosberger@tweag.io>2023-09-21 00:20:58 +0200
commitbd52895222b90c6dc75b081cb8f263e6bfbd1bf0 (patch)
tree149c3394bb5fd7e9655f4eff009564ba31a6fe79 /lib/fileset/default.nix
parentd866a0bda162155df43c019e1c4a4c9ef89470eb (diff)
lib.fileset.unions: init
Diffstat (limited to 'lib/fileset/default.nix')
-rw-r--r--lib/fileset/default.nix65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/fileset/default.nix b/lib/fileset/default.nix
index d04a653bd91b0..1bda8ef789a42 100644
--- a/lib/fileset/default.nix
+++ b/lib/fileset/default.nix
@@ -9,11 +9,16 @@ let
     ;
 
   inherit (builtins)
+    isList
     isPath
     pathExists
     typeOf
     ;
 
+  inherit (lib.lists)
+    imap0
+    ;
+
   inherit (lib.path)
     hasPrefix
     splitRoot
@@ -135,6 +140,8 @@ The only way to change which files get added to the store is by changing the `fi
 
   /*
     The file set containing all files that are in either of two given file sets.
+    This is the same as [`unions`](#function-library-lib.fileset.unions),
+    but takes just two file sets instead of a list.
     See also [Union (set theory)](https://en.wikipedia.org/wiki/Union_(set_theory)).
 
     The given file sets are evaluated as lazily as possible,
@@ -175,4 +182,62 @@ The only way to change which files get added to the store is by changing the `fi
     in
     _unionMany filesets;
 
+  /*
+    The file set containing all files that are in any of the given file sets.
+    This is the same as [`union`](#function-library-lib.fileset.unions),
+    but takes a list of file sets instead of just two.
+    See also [Union (set theory)](https://en.wikipedia.org/wiki/Union_(set_theory)).
+
+    The given file sets are evaluated as lazily as possible,
+    with earlier elements being evaluated first if needed.
+
+    Type:
+      unions :: [ FileSet ] -> FileSet
+
+    Example:
+      # Create a file set containing selected files
+      unions [
+        # Include the single file `Makefile` in the current directory
+        # This errors if the file doesn't exist
+        ./Makefile
+
+        # Recursively include all files in the `src/code` directory
+        # If this directory is empty this has no effect
+        ./src/code
+
+        # Include the files `run.sh` and `unit.c` from the `tests` directory
+        ./tests/run.sh
+        ./tests/unit.c
+
+        # Include the `LICENSE` file from the parent directory
+        ../LICENSE
+      ]
+  */
+  unions =
+    # A list of file sets.
+    # Must contain at least 1 element.
+    # The elements can also be paths,
+    # which get [implicitly coerced to file sets](#sec-fileset-path-coercion).
+    filesets:
+    let
+      # We cannot rename matched attribute arguments, so let's work around it with an extra `let in` statement
+      maybeFilesets = filesets;
+    in
+    let
+      # Annotate the elements with context, used by _coerceMany for better errors
+      annotated = imap0 (i: el: {
+        context = "element ${toString i} of the argument";
+        value = el;
+      }) maybeFilesets;
+
+      filesets = _coerceMany "lib.fileset.unions" annotated;
+    in
+    if ! isList maybeFilesets then
+      throw "lib.fileset.unions: Expected argument to be a list, but got a ${typeOf maybeFilesets}."
+    else if maybeFilesets == [ ] then
+      # TODO: This could be supported, but requires an extra internal representation for the empty file set
+      throw "lib.fileset.unions: Expected argument to be a list with at least one element, but it contains no elements."
+    else
+      _unionMany filesets;
+
 }