summary refs log tree commit diff
diff options
context:
space:
mode:
authorSilvan Mosberger <silvan.mosberger@tweag.io>2022-12-23 21:04:14 +0100
committerSilvan Mosberger <silvan.mosberger@tweag.io>2023-01-03 13:20:36 +0100
commit98fbcf17888872f5ebdf9fb6247266929f4308db (patch)
tree9244e627da309f1414891e951e54f383b8b37b24
parentba7ed22f844b984a1da0031da736d13a11509bb7 (diff)
downloadnixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar.gz
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar.bz2
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar.lz
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar.xz
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.tar.zst
nixpkgs-98fbcf17888872f5ebdf9fb6247266929f4308db.zip
lib.path.subpath.isValid: init
The first path library function
-rw-r--r--doc/doc-support/default.nix1
-rw-r--r--lib/default.nix3
-rw-r--r--lib/path/default.nix75
-rw-r--r--lib/path/tests/default.nix27
-rw-r--r--lib/path/tests/unit.nix76
-rw-r--r--lib/tests/release.nix3
6 files changed, 184 insertions, 1 deletions
diff --git a/doc/doc-support/default.nix b/doc/doc-support/default.nix
index ec180064c35..e9cb96e37fd 100644
--- a/doc/doc-support/default.nix
+++ b/doc/doc-support/default.nix
@@ -12,6 +12,7 @@ let
     { name = "lists"; description = "list manipulation functions"; }
     { name = "debug"; description = "debugging functions"; }
     { name = "options"; description = "NixOS / nixpkgs option handling"; }
+    { name = "path"; description = "path functions"; }
     { name = "filesystem"; description = "filesystem functions"; }
     { name = "sources"; description = "source filtering functions"; }
     { name = "cli"; description = "command-line serialization functions"; }
diff --git a/lib/default.nix b/lib/default.nix
index 68e5b8dea1e..15fe542c574 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -27,7 +27,6 @@ let
     maintainers = import ../maintainers/maintainer-list.nix;
     teams = callLibs ../maintainers/team-list.nix;
     meta = callLibs ./meta.nix;
-    sources = callLibs ./sources.nix;
     versions = callLibs ./versions.nix;
 
     # module system
@@ -53,7 +52,9 @@ let
     fetchers = callLibs ./fetchers.nix;
 
     # Eval-time filesystem handling
+    path = callLibs ./path;
     filesystem = callLibs ./filesystem.nix;
+    sources = callLibs ./sources.nix;
 
     # back-compat aliases
     platforms = self.systems.doubles;
