diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/README.md | 20 | ||||
-rw-r--r-- | lib/customisation.nix | 18 | ||||
-rw-r--r-- | lib/default.nix | 2 | ||||
-rw-r--r-- | lib/fileset/README.md | 3 | ||||
-rw-r--r-- | lib/fileset/default.nix | 6 | ||||
-rw-r--r-- | lib/fileset/internal.nix | 39 | ||||
-rwxr-xr-x | lib/fileset/tests.sh | 27 | ||||
-rw-r--r-- | lib/trivial.nix | 34 |
8 files changed, 120 insertions, 29 deletions
diff --git a/lib/README.md b/lib/README.md index 627086843db7c..220940bc21224 100644 --- a/lib/README.md +++ b/lib/README.md @@ -74,3 +74,23 @@ path/tests/prop.sh # Run the lib.fileset tests fileset/tests.sh ``` + +## Commit conventions + +- Make sure you read about the [commit conventions](../CONTRIBUTING.md#commit-conventions) common to Nixpkgs as a whole. + +- Format the commit messages in the following way: + + ``` + lib.(section): (init | add additional argument | refactor | etc) + + (Motivation for change. Additional information.) + ``` + + Examples: + + * lib.getExe': check arguments + * lib.fileset: Add an additional argument in the design docs + + Closes #264537 + diff --git a/lib/customisation.nix b/lib/customisation.nix index c7d40339d05f5..08fc5db0614de 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -76,19 +76,22 @@ rec { Type: makeOverridable :: (AttrSet -> a) -> AttrSet -> a */ - makeOverridable = f: lib.setFunctionArgs - (origArgs: let + makeOverridable = f: + let + # Creates a functor with the same arguments as f + mirrorArgs = lib.mirrorFunctionArgs f; + in + mirrorArgs (origArgs: + let result = f origArgs; - # Creates a functor with the same arguments as f - copyArgs = g: lib.setFunctionArgs g (lib.functionArgs f); # Changes the original arguments with (potentially a function that returns) a set of new attributes overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs); # Re-call the function but with different arguments - overrideArgs = copyArgs (newArgs: makeOverridable f (overrideWith newArgs)); + overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs)); # Change the result of the function call by applying g to it - overrideResult = g: makeOverridable (copyArgs (args: g (f args))) origArgs; + overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs; in if builtins.isAttrs result then result // { @@ -102,8 +105,7 @@ rec { lib.setFunctionArgs result (lib.functionArgs result) // { override = overrideArgs; } - else result) - (lib.functionArgs f); + else result); /* Call the package function in the file `fn` with the required diff --git a/lib/default.nix b/lib/default.nix index 80fc17985879a..a2958e561cf32 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -74,7 +74,7 @@ let importJSON importTOML warn warnIf warnIfNot throwIf throwIfNot checkListOfEnum info showWarnings nixpkgsVersion version isInOldestRelease mod compare splitByAndCompare - functionArgs setFunctionArgs isFunction toFunction + functionArgs setFunctionArgs isFunction toFunction mirrorFunctionArgs toHexString toBaseDigits inPureEvalMode; inherit (self.fixedPoints) fix fix' converge extends composeExtensions composeManyExtensions makeExtensible makeExtensibleWithCustomName; diff --git a/lib/fileset/README.md b/lib/fileset/README.md index 8518d88a7d642..91f892a1be951 100644 --- a/lib/fileset/README.md +++ b/lib/fileset/README.md @@ -241,7 +241,4 @@ Arguments: ## To update in the future Here's a list of places in the library that need to be updated in the future: -- > The file set library is currently somewhat limited but is being expanded to include more functions over time. - - in [the manual](../../doc/functions/fileset.section.md) - 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 372d445269f55..d90c770633d83 100644 --- a/lib/fileset/default.nix +++ b/lib/fileset/default.nix @@ -188,7 +188,7 @@ in { - Set `root` to ${toString fileset._internalBase} or any directory higher up. This changes the layout of the resulting store path. - Set `fileset` to a file set that cannot contain files outside the `root` (${toString root}). This could change the files included in the result.'' else - builtins.seq sourceFilter + seq sourceFilter cleanSourceWith { name = "source"; src = root; @@ -380,7 +380,7 @@ in { fileFilter (file: hasPrefix "." file.name) ./. # Include all regular files (not symlinks or others) in the current directory - fileFilter (file: file.type == "regular") + fileFilter (file: file.type == "regular") ./. */ fileFilter = /* @@ -401,7 +401,7 @@ in { fileset: if ! isFunction predicate then throw '' - lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function.'' + lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function instead.'' else _fileFilter predicate (_coerce "lib.fileset.fileFilter: Second argument" fileset); diff --git a/lib/fileset/internal.nix b/lib/fileset/internal.nix index 717253f45715b..b245caade1f53 100644 --- a/lib/fileset/internal.nix +++ b/lib/fileset/internal.nix @@ -786,29 +786,40 @@ rec { _differenceTree (path + "/${name}") lhsValue (rhs.${name} or null) ) (_directoryEntries path lhs); + # Filters all files in a file set based on a predicate + # Type: ({ name, type, ... } -> Bool) -> FileSet -> FileSet _fileFilter = predicate: fileset: let - recurse = path: tree: + # Check the predicate for a single file + # Type: String -> String -> filesetTree + fromFile = name: type: + if + predicate { + inherit name type; + # To ensure forwards compatibility with more arguments being added in the future, + # adding an attribute which can't be deconstructed :) + "lib.fileset.fileFilter: The predicate function passed as the first argument must be able to handle extra attributes for future compatibility. If you're using `{ name, file }:`, use `{ name, file, ... }:` instead." = null; + } + then + type + else + null; + + # Check the predicate for all files in a directory + # Type: Path -> filesetTree + fromDir = path: tree: mapAttrs (name: subtree: if isAttrs subtree || subtree == "directory" then - recurse (path + "/${name}") subtree - else if - predicate { - inherit name; - type = subtree; - # To ensure forwards compatibility with more arguments being added in the future, - # adding an attribute which can't be deconstructed :) - "lib.fileset.fileFilter: The predicate function passed as the first argument must be able to handle extra attributes for future compatibility. If you're using `{ name, file }:`, use `{ name, file, ... }:` instead." = null; - } - then - subtree - else + fromDir (path + "/${name}") subtree + else if subtree == null then null + else + fromFile name subtree ) (_directoryEntries path tree); in if fileset._internalIsEmptyWithoutBase then _emptyWithoutBase else _create fileset._internalBase - (recurse fileset._internalBase fileset._internalTree); + (fromDir fileset._internalBase fileset._internalTree); } diff --git a/lib/fileset/tests.sh b/lib/fileset/tests.sh index 796a03b52f0e4..5ef155d25a881 100755 --- a/lib/fileset/tests.sh +++ b/lib/fileset/tests.sh @@ -810,6 +810,13 @@ checkFileset 'difference ./. ./b' ## File filter +# The first argument needs to be a function +expectFailure 'fileFilter null (abort "this is not needed")' 'lib.fileset.fileFilter: First argument is of type null, but it should be a function instead.' + +# The second argument can be a file set or an existing path +expectFailure 'fileFilter (file: abort "this is not needed") null' 'lib.fileset.fileFilter: Second argument is of type null, but it should be a file set or a path instead.' +expectFailure 'fileFilter (file: abort "this is not needed") ./a' 'lib.fileset.fileFilter: Second argument \('"$work"'/a\) is a path that does not exist.' + # The predicate is not called when there's no files tree=() checkFileset 'fileFilter (file: abort "this is not needed") ./.' @@ -875,6 +882,26 @@ checkFileset 'union ./c/a (fileFilter (file: assert file.name != "a"; true) ./.) # but here we need to use ./c checkFileset 'union (fileFilter (file: assert file.name != "a"; true) ./.) ./c' +# Also lazy, the filter isn't called on a filtered out path +tree=( + [a]=1 + [b]=0 + [c]=0 +) +checkFileset 'fileFilter (file: assert file.name != "c"; file.name == "a") (difference ./. ./c)' + +# Make sure single files are filtered correctly +tree=( + [a]=1 + [b]=0 +) +checkFileset 'fileFilter (file: assert file.name == "a"; true) ./a' +tree=( + [a]=0 + [b]=0 +) +checkFileset 'fileFilter (file: assert file.name == "a"; false) ./a' + ## Tracing # The second trace argument is returned diff --git a/lib/trivial.nix b/lib/trivial.nix index c23fc6070be46..a89c1aa25b1f7 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -449,6 +449,40 @@ rec { (f ? __functor && isFunction (f.__functor f)); /* + `mirrorFunctionArgs f g` creates a new function `g'` with the same behavior as `g` (`g' x == g x`) + but its function arguments mirroring `f` (`lib.functionArgs g' == lib.functionArgs f`). + + Type: + mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) + + Example: + addab = {a, b}: a + b + addab { a = 2; b = 4; } + => 6 + lib.functionArgs addab + => { a = false; b = false; } + addab1 = attrs: addab attrs + 1 + addab1 { a = 2; b = 4; } + => 7 + lib.functionArgs addab1 + => { } + addab1' = lib.mirrorFunctionArgs addab addab1 + addab1' { a = 2; b = 4; } + => 7 + lib.functionArgs addab1' + => { a = false; b = false; } + */ + mirrorFunctionArgs = + # Function to provide the argument metadata + f: + let + fArgs = functionArgs f; + in + # Function to set the argument metadata to + g: + setFunctionArgs g fArgs; + + /* Turns any non-callable values into constant functions. Returns callable values as is. |