summary refs log tree commit diff
path: root/lib/path
diff options
context:
space:
mode:
authorRobert Hensing <roberth@users.noreply.github.com>2023-08-04 17:00:46 +0200
committerGitHub <noreply@github.com>2023-08-04 17:00:46 +0200
commit8fa169707fa055994fe60f194027629fee8e417a (patch)
tree22e7bdef086799cabf7409ad5ce10c1327cafca4 /lib/path
parent35184dd3a52239b91a1eea5e430fa35c32139161 (diff)
parent407db583c54245136fe8e73976abadb7eb9fad80 (diff)
downloadnixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar.gz
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar.bz2
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar.lz
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar.xz
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.tar.zst
nixpkgs-8fa169707fa055994fe60f194027629fee8e417a.zip
Merge pull request #242695 from tweag/lib.path.subpath.components
`lib.path.subpath.components`: init
Diffstat (limited to 'lib/path')
-rw-r--r--lib/path/README.md21
-rw-r--r--lib/path/default.nix31
-rw-r--r--lib/path/tests/unit.nix13
3 files changed, 65 insertions, 0 deletions
diff --git a/lib/path/README.md b/lib/path/README.md
index 87e552d120d..89eec18b113 100644
--- a/lib/path/README.md
+++ b/lib/path/README.md
@@ -187,6 +187,27 @@ Decision: All functions remove trailing slashes in their results.
 
 </details>
 
+### Prefer returning subpaths over components
+[subpath-preference]: #prefer-returning-subpaths-over-components
+
+Observing: Functions could return subpaths or lists of path component strings.
+
+Considering: Subpaths are used as inputs for some functions. Using them for outputs, too, makes the library more consistent and composable.
+
+Decision: Subpaths should be preferred over list of path component strings.
+
+<details>
+<summary>Arguments</summary>
+
+- (+) It is consistent with functions accepting subpaths, making the library more composable
+- (-) It is less efficient when the components are needed, because after creating the normalised subpath string, it will have to be parsed into components again
+  - (+) If necessary, we can still make it faster by adding builtins to Nix
+  - (+) Alternatively if necessary, versions of these functions that return components could later still be introduced.
+- (+) It makes the path library simpler because there's only two types (paths and subpaths). Only `lib.path.subpath.components` can be used to get a list of components.
+  And once we have a list of component strings, `lib.lists` and `lib.strings` can be used to operate on them.
+  For completeness, `lib.path.subpath.join` allows converting the list of components back to a subpath.
+</details>
+
 ## Other implementations and references
 
 - [Rust](https://doc.rust-lang.org/std/path/struct.Path.html)
diff --git a/lib/path/default.nix b/lib/path/default.nix
index 24a7f85affc..5c6c5f60895 100644
--- a/lib/path/default.nix
+++ b/lib/path/default.nix
@@ -438,6 +438,37 @@ in /* No rec! Add dependencies on this file at the top. */ {
               ${subpathInvalidReason path}''
       ) 0 subpaths;
 
+  /*
+  Split [a subpath](#function-library-lib.path.subpath.isValid) into its path component strings.
+  Throw an error if the subpath isn't valid.
+  Note that the returned path components are also valid subpath strings, though they are intentionally not [normalised](#function-library-lib.path.subpath.normalise).
+
+  Laws:
+
+  - Splitting a subpath into components and [joining](#function-library-lib.path.subpath.join) the components gives the same subpath but [normalised](#function-library-lib.path.subpath.normalise):
+
+        subpath.join (subpath.components s) == subpath.normalise s
+
+  Type:
+    subpath.components :: String -> [ String ]
+
+  Example:
+    subpath.components "."
+    => [ ]
+
+    subpath.components "./foo//bar/./baz/"
+    => [ "foo" "bar" "baz" ]
+
+    subpath.components "/foo"
+    => <error>
+  */
+  subpath.components =
+    subpath:
+    assert assertMsg (isValid subpath) ''
+      lib.path.subpath.components: Argument is not a valid subpath string:
+          ${subpathInvalidReason subpath}'';
+    splitRelPath subpath;
+
   /* Normalise a subpath. Throw an error if the subpath isn't valid, see
   `lib.path.subpath.isValid`
 
diff --git a/lib/path/tests/unit.nix b/lib/path/tests/unit.nix
index 8bfb6f20121..bad6560f13a 100644
--- a/lib/path/tests/unit.nix
+++ b/lib/path/tests/unit.nix
@@ -238,6 +238,19 @@ let
       expr = (builtins.tryEval (subpath.normalise "..")).success;
       expected = false;
     };
+
+    testSubpathComponentsExample1 = {
+      expr = subpath.components ".";
+      expected = [ ];
+    };
+    testSubpathComponentsExample2 = {
+      expr = subpath.components "./foo//bar/./baz/";
+      expected = [ "foo" "bar" "baz" ];
+    };
+    testSubpathComponentsExample3 = {
+      expr = (builtins.tryEval (subpath.components "/foo")).success;
+      expected = false;
+    };
   };
 in
   if cases == [] then "Unit tests successful"