Extend Lib global flake

Good Evening,

I’m working on modularising my nix config, and to do so, I’ve written several nix functions that I would like to extend the global lib to include, to save me needing to write them multiple times. These functions mostly involve file finding and importing, and use various builtins and other lib functions to find and import all nix files in a directory.

I would like to create an easily extensible /lib directory in my config folder, using one of my written functions to import all .nix files in the directory, build one large overlay and extend nixpkgs.lib with this.

I’ve got as far as this:

# Flake.nix
...
lib = nixpkgs.lib.extend (
        self: super: {custom = (import ./lib {lib = self;});} // home-manager.lib
      );
...
#/lib/default.nix
{lib}:

with lib; let
  _lib = (self: let importDirRec = (import ./dirOps.nix {lib = self;}).importDirRec;
    in
    foldr (a: b: a // b) {} (importDirRec ./. {lib=self;}));
  custom = makeExtensible _lib;
  in
custom.extend (self: super:
    foldr (a: b: a // b) {} (attrValues super))
#/lib/dirOps.nix
{lib}:
let 
getNixFilesF = dir : builtins.attrValues (builtins.mapAttrs (name: _: ./. + "/${name}") (lib.attrsets.filterAttrs (name: _: (lib.hasSuffix ".nix" name) && !(name == "default.nix")) (builtins.readDir dir)));

getSubDirNamesF = dir : builtins.attrValues (builtins.mapAttrs (name: _: "${name}") (lib.attrsets.filterAttrs (name: type: (type=="directory")) (builtins.readDir dir)));

importerF = f: args: import f args;

importAllF = fs: args: builtins.map (f: importerF f args) fs;

in rec
{
  getDir = (
    dir: getNixFilesF(dir));

  getDirRec = (
    dir: getDir(dir) ++ (
      let 
      subDirs = (getSubDirNames dir); 
      in 
      ( if (subDirs != []) then 
          lib.lists.flatten (
            builtins.map (subdir: getDirRec "${dir}/${subdir}") subDirs  
          )
        else []
      )) );

  getSubDirNames = (
    dir: getSubDirNamesF(dir));

  getSubDirs = (
    dir: builtins.map (name: "./${name}") (getSubDirNames dir));

  importDir = ( dir: args:
    importAllF (getDir dir) args);

  importDirRec = ( dir: args:
    importAllF (getDirRec dir) args);
}

This works until I call one of these functions elsewhere in my config, when I receive an infinite recursion error. How can I add these functions to lib without this happening? I’m also using these functions for my package overlays, so it isn’t ideal to instead override pkgs.lib, if that’s feasible.

Also, I’d prefer to not have to include these functions as a sub-library (e.g: lib.custom.importDirRec), is it possible to add functions to top level lib (e.g: lib.importDirRec) instead.

1 Like

share how you call it and share the error

I’ve been able to get this partially working by replacing

self: super: {custom = (import ./lib {lib = self;});} // home-manager.lib

in flake.nix with

self: super: (import ./lib nixpkgs.lib) // home-manager.lib

and my /lib/default.nix with

lib:

let importDirRec = (import ./dirOps.nix {inherit lib;}).importDirRec;
in
(lib.lists.foldr (a: b: a//b) {} (importDirRec ./. {inherit lib;}))

However, that doesn’t allow my custom lib functions to call those in other files. Is there a way to do this such that they can?

My config is here, if that helps?

1 Like