summary refs log tree commit diff
path: root/lib/fileset
diff options
context:
space:
mode:
authorSilvan Mosberger <silvan.mosberger@tweag.io>2023-09-13 18:50:45 +0200
committerSilvan Mosberger <silvan.mosberger@tweag.io>2023-09-13 18:53:53 +0200
commit19b39dcc934aba37e39b5f492c2919dd93b74870 (patch)
tree35184a186a01641a4ee0ec6e9acda5d043e1b721 /lib/fileset
parent48abfde844547c1b62c8a082ccccd9caf2d650bd (diff)
downloadnixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar.gz
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar.bz2
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar.lz
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar.xz
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.tar.zst
nixpkgs-19b39dcc934aba37e39b5f492c2919dd93b74870.zip
lib.fileset: Internal representation v1
Diffstat (limited to 'lib/fileset')
-rw-r--r--lib/fileset/README.md12
-rw-r--r--lib/fileset/internal.nix64
-rwxr-xr-xlib/fileset/tests.sh12
3 files changed, 64 insertions, 24 deletions
diff --git a/lib/fileset/README.md b/lib/fileset/README.md
index dbb591a4c8c..306dcdaa421 100644
--- a/lib/fileset/README.md
+++ b/lib/fileset/README.md
@@ -41,13 +41,21 @@ An attribute set with these values:
 - `_type` (constant string `"fileset"`):
   Tag to indicate this value is a file set.
 
-- `_internalVersion` (constant string equal to the current version):
-  Version of the representation
+- `_internalVersion` (constant `1`, the current version):
+  Version of the representation.
 
 - `_internalBase` (path):
   Any files outside of this path cannot influence the set of files.
   This is always a directory.
 