diff --git a/lib/path/default.nix b/lib/path/default.nix
new file mode 100644
index 00000000000..59f670dfed0
--- /dev/null
+++ b/lib/path/default.nix
@@ -0,0 +1,75 @@
+# Functions for working with paths, see ./path.md
+{ lib }:
+let
+
+  inherit (builtins)
+    isString
+    match
+    ;
+
+  inherit (lib.strings)
+    substring
+    ;
+
+  inherit (lib.asserts)
+    assertMsg
+    ;
+
+  # Return the reason why a subpath is invalid, or `null` if it's valid
+  subpathInvalidReason = value:
+    if ! isString value then
+      "The given value is of type ${builtins.typeOf value}, but a string was expected"
+    else if value == "" then
+      "The given string is empty"
+    else if substring 0 1 value == "/" then
+      "The given string \"${value}\" starts with a `/`, representing an absolute path"
+    # We don't support ".." components, see ./path.md#parent-directory
+    else if match "(.*/)?\\.\\.(/.*)?" value != null then
+      "The given string \"${value}\" contains a `..` component, which is not allowed in subpaths"
+    else null;
+
+in /* No rec! Add dependencies on this file at the top. */ {
+
+
+  /* Whether a value is a valid subpath string.
+
+  - The value is a string
+
+  - The string is not empty
+
+  - The string doesn't start with a `/`
+
+  - The string doesn't contain any `..` path components
+
+  Type:
+    subpath.isValid :: String -> Bool
+
+  Example:
+    # Not a string
+    subpath.isValid null
+    => false
+
+    # Empty string
+    subpath.isValid ""
+    => false
+
+    # Absolute path
+    subpath.isValid "/foo"
+    => false
+
+    # Contains a `..` path component
+    subpath.isValid "../foo"
+    => false
+
+    # Valid subpath
+    subpath.isValid "foo/bar"
+    => true
+
+    # Doesn't need to be normalised
+    subpath.isValid "./foo//bar/"
+    => true
+  */
+  subpath.isValid = value:
+    subpathInvalidReason value == null;
+
+}
diff --git a/lib/path/tests/default.nix b/lib/path/tests/default.nix
new file mode 100644
index 00000000000..784a3af68b6
--- /dev/null
+++ b/lib/path/tests/default.nix
@@ -0,0 +1,27 @@
+{
+  nixpkgs ? ../../..,
+  system ? builtins.currentSystem,
+  pkgs ? import nixpkgs {
+    config = {};
+    overlays = [];
+    inherit system;
+  },
+  libpath ? ../..,
+}:
+pkgs.runCommand "lib-path-tests" {
+  nativeBuildInputs = with pkgs; [
+    nix
+  ];
+} ''
+  # Needed to make Nix evaluation work
+  export NIX_STATE_DIR=$(mktemp -d)
+
+  cp -r ${libpath} lib
+  export TEST_LIB=$PWD/lib
+
+  echo "Running unit tests lib/path/tests/unit.nix"
+  nix-instantiate --eval lib/path/tests/unit.nix \
+    --argstr libpath "$TEST_LIB"
+
+  touch $out
+''
diff --git a/lib/path/tests/unit.nix b/lib/path/tests/unit.nix
new file mode 100644
index 00000000000..15f5940a51e
--- /dev/null
+++ b/lib/path/tests/unit.nix
@@ -0,0 +1,76 @@
+# Unit tests for lib.path functions. Use `nix-build` in this directory to
+# run these
+{ libpath }:
+let
+  lib = import libpath;
+  inherit (lib.path) subpath;
+
+  cases = lib.runTests {
+    testSubpathIsValidExample1 = {
+      expr = subpath.isValid null;
+      expected = false;
+    };
+    testSubpathIsValidExample2 = {
+      expr = subpath.isValid "";
+      expected = false;
+    };
+    testSubpathIsValidExample3 = {
+      expr = subpath.isValid "/foo";
+      expected = false;
+    };
+    testSubpathIsValidExample4 = {
+      expr = subpath.isValid "../foo";
+      expected = false;
+    };
+    testSubpathIsValidExample5 = {
+      expr = subpath.isValid "foo/bar";
+      expected = true;
+    };
+    testSubpathIsValidExample6 = {
+      expr = subpath.isValid "./foo//bar/";
+      expected = true;
+    };
+    testSubpathIsValidTwoDotsEnd = {
+      expr = subpath.isValid "foo/..";
+      expected = false;
+    };
+    testSubpathIsValidTwoDotsMiddle = {
+      expr = subpath.isValid "foo/../bar";
+      expected = false;
+    };
+    testSubpathIsValidTwoDotsPrefix = {
+      expr = subpath.isValid "..foo";
+      expected = true;
+    };
+    testSubpathIsValidTwoDotsSuffix = {
+      expr = subpath.isValid "foo..";
+      expected = true;
+    };
+    testSubpathIsValidTwoDotsPrefixComponent = {
+      expr = subpath.isValid "foo/..bar/baz";
+      expected = true;
+    };
+    testSubpathIsValidTwoDotsSuffixComponent = {
+      expr = subpath.isValid "foo/bar../baz";
+      expected = true;
+    };
+    testSubpathIsValidThreeDots = {
+      expr = subpath.isValid "...";
+      expected = true;
+    };
+    testSubpathIsValidFourDots = {
+      expr = subpath.isValid "....";
+      expected = true;
+    };
+    testSubpathIsValidThreeDotsComponent = {
+      expr = subpath.isValid "foo/.../bar";
+      expected = true;
+    };
+    testSubpathIsValidFourDotsComponent = {
+      expr = subpath.isValid "foo/..../bar";
+      expected = true;
+    };
+  };
+in
+  if cases == [] then "Unit tests successful"
+  else throw "Path unit tests failed: ${lib.generators.toPretty {} cases}"
diff --git a/lib/tests/release.nix b/lib/tests/release.nix
index b93a4236f91..f67892ab962 100644
--- a/lib/tests/release.nix
+++ b/lib/tests/release.nix
@@ -15,6 +15,9 @@ pkgs.runCommand "nixpkgs-lib-tests" {
       inherit pkgs;
       lib = import ../.;
     })
+    (import ../path/tests {
+      inherit pkgs;
+    })
   ];
 } ''
     datadir="${pkgs.nix}/share"