nix-config/modules/top/classes/nixos.nix
2026-05-03 17:10:27 -04:00

167 lines
4.6 KiB
Nix

{
lib,
inputs,
config,
...
}:
let
inherit (lib)
mapAttrs
flatten
unique
optionals
optional
;
allRoles = config.dendritic.roles;
allFeatures = config.dendritic.features;
resolveRoles =
let
go =
seen: roleName:
if builtins.elem roleName seen then
throw "Circular dendritic role reference detected: ${
builtins.concatStringsSep " -> " (seen ++ [ roleName ])
}"
else
let
role = allRoles.${roleName} or null;
in
if role == null then
throw "Unknown dendritic role: ${roleName}"
else
[ roleName ] ++ flatten (map (go (seen ++ [ roleName ])) role.roles);
in
roleNames: unique (flatten (map (go [ ]) roleNames));
resolveFeatures =
let
go =
seen: featureName:
if builtins.elem featureName seen then
throw "Circular dendritic feature reference detected: ${
builtins.concatStringsSep " -> " (seen ++ [ featureName ])
}"
else
let
feature = allFeatures.${featureName} or null;
in
if feature == null then
throw "Unknown dendritic feature: ${featureName}"
else
[ featureName ] ++ flatten (map (go (seen ++ [ featureName ])) feature.features);
in
featureNames: unique (flatten (map (go [ ]) featureNames));
mkHost =
hostName: host:
let
username = if host.primaryUser == null then null else host.primaryUser;
user = if username == null then null else config.dendritic.users.${username};
userHome = if user == null then null else user.homes.${hostName} or null;
resolvedRoleNames = resolveRoles host.roles;
roleFeatureNames = flatten (map (roleName: allRoles.${roleName}.features) resolvedRoleNames);
resolvedFeatureNames = resolveFeatures roleFeatureNames;
featureNixosModules = flatten (
map (featureName: allFeatures.${featureName}.nixosModules) resolvedFeatureNames
);
featureHomeModules =
if userHome == null then
[ ]
else
let
resolvedHomeRoleNames = resolveRoles userHome.roles;
homeRoleFeatureNames = flatten (
map (roleName: allRoles.${roleName}.features) resolvedHomeRoleNames
);
resolvedHomeFeatureNames = resolveFeatures homeRoleFeatureNames;
embeddedHomeFeatureNames = builtins.filter (
featureName: allFeatures.${featureName}.includeInEmbeddedHomeManager
) resolvedHomeFeatureNames;
in
flatten (map (featureName: allFeatures.${featureName}.homeModules) embeddedHomeFeatureNames);
in
inputs.nixpkgs.lib.nixosSystem {
system = host.system;
specialArgs = {
inherit inputs;
};
modules = [
{
nixpkgs.overlays = [
inputs.self.overlays.default
];
}
../inventory/current.nix
../inventory/features.nix
../inventory/hosts.nix
../inventory/users.nix
../../aspects/roles.nix
{
dendritic.current = {
inherit hostName;
primaryUser = username;
};
networking.hostName = hostName;
}
]
++ host.nixosModules
++ featureNixosModules
++ optional (username != null) {
users.users.${username} = {
isNormalUser = true;
extraGroups = host.primaryUserExtraGroups;
};
}
++ optionals (user != null) user.nixosModules
++ optional (userHome != null) inputs.home-manager.nixosModules.home-manager
++ optional (userHome != null) {
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = {
inherit inputs;
};
home-manager.sharedModules = [
../inventory/current.nix
../inventory/features.nix
../inventory/hosts.nix
../inventory/users.nix
../../aspects/roles.nix
];
home-manager.users.${username}.imports = [
{
dendritic.current = {
inherit hostName;
primaryUser = username;
};
}
]
++ user.homeModules
++ featureHomeModules
++ userHome.extraModules
++ [
{
home.username = user.username;
home.homeDirectory = "/home/${user.username}";
home.stateVersion = userHome.stateVersion;
}
];
};
};
in
{
config.flake.nixosConfigurations = mapAttrs mkHost config.dendritic.hosts;
}