From 66fa718cebb4808a95c17e7ee692cf8e5dc87653 Mon Sep 17 00:00:00 2001 From: sterni Date: Sat, 11 Sep 2021 18:47:18 +0200 Subject: feat(nix/utils): expose pathType of symlink target In order to make readTree import symlinked directories I've been looking into how to detect if a symlink points to a directory (since this would allow us to use symlinks for //nix/sparseTree). I've found a hack for this: symlinkPointsToDir = path: isSymlink path && builtins.pathExists (toString path + "/.") Unfortunately it doesn't seem to be possible to distinguish whether the symlink target does not exist or is a regular file. Since it's possible, I thought might as well add this to `pathType`. To make returning the extra information workable, I've elected to use the attribute set layout used by `//nix/tag`. This doesn't require us to depend anything (as opposed to yants), but gives us pattern matching (via `nix.tag.match`) and also quite idiomatic checking of pathTypes: pathType ./foo ? file (pathType ./foo).symlink or null == "symlink-directory" Nonexistent paths are encoded like this: pathType ./foo ? missing Of course we can't use this in readTree (since it must be zero dependency), but we can easily inline this hack at some point. Change-Id: I15b64a1ea69953c95dc3239ef5860623652b3089 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3535 Tested-by: BuildkiteCI Reviewed-by: Profpatsch Reviewed-by: tazjin --- nix/utils/tests/default.nix | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'nix/utils/tests/default.nix') diff --git a/nix/utils/tests/default.nix b/nix/utils/tests/default.nix index 366ddd7c9c94..1ba68486077e 100644 --- a/nix/utils/tests/default.nix +++ b/nix/utils/tests/default.nix @@ -11,8 +11,10 @@ let inherit (depot.nix.utils) isDirectory + realPathIsDirectory isRegularFile isSymlink + pathType storePathName ; @@ -29,6 +31,13 @@ let (isDirectory ./symlink-directory) false) (assertUtilsPred "file not isDirectory" (isDirectory ./directory/file) false) + # realPathIsDirectory + (assertUtilsPred "directory realPathIsDirectory" + (realPathIsDirectory ./directory) true) + (assertUtilsPred "symlink to directory realPathIsDirectory" + (realPathIsDirectory ./symlink-directory) true) + (assertUtilsPred "realPathIsDirectory resolves chained symlinks" + (realPathIsDirectory ./symlink-symlink-directory) true) # isRegularFile (assertUtilsPred "file isRegularFile" (isRegularFile ./directory/file) true) @@ -52,12 +61,27 @@ let # missing files throw (assertThrows "isDirectory throws on missing file" (isDirectory ./does-not-exist)) + (assertThrows "realPathIsDirectory throws on missing file" + (realPathIsDirectory ./does-not-exist)) (assertThrows "isRegularFile throws on missing file" (isRegularFile ./does-not-exist)) (assertThrows "isSymlink throws on missing file" (isSymlink ./does-not-exist)) ]); + symlinkPathTypeTests = it "correctly judges symlinks" [ + (assertEq "symlinks to directories are detected correcty" + ((pathType ./symlink-directory).symlink or null) "directory") + (assertEq "symlinks to symlinks to directories are detected correctly" + ((pathType ./symlink-symlink-directory).symlink or null) "directory") + (assertEq "symlinks to files are detected-ish" + ((pathType ./symlink-file).symlink or null) "regular-or-missing") + (assertEq "symlinks to symlinks to files are detected-ish" + ((pathType ./symlink-symlink-file).symlink or null) "regular-or-missing") + (assertEq "symlinks to nowhere are not distinguished from files" + ((pathType ./missing).symlink or null) "regular-or-missing") + ]; + cheddarStorePath = builtins.unsafeDiscardStringContext depot.tools.cheddar.outPath; @@ -75,5 +99,6 @@ in runTestsuite "nix.utils" [ pathPredicates + symlinkPathTypeTests storePathNameTests ] -- cgit 1.4.1