Files
athenix/hosts/user-config.nix

196 lines
6.2 KiB
Nix

{
pkgs,
config,
lib,
inputs,
...
}:
# ============================================================================
# User Configuration Module
# ============================================================================
# This module defines the schema for user accounts and handles their creation.
# It bridges the gap between the data in 'users.nix' and the actual NixOS
# and Home Manager configuration.
let
# Submodule defining the structure of a user account
userSubmodule = lib.types.submodule {
options = {
isNormalUser = lib.mkOption {
type = lib.types.bool;
default = true;
};
description = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
extraGroups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
hashedPassword = lib.mkOption {
type = lib.types.str;
default = "!";
};
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
home = lib.mkOption {
type = lib.types.nullOr (
lib.types.oneOf [
lib.types.path
lib.types.package
lib.types.attrs
]
);
default = null;
description = ''
External home-manager configuration. Can be:
- A path to a local module
- A fetchGit/fetchTarball result pointing to a repository
- An attribute set with home-manager configuration
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
'';
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The shell for this user.";
};
editor = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The default editor for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether this user account is enabled on this system.";
};
};
};
in
{
options.ugaif.users = lib.mkOption {
type = lib.types.attrsOf userSubmodule;
default = { };
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
};
config = {
# Generate NixOS users
users.users =
let
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.ugaif.users;
in
lib.mapAttrs (
name: user:
let
isPlasma6 = config.services.desktopManager.plasma6.enable;
defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ];
finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages);
in
{
inherit (user) isNormalUser extraGroups hashedPassword;
description = if user.description != null then user.description else lib.mkDefault "";
openssh.authorizedKeys.keys = user.opensshKeys;
packages = finalPackages;
shell = if user.shell != null then user.shell else pkgs.bash;
}
) enabledAccounts;
# Home Manager configs per user
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
osConfig = config;
inherit inputs;
};
users =
let
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.ugaif.users;
in
lib.mapAttrs (
name: user:
{ ... }:
let
# Check if user has external home configuration
hasExternalHome = user.home != null;
# Extract path from fetchGit/fetchTarball if needed
externalHomePath =
if hasExternalHome then
if builtins.isAttrs user.home && user.home ? outPath then user.home.outPath else user.home
else
null;
# Import external module if it's a path
externalHomeModule =
if
externalHomePath != null
&& (
builtins.isPath externalHomePath
|| (builtins.isString externalHomePath && lib.hasPrefix "/" externalHomePath)
)
then
import (externalHomePath + "/home.nix") { inherit inputs; }
else if builtins.isAttrs user.home && !(user.home ? outPath) then
user.home # Direct attrset configuration
else
{ };
# Common imports based on flags
commonImports = lib.optional user.useZshTheme ../sw/theme.nix ++ [
(import ../sw/nvim.nix { inherit user; })
];
in
if hasExternalHome then
{
# External users: Merge external config with common imports
imports = commonImports ++ [ externalHomeModule ];
}
else
{
# Local users: Apply full configuration.
imports = user.extraImports ++ commonImports;
home.username = name;
home.homeDirectory = if name == "root" then "/root" else "/home/${name}";
home.stateVersion = "25.11";
home.packages = user.homePackages;
}
) enabledAccounts;
};
};
}