+- `_internalBaseRoot` (path):
+  The filesystem root of `_internalBase`, same as `(lib.path.splitRoot _internalBase).root`.
+  This is here because this needs to be computed anyways, and this computation shouldn't be duplicated.
+
+- `_internalBaseComponents` (list of strings):
+  The path components of `_internalBase`, same as `lib.path.subpath.components (lib.path.splitRoot _internalBase).subpath`.
+  This is here because this needs to be computed anyways, and this computation shouldn't be duplicated.
+
 - `_internalTree` ([filesetTree](#filesettree)):
   A tree representation of all included files under `_internalBase`.
 
diff --git a/lib/fileset/internal.nix b/lib/fileset/internal.nix
index eeaa7d96875..ae8eb20e3ed 100644
--- a/lib/fileset/internal.nix
+++ b/lib/fileset/internal.nix
@@ -23,7 +23,9 @@ let
   inherit (lib.lists)
     all
     elemAt
+    foldl'
     length
+    sublist
     ;
 
   inherit (lib.path)
@@ -50,24 +52,48 @@ in
 rec {
 
   # If you change the internal representation, make sure to:
-  # - Update this version
-  # - Adjust _coerce to also accept and coerce older versions
+  # - Increment this version
+  # - Add an additional migration function below
   # - Update the description of the internal representation in ./README.md
-  _currentVersion = 0;
+  _currentVersion = 1;
+
+  # Migrations between versions. The 0th element converts from v0 to v1, and so on
+  migrations = [
+    # Convert v0 into v1: Add the _internalBase{Root,Components} attributes
+    (
+      filesetV0:
+      let
+        parts = splitRoot filesetV0._internalBase;
+      in
+      filesetV0 // {
+        _internalVersion = 1;
+        _internalBaseRoot = parts.root;
+        _internalBaseComponents = components parts.subpath;
+      }
+    )
+  ];
 
   # Create a fileset, see ./README.md#fileset
   # Type: path -> filesetTree -> fileset
-  _create = base: tree: {
-    _type = "fileset";
+  _create = base: tree:
+    let
+      # Decompose the base into its components
+      # See ../path/README.md for why we're not just using `toString`
+      parts = splitRoot base;
+    in
+    {
+      _type = "fileset";
 
-    _internalVersion = _currentVersion;
-    _internalBase = base;
-    _internalTree = tree;
+      _internalVersion = _currentVersion;
+      _internalBase = base;
+      _internalBaseRoot = parts.root;
+      _internalBaseComponents = components parts.subpath;
+      _internalTree = tree;
 
-    # Double __ to make it be evaluated and ordered first
-    __noEval = throw ''
-      lib.fileset: Directly evaluating a file set is not supported. Use `lib.fileset.toSource` to turn it into a usable source instead.'';
-  };
+      # Double __ to make it be evaluated and ordered first
+      __noEval = throw ''
+        lib.fileset: Directly evaluating a file set is not supported. Use `lib.fileset.toSource` to turn it into a usable source instead.'';
+    };
 
   # Coerce a value to a fileset, erroring when the value cannot be coerced.
   # The string gives the context for error messages.
@@ -80,6 +106,12 @@ rec {
               - Internal version of the file set: ${toString value._internalVersion}
               - Internal version of the library: ${toString _currentVersion}
               Make sure to update your Nixpkgs to have a newer version of `lib.fileset`.''
+      else if value._internalVersion < _currentVersion then
+        let
+          # Get all the migration functions necessary to convert from the old to the current version
+          migrationsToApply = sublist value._internalVersion (_currentVersion - value._internalVersion) migrations;
+        in
+        foldl' (value: migration: migration value) value migrationsToApply
       else
         value
     else if ! isPath value then
@@ -193,17 +225,13 @@ rec {
       # which has the effect that they aren't included in the result
       tree = _simplifyTree fileset._internalBase fileset._internalTree;
 
-      # Decompose the base into its components
-      # See ../path/README.md for why we're not just using `toString`
-      baseComponents = components (splitRoot fileset._internalBase).subpath;
-
       # The base path as a string with a single trailing slash
       baseString =
-        if baseComponents == [] then
+        if fileset._internalBaseComponents == [] then
           # Need to handle the filesystem root specially
           "/"
         else
-          "/" + concatStringsSep "/" baseComponents + "/";
+          "/" + concatStringsSep "/" fileset._internalBaseComponents + "/";
 
       baseLength = stringLength baseString;
 
diff --git a/lib/fileset/tests.sh b/lib/fileset/tests.sh
index 88cd4bcc47c..e27610573a8 100755
--- a/lib/fileset/tests.sh
+++ b/lib/fileset/tests.sh
@@ -264,17 +264,21 @@ expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `
 # File sets cannot be evaluated directly
 expectFailure '_create ./. null' 'lib.fileset: Directly evaluating a file set is not supported. Use `lib.fileset.toSource` to turn it into a usable source instead.'
 
+# Past versions of the internal representation are supported
+expectEqual '_coerce "<tests>: value" { _type = "fileset"; _internalVersion = 0; _internalBase = ./.; }' \
+    '{ _internalBase = ./.; _internalBaseComponents = path.subpath.components (path.splitRoot ./.).subpath; _internalBaseRoot = /.; _internalVersion = 1; _type = "fileset"; }'
+
 # Future versions of the internal representation are unsupported
-expectFailure '_coerce "<tests>: value" { _type = "fileset"; _internalVersion = 1; }' '<tests>: value is a file set created from a future version of the file set library with a different internal representation:
-\s*- Internal version of the file set: 1
-\s*- Internal version of the library: 0
+expectFailure '_coerce "<tests>: value" { _type = "fileset"; _internalVersion = 2; }' '<tests>: value is a file set created from a future version of the file set library with a different internal representation:
+\s*- Internal version of the file set: 2
+\s*- Internal version of the library: 1
 \s*Make sure to update your Nixpkgs to have a newer version of `lib.fileset`.'
 
 # _create followed by _coerce should give the inputs back without any validation
 expectEqual '{
   inherit (_coerce "<test>" (_create ./. "directory"))
     _internalVersion _internalBase _internalTree;
-}' '{ _internalBase = ./.; _internalTree = "directory"; _internalVersion = 0; }'
+}' '{ _internalBase = ./.; _internalTree = "directory"; _internalVersion = 1; }'
 
 #### Resulting store path ####