···11{
22 imports = [
33- # Automagically imports libs from "/lib/lib-name" and exposes them to the `flake.lib` output.
43 ./lib.nix
55-66- # Automagically imports systems from "/systems/arch-classname/system-name".
74 ./systems.nix
88-99- # Automagically import custom packages defined in "/pkgs/pkg-name/default.nix"
1010- ./packages.nix
115 ];
126}
+60-69
modules/flake/lib.nix
···44 ...
55}:
66let
77- # Utility function to read a directory and return its contents.
88- readDirectory = directory: builtins.readDir directory;
77+ /*
88+ Recursively find all .nix files in a directory tree.
991010- # Utility function to handle each filesystem entity (file or directory).
1111- filesystemEntityToAttrSet =
1212- directory: importArgs: name: type:
1313- if type == "directory" then
1414- dirToAttrSet "${directory}/${name}" importArgs
1515- else if name == "default.nix" then
1616- import "${directory}/${name}" importArgs
1717- else
1818- { };
1010+ This traverses a directory recursively and returns a flat list
1111+ of paths to every .nix file found.
19122020- filesystemEntityToList =
2121- directory: name: type:
2222- if type == "directory" then
2323- dirToModuleList "${directory}/${name}"
2424- else if name == "default.nix" then
2525- [ "${directory}/${name}" ]
2626- else
2727- [ ];
1313+ Type: dirToModuleList :: Path -> [Path]
28142929- filesystemEntityToPackage =
3030- directory: pkgs: pkgArgs: name: type:
3131- if type == "directory" then
3232- dirToPkgAttrSet "${directory}/${name}" pkgs pkgArgs
3333- else if name == "default.nix" then
3434- {
3535- ${builtins.unsafeDiscardStringContext (builtins.baseNameOf directory)} =
3636- pkgs.callPackage "${directory}/${name}" pkgArgs;
3737- }
3838- else
3939- { };
4040-1515+ Example:
1616+ dirToModuleList ./modules/nixos
1717+ => [
1818+ /path/to/modules/nixos/users/default.nix
1919+ /path/to/modules/nixos/networking/default.nix
2020+ ]
2121+ */
4122 dirToModuleList =
4223 directory:
4324 let
4444- readDir = readDirectory directory;
2525+ entries = builtins.readDir directory;
2626+ processEntry =
2727+ name: type:
2828+ if type == "directory" then
2929+ dirToModuleList "${directory}/${name}"
3030+ else if lib.hasSuffix ".nix" name then
3131+ [ "${directory}/${name}" ]
3232+ else
3333+ [ ];
4534 in
4646- builtins.foldl' (
4747- acc: name: acc ++ (filesystemEntityToList directory name (builtins.getAttr name readDir))
4848- ) [ ] (builtins.attrNames readDir);
3535+ lib.flatten (lib.mapAttrsToList processEntry entries);
3636+3737+ /*
3838+ Recursively import all .nix files from a directory into an attrset.
3939+4040+ Traverses a directory tree, imports each .nix file with the provided
4141+ arguments, and merges all results into a single attribute set.
4242+ Subdirectories are recursively processed.
4343+4444+ Type: dirToAttrset :: Path -> AttrSet -> AttrSet
4545+4646+ Example:
4747+ Given directory structure:
4848+ lib/
4949+ strings.nix -> { trim = s: ...; }
5050+ math.nix -> { add = a: b: ...; }
49515050- # Utility function to recursively load modules from a directory.
5151- dirToAttrSet =
5252- directory: importArgs:
5353- let
5454- # Read provided directory only once at the very start and save the result.
5555- readDir = readDirectory directory;
5656- in
5757- # Iterate over the attr names of a readDir operation.
5858- builtins.foldl' (
5959- acc: name:
6060- # Merge outputs of handling a filesystem entity (file or directory) into accumulator.
6161- # Files return attribute sets with their resulting expressions, directories return the result of multiple file handling operations.
6262- acc // (filesystemEntityToAttrSet directory importArgs name (builtins.getAttr name readDir))
6363- ) { } (builtins.attrNames readDir);
5252+ dirToAttrset ./lib { inherit lib; }
5353+ => { trim = ...; add = ...; }
64546565- dirToPkgAttrSet =
6666- directory: pkgs: pkgArgs:
5555+ Arguments:
5656+ directory: Path to scan for .nix files
5757+ importArgs: Attribute set to pass to each imported file
5858+ */
5959+ dirToAttrset =
6060+ directory: importArgs:
6761 let
6868- # Read provided directory only once at the very start and save the result.
6969- readDir = readDirectory directory;
6262+ entries = builtins.readDir directory;
6363+ processEntry =
6464+ name: type:
6565+ if type == "directory" then
6666+ dirToAttrset "${directory}/${name}" importArgs
6767+ else if lib.hasSuffix ".nix" name then
6868+ import "${directory}/${name}" importArgs
6969+ else
7070+ { };
7071 in
7171- builtins.foldl' (
7272- acc: name:
7373- acc // (filesystemEntityToPackage directory pkgs pkgArgs name (builtins.getAttr name readDir))
7474- ) { } (builtins.attrNames readDir);
7272+ builtins.foldl' (acc: element: acc // element) { } (lib.mapAttrsToList processEntry entries);
75737676- puzzlelib = dirToAttrSet ../../lib { inherit lib self; } // {
7777- inherit
7878- dirToAttrSet
7979- dirToPkgAttrSet
8080- dirToModuleList
8181- filesystemEntityToList
8282- filesystemEntityToAttrSet
8383- filesystemEntityToPackage
8484- ;
8585- };
8674in
8775{
8888- # Expose custom library on flake "lib" output
8989- flake.lib = puzzlelib;
7676+ flake = {
7777+ lib = dirToAttrset ../../lib { inherit lib self; } // {
7878+ filesystem = { inherit dirToModuleList dirToAttrset; };
7979+ };
8080+ };
9081}