I created a custom set of options, which contains an attribute set of user settings. Attribute name is the username, attribute value is their settings.
Now I want to import a module for each user, passing the user’s userSettings as argument. This module will generate the user’s user and home-manager configs. The goal is to be able to simply define my list of users and all will be setup according to their personal config.
When I do this for a specific user there is no problem, but as soon as I pre-compute the list of modules to import (with mapAttrsToList) I get infinite recursion.
Here is the code:
{ config, lib, ... }:
# import create-user.nix for each user listed in config.sharedConfig.users
let
getUserConfigModule = userSettings: (import ./create-user.nix { inherit userSettings; });
allUserSettings = lib.attrsets.mapAttrsToList (name: value: value) config.sharedConfig.users;
userModules = map (userSettings: getUserConfigModule userSettings) allUserSettings;
#usri = getUserConfigModule (builtins.head allUserSettings);
in
{
imports = userModules; # error: infinite recursion encountered
# imports = [ usri ]; # works
}
You probably want attrsOf submodule here, then you can use a different config binding within the submodule for user-specific config. There are many such examples throughout nixpkgs if you search attrsOf submodule.
users = mkOption {
type = with types; attrsOf (submodule userSettings);
default = {};
description = "Per-user settings";
};
But I still don’t understand how to pass each userConfig that are under the attribute users as an argument of the create-user module…
Also why does it work when I pass a list containing just the first user, obtained with builtins.head ? It was obtained from config just the same way as with the failing method.
Why don’t you just use the inner config module arg in the module itself?
Or if you want to set config for options outside of the submodule, do what you were doing but without using imports.
Hey thanks for your answers but I’m still confused. I did use config in the module itself but that’s not the problem.
What I want is, for each user in my config, to inject the userConfig of that user as argument in the imported module and I want to import the parameterised module for each defined user.
I tried to follow your advice to get rid of imports (even though I haven’t understood why imports is specifically bad in this case) and so I figured out a different approach where I replaced lib.attrsets.mapAttrsToList and imports with lib.mkMerge and lib.genAttrs:
the solution is to not set the top level attribute (config) directly.
So config = myConfig gives infinite recursion but
config.home-manager = myConfig.home-manager will work.