{ lib, pkgs, config, ... }: with lib; let cfg = config.custom.users; machine = config.custom.machine; valid-on-machine = on: # TODO: iterate over possibilities if machine.type == "server" then on.server else if machine.type == "pc" then on.pc else false; matches-capabilities = # all requirements are contained in the machine capabilities requirements: lib.all (req: builtins.elem req machine.capabilities) requirements; users = lib.filterAttrs (_: value: valid-on-machine value.on) cfg; home-users = lib.filterAttrs (_: value: value.apply-home-configs) users; stateVersion = config.system.stateVersion; programs = lib.attrsets.attrValues config.custom.program; valid-programs = builtins.filter (program: matches-capabilities program.requirements) programs; in { options = let userType = types.submodule { options = { name = mkOption { type = types.str; default = [ ]; }; groups = mkOption { type = types.listOf types.str; default = [ ]; }; keys = mkOption { type = types.listOf types.str; default = [ ]; }; shell = mkOption { type = types.package; default = pkgs.fish; }; on = mkOption { type = types.submodule { options = { server = mkOption { type = types.bool; default = true; }; pc = mkOption { type = types.bool; default = false; }; }; }; default = { }; }; apply-home-configs = mkOption { type = types.bool; default = false; }; }; }; in { custom.users = mkOption { type = types.attrsOf userType; }; }; config = lib.mkMerge ([ { users.extraUsers = lib.mapAttrs (name: value: { isNormalUser = true; extraGroups = value.groups; openssh.authorizedKeys.keys = value.keys; shell = value.shell; description = name; }) users; home-manager.users = lib.mapAttrs ( name: value: ( { pkgs, lib, ... }: { imports = ( [ ./home-info.nix ] ++ (map (program: program.home-config) valid-programs) ); home = { inherit stateVersion; username = name; homeDirectory = "/home/${name}"; }; } ) ) home-users; } ]); }