From 98fbcf17888872f5ebdf9fb6247266929f4308db Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 23 Dec 2022 21:04:14 +0100 Subject: [PATCH] lib.path.subpath.isValid: init The first path library function --- doc/doc-support/default.nix | 1 + lib/default.nix | 3 +- lib/path/default.nix | 75 ++++++++++++++++++++++++++++++++++++ lib/path/tests/default.nix | 27 +++++++++++++ lib/path/tests/unit.nix | 76 +++++++++++++++++++++++++++++++++++++ lib/tests/release.nix | 3 ++ 6 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 lib/path/default.nix create mode 100644 lib/path/tests/default.nix create mode 100644 lib/path/tests/unit.nix diff --git a/doc/doc-support/default.nix b/doc/doc-support/default.nix index ec180064c35d..e9cb96e37fdd 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 68e5b8dea1eb..15fe542c574a 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 000000000000..59f670dfed0f --- /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 000000000000..784a3af68b6e --- /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 000000000000..15f5940a51e0 --- /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 b93a4236f91e..f67892ab962f 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"