Is there a mkIf equivalent of mapAttrs?

I have a NixOS module like this:

{
  users.users.hgl = { ... }
}

And I want to have another NixOS module that does this:

{ config, lib, ... }:
{
  home-manager.users = builtins.mapAttrs
    (name: user: lib.nameValuePair name { ... })
    config.users.users;
}

Because I want to only specify the user name once. However, using builtins.mapAttrs directly results in infinite recursion. I know mkIf is used to prevent this when the value is a boolean.

Any idea what I should use when a set should be mapped?

You do not want to create a HM entry for every user known to users.users. Instead you want to selectively specify only the 2 or 3 that are actually using and prepared for HM.

You do not want to have a HM for each and every implicitely created demon user, that drives some service you have activated.

Thanks for the advice.

I guess I can add in some conditions to filter the “main” users (e.g, any user who has a login shell configured).

But I still wonder if mapAttrs lazily is possible?

To be fair, you can filter the config.users.users attrset for only those users that have isNormalUser set.

Thats true, though fact is, that HM already does some carefully crafted back and forth between the 2 options, any additional direct dependency between those can just cause problems.

3 Likes

Have you enabled home-manager.useUserPackages? Because of this line, https://github.com/nix-community/home-manager/blob/6a94c1a59737783c282c4031555a289c28b961e4/nixos/common.nix#L107, home-manager sets users.users option based on your HM users. So going the other way will cause infinite recursion. Disabling useUserPackages could fix it, but I’m not sure if it will matter.
I don’t think its possible to make a lazy mapAttrs in the same way mkIf can be lazy in the module system.