flake-parts/setups/nixos: init option to add home-manager users from declarative users setup

This commit is contained in:
Gabriel Arazas 2024-01-18 16:54:16 +08:00
parent 521424e7f1
commit 22aeb0c396
No known key found for this signature in database
GPG Key ID: ADE0C41DAB221FCC

View File

@ -99,6 +99,49 @@ let
};
};
homeManagerUserType =
let
partsConfig = config;
in
{ name, config, lib, ... }: {
options = {
userConfig = lib.mkOption {
type = with lib.types; attrsOf anything;
description = ''
The configuration applied for {option}`users.users.<name>` in the
NixOS configuration.
'';
};
additionalModules = lib.mkOption {
type = with lib.types; listOf raw;
description = ''
A list of additional home-manager modules to be added with the
user.
'';
};
};
config =
let
hmUserConfig = partsConfig.setups.home-manager.configs.${name};
in
{
userConfig = {
isNormalUser = lib.mkDefault true;
createHome = lib.mkDefault true;
home = lib.mkForce hmUserConfig.homeDirectory;
};
additionalModules = [
({ lib, ... }: {
home.homeDirectory = lib.mkForce hmUserConfig.homeDirectory;
home.username = lib.mkForce name;
})
];
};
};
configType =
let
partsConfig = config;
@ -189,6 +232,83 @@ let
'';
};
homeManagerUsers = lib.mkOption {
type = lib.types.submodule {
options = {
users = lib.mkOption {
type = with lib.types; attrsOf (submodule homeManagerUserType);
default = { };
description = ''
A set of home-manager users from {option}`setups.home-manager` to be
mapped within the NixOS system as a normal user with their
home-manager configuration. This would be the preferred method of
creating NixOS users if you have a more comprehensive home-manager
user that needed more setup to begin with.
'';
};
nixpkgsInstance = lib.mkOption {
type = lib.types.enum [ "global" "separate" "none" ];
default = "global";
description = ''
Indicates how to manage the nixpkgs instance (or instances)
of the holistic system. This will also dictate how to import
overlays from
{option}`setups.home-manager.configs.<user>.overlays`.
* `global` enforces to use one nixpkgs instance for all
home-manager users and imports all of the overlays into the
nixpkgs instance of the NixOS system.
* `separate` enforces the NixOS system to use individual
nixpkgs instance for all home-manager users and imports the
overlays to the nixpkgs instance of the home-manager user.
* `none` leave the configuration alone and do not import
overlays at all where you have to set them yourself. This is
the best option if you want more control over each individual
NixOS and home-manager configuration.
The default value is set to `global` which is the encouraged
practice with this module.
'';
};
};
};
default = { };
example = lib.literalExpression ''
{
nixpkgsInstance = "global";
users.foo-dogsquared = {
userConfig = {
extraGroups = [
"adbusers"
"wheel"
"audio"
"docker"
"podman"
"networkmanager"
"wireshark"
];
hashedPassword =
"0000000000000000000000000000000000000000000000";
isNormalUser = true;
createHome = true;
home = "/home/foo-dogsquared";
description = "Gabriel Arazas";
};
additionalModules = [
({ config, lib, osConfig, ... }: {
programs.foo.enable = lib.mkIf osConfig.programs.bar.enable true;
})
];
};
}
'';
description = ''
Import home-manager users from
{option}`setups.home-manager.configs` and map them as a normal
NixOS user.
'';
};
deploy = lib.mkOption {
type = with lib.types; nullOr (submodule deployNodeType);
default = null;
@ -206,33 +326,108 @@ let
remoteBuild = true;
};
};
};
config = {
modules = [
inputs.${config.homeManagerBranch}.nixosModules.home-manager
../../../configs/nixos/${name}
(
let
setupConfig = config;
hasHomeManagerUsers = config.homeManagerUsers.users != { };
inherit (config.homeManagerUsers) nixpkgsInstance;
isNixpkgs = state: hasHomeManagerUsers && nixpkgsInstance == state;
in
{ config, lib, ... }: {
config = lib.mkMerge [
{
nixpkgs.overlays = setupConfig.overlays;
networking.hostName = lib.mkDefault setupConfig.hostname;
}
(lib.mkIf (setupConfig.domain != null) {
networking.domain = lib.mkDefault setupConfig.domain;
})
(lib.mkIf hasHomeManagerUsers {
users.users =
lib.mkMerge
(lib.mapAttrsToList
(name: hmUser: { ${name} = hmUser.userConfig; })
setupConfig.homeManagerUsers.users);
home-manager.users = lib.mkMerge
(lib.mapAttrsToList
(name: hmUser: {
${name} = { lib, ... }: {
imports =
partsConfig.setups.home-manager.configs.${name}.modules
++ hmUser.additionalModules;
};
})
setupConfig.homeManagerUsers.users);
})
(lib.mkIf (isNixpkgs "global") {
home-manager.useGlobalPkgs = lib.mkForce true;
# Disable all options that are going to be blocked once
# `home-manager.useGlobalPkgs` is used.
home-manager.users =
lib.mkMerge
(lib.mapAttrsToList
(name: _: {
${name} = {
nixpkgs.overlays = lib.mkForce null;
nixpkgs.config = lib.mkForce null;
};
})
setupConfig.homeManagerUsers.users);
# Then apply all of the user overlays into the nixpkgs instance
# of the NixOS system.
nixpkgs.overlays =
let
hmUsersOverlays =
lib.mapAttrsToList
(name: _:
partsConfig.setups.home-manager.configs.${name}.overlays)
setupConfig.homeManagerUsers.users;
overlays = lib.lists.flatten hmUsersOverlays;
in
# Most of the overlays are going to be imported from a flake
# input anyways. This should massively reduce the step needed
# for nixpkgs to do its thing.
#
# Though, it becomes unpredictable due to the way how the
# overlay list is constructed. However, this is much more
# preferable than letting a massive list with duplicated
# overlays from different home-manager users to be applied.
lib.lists.unique overlays;
})
(lib.mkIf (isNixpkgs "separate") {
home-manager.useGlobalPkgs = lib.mkForce false;
home-manager.users =
lib.mkMerge
(lib.mapAttrsToList
(name: _: {
${name} = {
nixpkgs.overlays =
partsConfig.setups.home-manager.configs.${name}.overlays;
};
})
setupConfig.homeManagerUsers.users);
})
];
}
)
];
};
};
config = {
modules = [
inputs.${config.homeManagerBranch}.nixosModules.home-manager
../../../configs/nixos/${name}
(
let
setupConfig = config;
in
{ config, lib, ... }: {
config = lib.mkMerge [
{
nixpkgs.overlays = setupConfig.overlays;
networking.hostName = lib.mkDefault setupConfig.hostname;
}
(lib.mkIf (setupConfig.domain != null) {
networking.domain = lib.mkForce setupConfig.domain;
})
];
}
)
];
};
};
in
{
options.setups.nixos = {
@ -309,9 +504,13 @@ in
osConfig = config;
in
{ lib, ... }: {
home-manager.sharedModules = osConfig.setups.home-manager.sharedModules;
# These are just the recommended options for home-manager that may be
# the default value in the future but this is how most of the NixOS
# setups are already done so...
home-manager.useUserPackages = lib.mkDefault true;
home-manager.useGlobalPkgs = lib.mkDefault true;
home-manager.sharedModules = osConfig.setups.home-manager.sharedModules;
}
)
];