| # As our modules have nonstandard properties, we need to have some way of |
| # properly intepreting them |
| # This function takes a list of modules, as well as arguments to import them |
| # with, and returns a list of modules, each with the standard NixOS module |
| # properties as well as with custom properties as described in /README.md |
| lib: transformArgs: modules: args @ { pkgs, ... }: |
| let |
| resolver = module: |
| let |
| importedModule = |
| if builtins.typeOf module == "path" |
| then import module |
| else module; |
| resolvedModule = |
| if builtins.typeOf importedModule == "lambda" |
| then |
| importedModule |
| (transformArgs args) |
| else importedModule; |
| moduleName = |
| if builtins.typeOf module == "lambda" |
| then "<AnonFunction>" |
| else if builtins.typeOf module == "path" |
| then builtins.toString module |
| else builtins.toJSON module; |
| in |
| lib.warnIfNot |
| ((lib.pipe resolvedModule [ |
| builtins.attrNames |
| (lib.subtractLists [ "home" "config" "imports" "options" "traces" ]) |
| ]) |
| == [ ]) |
| "Module ${moduleName} had attribute names ${builtins.toJSON (builtins.attrNames resolvedModule)} but only home, config, imports and options are resolved" |
| [ |
| { |
| config = lib.recursiveUpdate (resolvedModule.config or { }) { |
| home-manager.users."${args.username}".imports = |
| (resolvedModule.config.home-manager.users."${args.username}".imports or [ ]) |
| ++ [ resolvedModule.home or { } ]; |
| }; |
| imports = resolvedModule.imports or [ ]; |
| options = resolvedModule.options or { }; |
| } |
| ] |
| ++ (builtins.map |
| (trace: |
| let |
| splitTrace = lib.splitString "." trace; |
| traceHead = builtins.head splitTrace; |
| traceTail = builtins.tail splitTrace; |
| resolvedTrace = |
| ( |
| if traceHead == "home" |
| then [ "home-manager" "users" args.username ] |
| else lib.errorIfNot (traceHead == "config") [ ] |
| ) |
| ++ traceTail; |
| in |
| { config, ... }: (builtins.seq |
| ( |
| lib.pipe resolvedTrace [ |
| (lib.foldl |
| ({ value |
| , error |
| , |
| }: key: |
| if builtins.hasAttr key value |
| then { |
| value = value.${key}; |
| inherit error; |
| } |
| else { |
| value = { }; |
| error = true; |
| }) |
| { |
| value = { }; |
| error = false; |
| }) |
| (data: lib.warnIf data.error "trace@${moduleName}/${trace} is invalid; the key does not exist" data) |
| ({ value |
| , error |
| , |
| }: { |
| value = builtins.toJSON value; |
| inherit error; |
| }) |
| ({ value |
| , error |
| , |
| }: { |
| value = "trace@${moduleName}/${trace}: ${value}"; |
| inherit error; |
| }) |
| ({ value |
| , error |
| , |
| }: |
| lib.traceIf (!error) value null) |
| ] |
| ) |
| { })) |
| (resolvedModule.traces or [ ])); |
| in |
| { |
| imports = ( |
| if builtins.typeOf modules == "list" |
| then builtins.concatLists (builtins.map resolver modules) |
| else resolver modules |
| ); |
| } |