From 1cc2c2f13d7a548759a55f710fd0222da14c5403 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Tue, 7 Nov 2023 01:04:13 +0100 Subject: [PATCH] lib.fileset.maybeMissing: init --- lib/fileset/README.md | 5 ----- lib/fileset/default.nix | 31 +++++++++++++++++++++++++++++++ lib/fileset/internal.nix | 3 ++- lib/fileset/tests.sh | 37 ++++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/lib/fileset/README.md b/lib/fileset/README.md index 14b6877a9065..f44df6fffeca 100644 --- a/lib/fileset/README.md +++ b/lib/fileset/README.md @@ -252,8 +252,3 @@ The `fileFilter` function takes a path, and not a file set, as its second argume - (+) That can change depending on which files are included, so if it's used for `fileFilter` it would change the `subpath`/`components` value depending on which files are included. - (+) If necessary, this restriction can be relaxed later, the opposite wouldn't be possible - -## To update in the future - -Here's a list of places in the library that need to be updated in the future: -- If/Once a function exists that can optionally include a path depending on whether it exists, the error message for the path not existing in `_coerce` should mention the new function diff --git a/lib/fileset/default.nix b/lib/fileset/default.nix index 2cb361ec9ba1..9ccbf0ed7ce7 100644 --- a/lib/fileset/default.nix +++ b/lib/fileset/default.nix @@ -11,6 +11,10 @@ Basics: - [Implicit coercion from paths to file sets](#sec-fileset-path-coercion) + - [`lib.fileset.maybeMissing`](#function-library-lib.fileset.maybeMissing): + + Create a file set from a path that may be missing. + - [`lib.fileset.trace`](#function-library-lib.fileset.trace)/[`lib.fileset.traceVal`](#function-library-lib.fileset.trace): Pretty-print file sets for debugging. @@ -105,6 +109,7 @@ let _difference _mirrorStorePath _fetchGitSubmodulesMinver + _emptyWithoutBase ; inherit (builtins) @@ -148,6 +153,32 @@ let in { + /* + Create a file set from a path that may or may not exist: + - If the path does exist, the path is [coerced to a file set](#sec-fileset-path-coercion). + - If the path does not exist, a file set containing no files is returned. + + Type: + maybeMissing :: Path -> FileSet + + Example: + # All files in the current directory, but excluding main.o if it exists + difference ./. (maybeMissing ./main.o) + */ + maybeMissing = + path: + if ! isPath path then + if isStringLike path then + throw '' + lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.'' + else + throw '' + lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead.'' + else if ! pathExists path then + _emptyWithoutBase + else + _singleton path; + /* Incrementally evaluate and trace a file set in a pretty way. This function is only intended for debugging purposes. diff --git a/lib/fileset/internal.nix b/lib/fileset/internal.nix index 23d7b847204c..2fddf0d02285 100644 --- a/lib/fileset/internal.nix +++ b/lib/fileset/internal.nix @@ -181,7 +181,8 @@ rec { ${context} is of type ${typeOf value}, but it should be a file set or a path instead.'' else if ! pathExists value then throw '' - ${context} (${toString value}) is a path that does not exist.'' + ${context} (${toString value}) is a path that does not exist. + To create a file set from a path that may not exist, use `lib.fileset.maybeMissing`.'' else _singleton value; diff --git a/lib/fileset/tests.sh b/lib/fileset/tests.sh index 06f92f297d88..81376bc451b1 100755 --- a/lib/fileset/tests.sh +++ b/lib/fileset/tests.sh @@ -413,7 +413,8 @@ expectFailure 'toSource { root = ./.; fileset = cleanSourceWith { src = ./.; }; \s*Note that this only works for sources created from paths.' # Path coercion errors for non-existent paths -expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist.' +expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist. +\s*To create a file set from a path that may not exist, use `lib.fileset.maybeMissing`.' # File sets cannot be evaluated directly expectFailure 'union ./. ./.' 'lib.fileset: Directly evaluating a file set is not supported. @@ -1450,6 +1451,40 @@ checkGitTracked rm -rf -- * +## lib.fileset.maybeMissing + +# Argument must be a path +expectFailure 'maybeMissing "someString"' 'lib.fileset.maybeMissing: Argument \("someString"\) is a string-like value, but it should be a path instead.' +expectFailure 'maybeMissing null' 'lib.fileset.maybeMissing: Argument is of type null, but it should be a path instead.' + +tree=( +) +checkFileset 'maybeMissing ./a' +checkFileset 'maybeMissing ./b' +checkFileset 'maybeMissing ./b/c' + +# Works on single files +tree=( + [a]=1 + [b/c]=0 + [b/d]=0 +) +checkFileset 'maybeMissing ./a' +tree=( + [a]=0 + [b/c]=1 + [b/d]=0 +) +checkFileset 'maybeMissing ./b/c' + +# Works on directories +tree=( + [a]=0 + [b/c]=1 + [b/d]=1 +) +checkFileset 'maybeMissing ./b' + # TODO: Once we have combinators and a property testing library, derive property tests from https://en.wikipedia.org/wiki/Algebra_of_sets echo >&2 tests ok