lib.packagesFromDirectoryRecursive: use explicit recursion, support nested scopes

nicoo 6b7576b0 fdd2c6f8

Changed files
+50 -35
doc
lib
nixos
doc
+3
doc/redirects.json
···
"sec-nixpkgs-release-25.05-lib-deprecations": [
"release-notes.html#sec-nixpkgs-release-25.05-lib-deprecations"
],
+
"sec-nixpkgs-release-25.05-lib-additions-improvements": [
+
"release-notes.html#sec-nixpkgs-release-25.05-lib-additions-improvements"
+
],
"sec-overlays-install": [
"index.html#sec-overlays-install"
],
+4
doc/release-notes/rl-2505.section.md
···
- Plasma 5 and Qt 5 based versions of associated software are deprecated in NixOS 25.05, and will be removed in NixOS 25.11. Users are encouraged to upgrade to Plasma 6.
- `rustPlatform.buildRustPackage` stops handling the deprecated argument `cargoSha256`. Out-of-tree packages that haven't migrated from `cargoSha256` to `cargoHash` now receive errors.
+
+
### Other notable changes {#sec-release-25.05-lib-notable-changes}
+
+
- `lib.packagesFromDirectoryRecursive` can now construct nested scopes matching the directory tree passed as input.
+40 -35
lib/filesystem.nix
···
# Type
```
-
packagesFromDirectoryRecursive :: {
+
packagesFromDirectoryRecursive :: (args :: {
callPackage :: Path -> {} -> a,
directory :: Path,
+
recurseIntoDirectory? :: (args -> AttrSet) -> args -> AttrSet,
...
-
} -> AttrSet
+
}) -> AttrSet
```
# Inputs
···
`directory`
: The directory to read package files from.
+
`recurseIntoDirectory`
+
: This argument is applied to the function which processes directories.
+
: Equivalently, this function takes `processDir` and `args`, and can modify arguments passed to `processDir`
+
(same as above) before calling it, as well as modify its output (which is then returned by `recurseIntoDirectory`).
# Examples
:::{.example}
···
::::{.example}
## Create a scope for the nix files found in a directory
```nix
-
lib.makeScope pkgs.newScope (
-
self: packagesFromDirectoryRecursive {
-
inherit (self) callPackage;
-
directory = ./my-packages;
-
}
-
)
+
packagesFromDirectoryRecursive {
+
inherit (pkgs) callPackage newScope;
+
recurseIntoDirectory = f: { newScope, ... }@args:
+
lib.recurseIntoAttrset (lib.makeScope newScope (self:
+
f (args // {
+
inherit (self) callPackage newScope;
+
})
+
));
+
directory = ./my-packages;
+
}
=> { ... }
```
···
:::{.note}
`a.nix` cannot directly take as inputs packages defined in a child directory, such as `b1`.
:::
-
-
:::{.warning}
-
As of now, `lib.packagesFromDirectoryRecursive` cannot create nested scopes for sub-directories.
-
-
In particular, files under `b/` can only require (as inputs) other files under `my-packages`,
-
but not to those in the same directory, nor those in a parent directory; e.g, `b2.nix` cannot directly
-
require `b1`.
-
:::
::::
*/
packagesFromDirectoryRecursive =
{
callPackage,
directory,
+
recurseIntoDirectory ? lib.id,
...
-
}:
+
}@args:
let
inherit (lib) concatMapAttrs removeSuffix;
inherit (lib.path) append;
···
if pathExists defaultPath then
# if `${directory}/package.nix` exists, call it directly
callPackage defaultPath {}
-
else concatMapAttrs (name: type:
-
# otherwise, for each directory entry
-
let path = append directory name; in
-
if type == "directory" then {
-
# recurse into directories
-
"${name}" = packagesFromDirectoryRecursive {
-
inherit callPackage;
-
directory = path;
-
};
-
} else if type == "regular" && hasSuffix ".nix" name then {
-
# call .nix files
-
"${removeSuffix ".nix" name}" = callPackage path {};
-
} else if type == "regular" then {
-
# ignore non-nix files
-
} else throw ''
-
lib.filesystem.packagesFromDirectoryRecursive: Unsupported file type ${type} at path ${toString path}
-
''
-
) (builtins.readDir directory);
+
else let
+
f = { callPackage, ... }@newArgs:
+
concatMapAttrs (name: type:
+
# otherwise, for each directory entry
+
let path = append directory name; in
+
if type == "directory" then {
+
# recurse into directories
+
"${name}" = packagesFromDirectoryRecursive (newArgs // {
+
directory = path;
+
});
+
} else if type == "regular" && hasSuffix ".nix" name then {
+
# call .nix files
+
"${removeSuffix ".nix" name}" = callPackage path {};
+
} else if type == "regular" then {
+
# ignore non-nix files
+
} else throw ''
+
lib.filesystem.packagesFromDirectoryRecursive: Unsupported file type ${type} at path ${toString path}
+
''
+
) (builtins.readDir directory);
+
in
+
recurseIntoDirectory f args;
}
+3
nixos/doc/manual/redirects.json
···
"sec-nixpkgs-release-25.05-lib-deprecations": [
"release-notes.html#sec-nixpkgs-release-25.05-lib-deprecations"
],
+
"sec-nixpkgs-release-25.05-lib-additions-improvements": [
+
"release-notes.html#sec-nixpkgs-release-25.05-lib-additions-improvements"
+
],
"sec-release-24.11": [
"release-notes.html#sec-release-24.11"
],