style(nix): apply style fixes #53

Merged
alexion merged 1 commits from apply-nix-style-fix into main 2026-09-16 00:18:54 -04:00
42 changed files with 389 additions and 289 deletions

View File

@@ -109,12 +109,16 @@ in
inherit (cfg.reverseProxy) trustedSources; inherit (cfg.reverseProxy) trustedSources;
}; };
volumes = lib.mapAttrs (_urlPath: volume: { volumes = lib.mapAttrs (_urlPath: volume: {
inherit (volume) path access flags readOnly; inherit (volume)
path
access
flags
readOnly
;
}) cfg.volumes; }) cfg.volumes;
}; };
mounts = mounts = {
{
${cfg.stateDir} = { ${cfg.stateDir} = {
directory = cfg.statePath; directory = cfg.statePath;
owner = config.registry."stable-uid".${config.networking.hostName}.copyparty; owner = config.registry."stable-uid".${config.networking.hostName}.copyparty;
@@ -126,7 +130,8 @@ in
readOnly = true; readOnly = true;
}; };
} }
// lib.mapAttrs' (_urlPath: volume: // lib.mapAttrs' (
_urlPath: volume:
lib.nameValuePair volume.path { lib.nameValuePair volume.path {
directory = volume.hostPath; directory = volume.hostPath;
owner = "root"; owner = "root";

View File

@@ -88,14 +88,18 @@ in
guests.palworld = { guests.palworld = {
interior.modules.services.games.palworld = { interior.modules.services.games.palworld = {
enable = true; enable = true;
inherit (cfg) serverName port publicIP autoStart; inherit (cfg)
serverName
port
publicIP
autoStart
;
inherit steamDir installDir stateDir; inherit steamDir installDir stateDir;
passwordFile = "/run/secrets/${cfg.passwordSecret}"; passwordFile = "/run/secrets/${cfg.passwordSecret}";
adminPasswordFile = "/run/secrets/${cfg.adminPasswordSecret}"; adminPasswordFile = "/run/secrets/${cfg.adminPasswordSecret}";
}; };
mounts = mounts = {
{
${steamDir} = { ${steamDir} = {
directory = cfg.steamPath; directory = cfg.steamPath;
owner = config.registry."stable-uid".${config.networking.hostName}.steamcmd; owner = config.registry."stable-uid".${config.networking.hostName}.steamcmd;
@@ -133,8 +137,7 @@ in
}; };
}; };
sops.secrets = sops.secrets = {
{
${cfg.passwordSecret} = { ${cfg.passwordSecret} = {
owner = "root"; owner = "root";
group = "storage"; group = "storage";

View File

@@ -34,7 +34,7 @@
registry.shell-shortcut.neogaia = { registry.shell-shortcut.neogaia = {
vpn-on = "sudo systemctl start wireguard-wg-home.target"; vpn-on = "sudo systemctl start wireguard-wg-home.target";
vpn-off = ''sudo systemctl stop 'wireguard-wg-home*.service' wireguard-wg-home.target''; vpn-off = "sudo systemctl stop 'wireguard-wg-home*.service' wireguard-wg-home.target";
}; };
modules.monorepo.enable = true; modules.monorepo.enable = true;

View File

@@ -1,4 +1,4 @@
{ ... }: _:
# neogaia's disk layout for disko: one NVMe disk, GPT, with an EFI system # neogaia's disk layout for disko: one NVMe disk, GPT, with an EFI system
# partition and a LUKS container holding btrfs subvolumes. # partition and a LUKS container holding btrfs subvolumes.
# No swap partition, since swap is zram. # No swap partition, since swap is zram.

View File

@@ -1,4 +1,4 @@
{ ... }: _:
# pikachu's install layout for disko: one NVMe boot disk with an EFI system partition and ext4 root. # pikachu's install layout for disko: one NVMe boot disk with an EFI system partition and ext4 root.
# The existing 8 TB ZFS mirror is imported by name and is never declared here. # The existing 8 TB ZFS mirror is imported by name and is never declared here.
{ {

View File

@@ -8,7 +8,10 @@
# Disk layout is in ./disk.nix. # Disk layout is in ./disk.nix.
# `fileSystems` are derived from it, none declared here. # `fileSystems` are derived from it, none declared here.
{ {
imports = [ ./disk.nix ] ++ lib.optional (builtins.pathExists ./hardware-configuration.nix) ./hardware-configuration.nix; imports = [
./disk.nix
]
++ lib.optional (builtins.pathExists ./hardware-configuration.nix) ./hardware-configuration.nix;
nixpkgs.hostPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "x86_64-linux";

View File

@@ -1,4 +1,4 @@
{ ... }: _:
# zeus's disk layout for disko: two NVMe disks with one EFI system partition # zeus's disk layout for disko: two NVMe disks with one EFI system partition
# and two LUKS containers joined into one btrfs filesystem. # and two LUKS containers joined into one btrfs filesystem.
# No swap partition, since swap is zram. # No swap partition, since swap is zram.

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.desktop.apps.alacritty.enable = lib.mkEnableOption "Alacritty as the desktop terminal"; options.modules.desktop.apps.alacritty.enable =
lib.mkEnableOption "Alacritty as the desktop terminal";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.alacritty ]; home-manager.users.${user}.home.packages = [ pkgs.alacritty ];

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.desktop.apps.obsidian.enable = lib.mkEnableOption "Obsidian as the desktop note-taking vault"; options.modules.desktop.apps.obsidian.enable =
lib.mkEnableOption "Obsidian as the desktop note-taking vault";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.obsidian ]; home-manager.users.${user}.home.packages = [ pkgs.obsidian ];

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.desktop.apps.vencord.enable = lib.mkEnableOption "Vesktop, a Discord client with Vencord built in"; options.modules.desktop.apps.vencord.enable =
lib.mkEnableOption "Vesktop, a Discord client with Vencord built in";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.vesktop ]; home-manager.users.${user}.home.packages = [ pkgs.vesktop ];

View File

@@ -67,8 +67,7 @@ in
# UWSM launches the session without the shell profile that would carry # UWSM launches the session without the shell profile that would carry
# them, so a variable the compositor or its children must see is set # them, so a variable the compositor or its children must see is set
# here rather than through home-manager's sessionVariables. # here rather than through home-manager's sessionVariables.
env = env = [
[
# Chromium and Electron apps read this to select native Wayland; # Chromium and Electron apps read this to select native Wayland;
# nixpkgs wrappers (Obsidian's included) gate their Wayland flags on # nixpkgs wrappers (Obsidian's included) gate their Wayland flags on
# it, so without it they run under XWayland and blur at this DPI. # it, so without it they run under XWayland and blur at this DPI.

View File

@@ -45,7 +45,8 @@ let
''; '';
in in
{ {
options.modules.desktop.session.hyprland.hyprlock.enable = lib.mkEnableOption "the hyprlock lock screen"; options.modules.desktop.session.hyprland.hyprlock.enable =
lib.mkEnableOption "the hyprlock lock screen";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user} = { home-manager.users.${user} = {

View File

@@ -10,7 +10,8 @@ let
cfg = config.modules.desktop.session.login; cfg = config.modules.desktop.session.login;
in in
{ {
options.modules.desktop.session.login.enable = lib.mkEnableOption "greetd with the tuigreet text greeter"; options.modules.desktop.session.login.enable =
lib.mkEnableOption "greetd with the tuigreet text greeter";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
services.greetd = { services.greetd = {

View File

@@ -25,7 +25,8 @@ let
''; '';
in in
{ {
options.modules.desktop.utilities.clipboard.enable = lib.mkEnableOption "cliphist clipboard history"; options.modules.desktop.utilities.clipboard.enable =
lib.mkEnableOption "cliphist clipboard history";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user} = { home-manager.users.${user} = {

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.desktop.utilities.osd.enable = lib.mkEnableOption "the SwayOSD volume and brightness popup"; options.modules.desktop.utilities.osd.enable =
lib.mkEnableOption "the SwayOSD volume and brightness popup";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
environment.systemPackages = [ pkgs.swayosd ]; environment.systemPackages = [ pkgs.swayosd ];

View File

@@ -41,7 +41,8 @@ let
''; '';
in in
{ {
options.modules.desktop.utilities.recording.enable = lib.mkEnableOption "wf-recorder screen recording"; options.modules.desktop.utilities.recording.enable =
lib.mkEnableOption "wf-recorder screen recording";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user} = { home-manager.users.${user} = {

View File

@@ -32,7 +32,8 @@ let
''; '';
in in
{ {
options.modules.desktop.utilities.screenshot.enable = lib.mkEnableOption "screenshots via grimblast and satty"; options.modules.desktop.utilities.screenshot.enable =
lib.mkEnableOption "screenshots via grimblast and satty";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user} = { home-manager.users.${user} = {

View File

@@ -5,7 +5,7 @@
}: }:
let let
cfg = config.modules.host; cfg = config.modules.host;
user = config.user; inherit (config) user;
hostSecrets = ../secrets + "/${config.networking.hostName}.yaml"; hostSecrets = ../secrets + "/${config.networking.hostName}.yaml";
passwordSecret = "${user.name}-password"; passwordSecret = "${user.name}-password";
in in

View File

@@ -104,8 +104,7 @@ let
isWorkstation = elem currentHost cfg.hosts.workstations; isWorkstation = elem currentHost cfg.hosts.workstations;
defaultAuthorizedKeys = lib.flatten ( defaultAuthorizedKeys = lib.flatten (
clientKeysFor workstationNames clientKeysFor workstationNames ++ optional isServer (clientKeysFor serverNames)
++ optional isServer (clientKeysFor serverNames)
); );
outboundTargetNames = outboundTargetNames =
@@ -120,7 +119,8 @@ let
in in
filter (name: name != currentHost) (targetNamesIn groupTargets); filter (name: name != currentHost) (targetNamesIn groupTargets);
sshSettingsFor = name: sshSettingsFor =
name:
let let
target = cfg.targets.${name}; target = cfg.targets.${name};
in in
@@ -131,7 +131,8 @@ let
} }
// optionalAttrs (target.port != 22) { Port = target.port; }; // optionalAttrs (target.port != 22) { Port = target.port; };
knownHostNamesFor = target: knownHostNamesFor =
target:
let let
names = unique (target.aliases ++ [ target.hostName ]); names = unique (target.aliases ++ [ target.hostName ]);
withPort = name: if target.port == 22 then name else "[${name}]:${toString target.port}"; withPort = name: if target.port == 22 then name else "[${name}]:${toString target.port}";
@@ -142,7 +143,8 @@ let
concatLists ( concatLists (
mapAttrsToList ( mapAttrsToList (
targetName: target: targetName: target:
imap0 (i: key: imap0 (
i: key:
nameValuePair "${targetName}-${toString i}" { nameValuePair "${targetName}-${toString i}" {
hostNames = knownHostNamesFor target; hostNames = knownHostNamesFor target;
publicKey = keyWithoutComment key; publicKey = keyWithoutComment key;
@@ -290,8 +292,7 @@ in
}; };
}; };
config = mkIf cfg.enable ( config = mkIf cfg.enable (mkMerge [
mkMerge [
{ {
services.openssh.enable = true; services.openssh.enable = true;
@@ -342,6 +343,5 @@ in
home-manager.users.${user}.programs.ssh.settings."*".IdentityFile = home-manager.users.${user}.programs.ssh.settings."*".IdentityFile =
config.sops.secrets.${userKeySecret}.path; config.sops.secrets.${userKeySecret}.path;
}) })
] ]);
);
} }

View File

@@ -75,8 +75,9 @@ in
]; ];
# networkd owns these interfaces so NetworkManager does not contend for them. # networkd owns these interfaces so NetworkManager does not contend for them.
networking.networkmanager.unmanaged = networking.networkmanager.unmanaged = [
[ "interface-name:${cfg.trunk}" ] "interface-name:${cfg.trunk}"
]
++ map (id: "interface-name:${bridgeName id}") cfg.ids ++ map (id: "interface-name:${bridgeName id}") cfg.ids
++ map (id: "interface-name:${vlanName id}") cfg.ids; ++ map (id: "interface-name:${vlanName id}") cfg.ids;

View File

@@ -88,16 +88,18 @@ in
networking.wireguard.interfaces.${cfg.interface} = { networking.wireguard.interfaces.${cfg.interface} = {
ips = [ cfg.address ]; ips = [ cfg.address ];
mtu = cfg.mtu; inherit (cfg) mtu;
privateKeyFile = config.sops.secrets.${cfg.privateKeySecret}.path; privateKeyFile = config.sops.secrets.${cfg.privateKeySecret}.path;
peers = [ peers = [
({ (
{
inherit (cfg.peer) publicKey endpoint allowedIPs; inherit (cfg.peer) publicKey endpoint allowedIPs;
} }
// lib.optionalAttrs (cfg.peer.persistentKeepalive != null) { // lib.optionalAttrs (cfg.peer.persistentKeepalive != null) {
inherit (cfg.peer) persistentKeepalive; inherit (cfg.peer) persistentKeepalive;
}) }
)
]; ];
}; };
}; };

View File

@@ -45,14 +45,14 @@ in
users.users.${cfg.user} = { users.users.${cfg.user} = {
isSystemUser = true; isSystemUser = true;
uid = config.registry."stable-uid".${config.networking.hostName}.actualbudget; uid = config.registry."stable-uid".${config.networking.hostName}.actualbudget;
group = cfg.group; inherit (cfg) group;
}; };
services.actual = { services.actual = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;
user = cfg.user; inherit (cfg) user;
group = cfg.group; inherit (cfg) group;
settings = { settings = {
inherit (cfg) port dataDir; inherit (cfg) port dataDir;
}; };

View File

@@ -40,13 +40,16 @@ let
renderAccess = permission: accounts: " ${permission}: ${lib.concatStringsSep ", " accounts}"; renderAccess = permission: accounts: " ${permission}: ${lib.concatStringsSep ", " accounts}";
hasFlag = name: flags: lib.any (flag: lib.hasPrefix "${name}:" flag || lib.hasPrefix "${name}=" flag) flags; hasFlag =
name: flags: lib.any (flag: lib.hasPrefix "${name}:" flag || lib.hasPrefix "${name}=" flag) flags;
defaultPermissionFlags = flags: defaultPermissionFlags =
flags:
lib.optionals (!(hasFlag "chmod_d" flags)) [ "chmod_d: 2770" ] lib.optionals (!(hasFlag "chmod_d" flags)) [ "chmod_d: 2770" ]
++ lib.optionals (!(hasFlag "chmod_f" flags)) [ "chmod_f: 660" ]; ++ lib.optionals (!(hasFlag "chmod_f" flags)) [ "chmod_f: 660" ];
renderFlags = flags: lib.concatMapStringsSep "\n" (flag: " ${flag}") (flags ++ defaultPermissionFlags flags); renderFlags =
flags: lib.concatMapStringsSep "\n" (flag: " ${flag}") (flags ++ defaultPermissionFlags flags);
renderVolume = urlPath: volume: '' renderVolume = urlPath: volume: ''
[${urlPath}] [${urlPath}]
@@ -173,7 +176,7 @@ in
users.users.${cfg.user} = { users.users.${cfg.user} = {
isSystemUser = true; isSystemUser = true;
uid = config.registry."stable-uid".${config.networking.hostName}.copyparty; uid = config.registry."stable-uid".${config.networking.hostName}.copyparty;
group = cfg.group; inherit (cfg) group;
home = cfg.stateDir; home = cfg.stateDir;
}; };
@@ -202,7 +205,10 @@ in
PrivateTmp = true; PrivateTmp = true;
ProtectSystem = "strict"; ProtectSystem = "strict";
ProtectHome = true; ProtectHome = true;
ReadWritePaths = [ cfg.stateDir ] ++ map (volume: volume.path) (lib.filter (volume: !volume.readOnly) (lib.attrValues cfg.volumes)); ReadWritePaths = [
cfg.stateDir
]
++ map (volume: volume.path) (lib.filter (volume: !volume.readOnly) (lib.attrValues cfg.volumes));
}; };
}; };

View File

@@ -134,8 +134,7 @@
appId = 2394010; appId = 2394010;
inherit (service) autoStart; inherit (service) autoStart;
executable = "${startScript}"; executable = "${startScript}";
arguments = arguments = [
[
"-useperfthreads" "-useperfthreads"
"-NoAsyncLoadingThread" "-NoAsyncLoadingThread"
"-UseMultithreadForDS" "-UseMultithreadForDS"

View File

@@ -7,7 +7,9 @@
let let
cfg = config.modules.services.homepage; cfg = config.modules.services.homepage;
mkRegistryPath = registryName: host: entry: "registry.${registryName}.${host}.${entry}"; mkRegistryPath =
registryName: host: entry:
"registry.${registryName}.${host}.${entry}";
homepageEntries = lib.concatLists ( homepageEntries = lib.concatLists (
lib.mapAttrsToList ( lib.mapAttrsToList (
@@ -19,7 +21,8 @@ let
) registry.homepage ) registry.homepage
); );
mkHref = item: mkHref =
item:
if item.homepage.href != null then if item.homepage.href != null then
item.homepage.href item.homepage.href
else if (item.composite.route or null) != null then else if (item.composite.route or null) != null then
@@ -32,7 +35,8 @@ let
else else
throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching route entry"; throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching route entry";
mkServiceAttrs = item: mkServiceAttrs =
item:
lib.filterAttrs (_: value: value != null) { lib.filterAttrs (_: value: value != null) {
href = mkHref item; href = mkHref item;
inherit (item.homepage) description icon; inherit (item.homepage) description icon;
@@ -40,11 +44,11 @@ let
sortedEntries = lib.sort (left: right: left.homepage.name < right.homepage.name) homepageEntries; sortedEntries = lib.sort (left: right: left.homepage.name < right.homepage.name) homepageEntries;
insertEntry = acc: item: insertEntry =
acc: item:
acc acc
// { // {
${item.homepage.tab} = (acc.${item.homepage.tab} or { }) ${item.homepage.tab} = (acc.${item.homepage.tab} or { }) // {
// {
${item.homepage.section} = (acc.${item.homepage.tab}.${item.homepage.section} or [ ]) ++ [ ${item.homepage.section} = (acc.${item.homepage.tab}.${item.homepage.section} or [ ]) ++ [
{ ${item.homepage.name} = mkServiceAttrs item; } { ${item.homepage.name} = mkServiceAttrs item; }
]; ];
@@ -80,13 +84,15 @@ let
]; ];
}; };
orderedSections = tab: sections: orderedSections =
tab: sections:
let let
sectionOrder = sectionOrderByTab.${tab} or [ ]; sectionOrder = sectionOrderByTab.${tab} or [ ];
in in
sectionOrder ++ lib.filter (section: !lib.elem section sectionOrder) (lib.attrNames sections); sectionOrder ++ lib.filter (section: !lib.elem section sectionOrder) (lib.attrNames sections);
mkTab = tab: mkTab =
tab:
let let
sections = entriesByTab.${tab}; sections = entriesByTab.${tab};
in in
@@ -148,7 +154,9 @@ in
openFirewall = true; openFirewall = true;
inherit (cfg) listenPort; inherit (cfg) listenPort;
environmentFiles = [ cfg.environmentFile ]; environmentFiles = [ cfg.environmentFile ];
allowedHosts = lib.concatStringsSep "," (if cfg.allowedHosts == null then derivedAllowedHosts else cfg.allowedHosts); allowedHosts = lib.concatStringsSep "," (
if cfg.allowedHosts == null then derivedAllowedHosts else cfg.allowedHosts
);
services = homepageServices; services = homepageServices;
widgets = [ widgets = [
{ {

View File

@@ -50,7 +50,7 @@ in
user = "navidrome"; user = "navidrome";
group = "storage"; group = "storage";
openFirewall = true; openFirewall = true;
environmentFile = cfg.environmentFile; inherit (cfg) environmentFile;
settings = { settings = {
Address = "0.0.0.0"; Address = "0.0.0.0";
Port = 4533; Port = 4533;

View File

@@ -7,15 +7,20 @@
let let
cfg = config.modules.services.reverse-proxy; cfg = config.modules.services.reverse-proxy;
mkRegistryPath = registryName: host: entry: "registry.${registryName}.${host}.${entry}"; mkRegistryPath =
registryName: host: entry:
"registry.${registryName}.${host}.${entry}";
mkBackend = address: port: "http://${address}:${toString port}"; mkBackend = address: port: "http://${address}:${toString port}";
mkVirtualHost = host: entry: mode: mkVirtualHost =
host: entry: mode:
let let
compositeEntry = registry.join host entry; compositeEntry = registry.join host entry;
route = compositeEntry.route; inherit (compositeEntry) route;
address = compositeEntry.address or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}"); address =
compositeEntry.address
or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
isHttp = mode == "http"; isHttp = mode == "http";
port = if isHttp then route.http.port else route.port; port = if isHttp then route.http.port else route.port;
in in
@@ -63,7 +68,11 @@ let
domain: virtualHosts: domain: virtualHosts:
if lib.length virtualHosts > 1 then if lib.length virtualHosts > 1 then
[ [
"duplicate route domain ${domain} in ${lib.concatMapStringsSep " and " (virtualHost: mkRegistryPath virtualHost.registryName virtualHost.host virtualHost.entry) virtualHosts}" "duplicate route domain ${domain} in ${
lib.concatMapStringsSep " and " (
virtualHost: mkRegistryPath virtualHost.registryName virtualHost.host virtualHost.entry
) virtualHosts
}"
] ]
else else
[ ] [ ]
@@ -76,13 +85,21 @@ let
else else
lib.listToAttrs generatedVirtualHostList; lib.listToAttrs generatedVirtualHostList;
mkUdpStream = host: entry: port: mkUdpStream =
host: entry: port:
let let
compositeEntry = registry.join host entry; compositeEntry = registry.join host entry;
address = compositeEntry.address or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}"); address =
compositeEntry.address
or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
in in
{ {
inherit host entry port address; inherit
host
entry
port
address
;
}; };
generatedUdpStreams = lib.concatLists ( generatedUdpStreams = lib.concatLists (

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.shell.bazel.enable = lib.mkEnableOption "Bazel for the primary user's shell environment"; options.modules.shell.bazel.enable =
lib.mkEnableOption "Bazel for the primary user's shell environment";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.${user}.home.packages = [ pkgs.bazel ]; home-manager.users.${user}.home.packages = [ pkgs.bazel ];

View File

@@ -107,8 +107,7 @@ in
# Rendered by home-manager into ~/.config/fish/config.fish. # Rendered by home-manager into ~/.config/fish/config.fish.
interactiveShellInit = lib.concatStringsSep "\n" ( interactiveShellInit = lib.concatStringsSep "\n" (
(lib.mapAttrsToList exportEnvVar envVars) (lib.mapAttrsToList exportEnvVar envVars) ++ [ (builtins.readFile ./config.fish) ]
++ [ (builtins.readFile ./config.fish) ]
); );
}; };
}; };

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.shell.herdr.enable = lib.mkEnableOption "Herdr, a terminal multiplexer for coding agents"; options.modules.shell.herdr.enable =
lib.mkEnableOption "Herdr, a terminal multiplexer for coding agents";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
registry.shell-shortcut.${config.networking.hostName}.hs = "herdr --session"; registry.shell-shortcut.${config.networking.hostName}.hs = "herdr --session";

View File

@@ -11,7 +11,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.shell.nvim.enable = lib.mkEnableOption "Neovim, configured declaratively via nixvim"; options.modules.shell.nvim.enable =
lib.mkEnableOption "Neovim, configured declaratively via nixvim";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
registry.shell-shortcut.${config.networking.hostName} = { registry.shell-shortcut.${config.networking.hostName} = {

View File

@@ -18,8 +18,7 @@ let
in in
{ {
options.modules.shell.pi = { options.modules.shell.pi = {
enable = lib.mkEnableOption '' enable = lib.mkEnableOption "Pi, a terminal coding agent, configured through home-manager";
Pi, a terminal coding agent, configured through home-manager'';
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {

View File

@@ -10,7 +10,8 @@ let
user = config.user.name; user = config.user.name;
in in
{ {
options.modules.shell.python.enable = lib.mkEnableOption "Python tools for the primary user's shell environment"; options.modules.shell.python.enable =
lib.mkEnableOption "Python tools for the primary user's shell environment";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
registry.env-var.${config.networking.hostName}.PYTHON_TOOLCHAIN_ROOT = "${pkgs.python3}"; registry.env-var.${config.networking.hostName}.PYTHON_TOOLCHAIN_ROOT = "${pkgs.python3}";

View File

@@ -20,7 +20,8 @@ let
}; };
in in
{ {
options.modules.shell.rust.enable = lib.mkEnableOption "Rust tools for the primary user's shell environment"; options.modules.shell.rust.enable =
lib.mkEnableOption "Rust tools for the primary user's shell environment";
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
registry.env-var.${config.networking.hostName}.RUST_TOOLCHAIN_ROOT = "${toolchain}"; registry.env-var.${config.networking.hostName}.RUST_TOOLCHAIN_ROOT = "${toolchain}";

View File

@@ -6,14 +6,16 @@
message = "Route domains must be unique."; message = "Route domains must be unique.";
} }
{ {
assertion = entries: assertion =
entries:
lib.registry.predicates.uniqueValue (entry: entry.value) ( lib.registry.predicates.uniqueValue (entry: entry.value) (
lib.concatMap (entry: map (port: entry // { value = port; }) entry.value.udp.ports) entries lib.concatMap (entry: map (port: entry // { value = port; }) entry.value.udp.ports) entries
); );
message = "Route UDP ports must be unique."; message = "Route UDP ports must be unique.";
} }
{ {
assertion = entries: lib.all (entry: entry.value.port == null || entry.value.http.port == null) entries; assertion =
entries: lib.all (entry: entry.value.port == null || entry.value.http.port == null) entries;
message = "Route entries must not set both port and http.port."; message = "Route entries must not set both port and http.port.";
} }
]; ];

View File

@@ -7,12 +7,14 @@ let
unique unique
; ;
serviceNamesByUid = entries: serviceNamesByUid =
entries:
mapAttrs (_uid: uidEntries: unique (map (entry: entry.entry) uidEntries)) ( mapAttrs (_uid: uidEntries: unique (map (entry: entry.entry) uidEntries)) (
groupBy (entry: toString entry.value) entries groupBy (entry: toString entry.value) entries
); );
duplicateUids = entries: duplicateUids =
entries:
filterAttrs (_uid: serviceNames: builtins.length serviceNames > 1) (serviceNamesByUid entries); filterAttrs (_uid: serviceNames: builtins.length serviceNames > 1) (serviceNamesByUid entries);
in in

View File

@@ -78,7 +78,7 @@
{ self, nixpkgs, ... }@inputs: { self, nixpkgs, ... }@inputs:
import ./src/dotfiles { import ./src/dotfiles {
inherit inputs self; inherit inputs self;
lib = nixpkgs.lib; inherit (nixpkgs) lib;
root = ./configs/nixos; root = ./configs/nixos;
system = "x86_64-linux"; system = "x86_64-linux";
}; };

View File

@@ -10,7 +10,8 @@ in
{ {
fix = { fix = {
type = "app"; type = "app";
program = lib.getExe (pkgs.writeShellApplication { program = lib.getExe (
pkgs.writeShellApplication {
name = "fix"; name = "fix";
runtimeInputs = [ runtimeInputs = [
formatter.config.build.wrapper formatter.config.build.wrapper
@@ -23,6 +24,7 @@ in
deadnix --edit --exclude configs/nixos/hosts/*/hardware-configuration.nix -- . deadnix --edit --exclude configs/nixos/hosts/*/hardware-configuration.nix -- .
treefmt treefmt
''; '';
}); }
);
}; };
} }

View File

@@ -17,16 +17,13 @@ let
directoryMounts = lib.filterAttrs (_: mount: mount.directory != null) cfg.mounts; directoryMounts = lib.filterAttrs (_: mount: mount.directory != null) cfg.mounts;
directoryScript = lib.concatStringsSep "\n" ( directoryScript = lib.concatStringsSep "\n" (
lib.mapAttrsToList ( lib.mapAttrsToList (_: mount: ''
_: mount:
''
${config.system.path}/bin/install -d \ ${config.system.path}/bin/install -d \
${lib.optionalString (mount.owner != null) "-o ${lib.escapeShellArg (toString mount.owner)}"} \ ${lib.optionalString (mount.owner != null) "-o ${lib.escapeShellArg (toString mount.owner)}"} \
${lib.optionalString (mount.group != null) "-g ${lib.escapeShellArg mount.group}"} \ ${lib.optionalString (mount.group != null) "-g ${lib.escapeShellArg mount.group}"} \
${lib.optionalString (mount.mode != null) "-m ${lib.escapeShellArg mount.mode}"} \ ${lib.optionalString (mount.mode != null) "-m ${lib.escapeShellArg mount.mode}"} \
${lib.escapeShellArg mount.directory} ${lib.escapeShellArg mount.directory}
'' '') directoryMounts
) directoryMounts
); );
in in
{ {
@@ -171,14 +168,20 @@ let
assertions = assertions =
let let
hasDirectorySettings = mount: mount.owner != null || mount.group != null || mount.mode != null; hasDirectorySettings = mount: mount.owner != null || mount.group != null || mount.mode != null;
hasCompleteDirectorySettings = mount: mount.owner != null && mount.group != null && mount.mode != null; hasCompleteDirectorySettings =
mount: mount.owner != null && mount.group != null && mount.mode != null;
hasOneSource = mount: (mount.directory != null) != (mount.file != null); hasOneSource = mount: (mount.directory != null) != (mount.file != null);
mountsWithInvalidSource = lib.attrNames (lib.filterAttrs (_: mount: !hasOneSource mount) cfg.mounts); mountsWithInvalidSource = lib.attrNames (
lib.filterAttrs (_: mount: !hasOneSource mount) cfg.mounts
);
fileMountsWithHostSettings = lib.attrNames ( fileMountsWithHostSettings = lib.attrNames (
lib.filterAttrs (_: mount: mount.file != null && hasDirectorySettings mount) cfg.mounts lib.filterAttrs (_: mount: mount.file != null && hasDirectorySettings mount) cfg.mounts
); );
directoryMountsWithPartialHostSettings = lib.attrNames ( directoryMountsWithPartialHostSettings = lib.attrNames (
lib.filterAttrs (_: mount: mount.directory != null && hasDirectorySettings mount && !hasCompleteDirectorySettings mount) cfg.mounts lib.filterAttrs (
_: mount:
mount.directory != null && hasDirectorySettings mount && !hasCompleteDirectorySettings mount
) cfg.mounts
); );
in in
[ [
@@ -203,20 +206,23 @@ let
{ {
assertion = lib.elem cfg.vlan config.modules.network.vlans.ids; assertion = lib.elem cfg.vlan config.modules.network.vlans.ids;
message = '' message = ''
guests.${name}.vlan = ${toString cfg.vlan} is not among its host's modules.network.vlans.ids (${lib.concatMapStringsSep ", " toString config.modules.network.vlans.ids}). Declare the VLAN on the host or correct the guest's placement. guests.${name}.vlan = ${toString cfg.vlan} is not among its host's modules.network.vlans.ids (${
lib.concatMapStringsSep ", " toString config.modules.network.vlans.ids
}). Declare the VLAN on the host or correct the guest's placement.
''; '';
} }
]; ];
registry.address.${config.networking.hostName}.${name} = registry.address.${config.networking.hostName}.${name} = lib.mkIf (cfg.address != null) cfg.address;
lib.mkIf (cfg.address != null) cfg.address;
registry.route.${config.networking.hostName}.${name} = registry.route.${config.networking.hostName}.${name} =
lib.mkIf cfg.reverseProxy.enable cfg.reverseProxy.route; lib.mkIf cfg.reverseProxy.enable cfg.reverseProxy.route;
systemd.services."container@${name}" = systemd.services."container@${name}" =
let let
bridgeDevice = "sys-subsystem-net-devices-${lib.replaceStrings [ "-" ] [ "\\x2d" ] (util.bridgeName cfg.vlan)}.device"; bridgeDevice = "sys-subsystem-net-devices-${
lib.replaceStrings [ "-" ] [ "\\x2d" ] (util.bridgeName cfg.vlan)
}.device";
in in
{ {
after = [ bridgeDevice ]; after = [ bridgeDevice ];
@@ -268,10 +274,11 @@ let
}; };
}; };
}; };
in
let
files = util.collectNixFiles root; files = util.collectNixFiles root;
guestFiles = lib.filterAttrs (file: type: type == "regular" && lib.hasSuffix ".nix" file) (builtins.readDir root); guestFiles = lib.filterAttrs (file: type: type == "regular" && lib.hasSuffix ".nix" file) (
builtins.readDir root
);
names = map (file: lib.removeSuffix ".nix" file) (lib.attrNames guestFiles); names = map (file: lib.removeSuffix ".nix" file) (lib.attrNames guestFiles);
in in
{ {

View File

@@ -26,7 +26,8 @@ let
guestModules guestModules
# TODO: refactor # TODO: refactor
registryModule (root + "/${name}") registryModule
(root + "/${name}")
{ {
networking.hostName = name; networking.hostName = name;
@@ -34,12 +35,8 @@ let
} }
]; ];
}; };
in
let
directories = lib.filterAttrs (_name: type: type == "directory") (builtins.readDir root); directories = lib.filterAttrs (_name: type: type == "directory") (builtins.readDir root);
names = lib.attrNames directories; names = lib.attrNames directories;
in in
lib.genAttrs names ( lib.genAttrs names (name: mkHost { inherit root name; })
name:
mkHost { inherit root name; }
)

View File

@@ -1,4 +1,8 @@
{ hosts, lib, root }: {
hosts,
lib,
root,
}:
let let
checkType = lib.types.submodule { checkType = lib.types.submodule {
options = { options = {
@@ -19,7 +23,8 @@ let
}; };
predicates = { predicates = {
uniqueValue = value: entries: builtins.length (lib.unique (map value entries)) == builtins.length entries; uniqueValue =
value: entries: builtins.length (lib.unique (map value entries)) == builtins.length entries;
}; };
registryLib = lib // { registryLib = lib // {
@@ -57,7 +62,9 @@ let
registryName = fileName: lib.removeSuffix ".nix" fileName; registryName = fileName: lib.removeSuffix ".nix" fileName;
registryOption = registry: lib.mkOption { registryOption =
registry:
lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf registry.type); type = lib.types.attrsOf (lib.types.attrsOf registry.type);
default = { }; default = { };
description = '' description = ''
@@ -65,7 +72,8 @@ let
''; '';
}; };
mkRegistry = path: mkRegistry =
path:
let let
evaluated = lib.evalModules { evaluated = lib.evalModules {
specialArgs.lib = registryLib; specialArgs.lib = registryLib;
@@ -79,15 +87,21 @@ let
inherit (evaluated.config) type replicate checks; inherit (evaluated.config) type replicate checks;
}; };
definitions = lib.mapAttrs' ( definitions =
name: type: lib.mapAttrs'
(
name: _type:
let let
path = root + "/${name}"; path = root + "/${name}";
in in
lib.nameValuePair (registryName name) (mkRegistry path) lib.nameValuePair (registryName name) (mkRegistry path)
) (lib.filterAttrs (name: type: type == "regular" && lib.hasSuffix ".nix" name) (builtins.readDir root)); )
(
lib.filterAttrs (name: type: type == "regular" && lib.hasSuffix ".nix" name) (builtins.readDir root)
);
flattenRegistryEntries = registryName: data: flattenRegistryEntries =
registryName: data:
lib.concatLists ( lib.concatLists (
lib.mapAttrsToList ( lib.mapAttrsToList (
host: entries: host: entries:
@@ -98,10 +112,12 @@ let
) data ) data
); );
rawDeclarations = registryName: hosts: rawDeclarations =
registryName: hosts:
lib.mapAttrs (_hostName: host: host.config.registry.${registryName} or { }) hosts; lib.mapAttrs (_hostName: host: host.config.registry.${registryName} or { }) hosts;
replicatedEntries = registryName: raw: replicatedEntries =
registryName: raw:
let let
entries = lib.concatLists ( entries = lib.concatLists (
lib.concatLists ( lib.concatLists (
@@ -126,18 +142,21 @@ let
else else
throw "conflicting replicated registry entry ${entry.path} does not match ${acc.${entry.entryName}.path}" throw "conflicting replicated registry entry ${entry.path} does not match ${acc.${entry.entryName}.path}"
else else
acc // { acc
// {
${entry.entryName} = entry; ${entry.entryName} = entry;
} }
) { } entries; ) { } entries;
replicatedData = registryName: hosts: raw: replicatedData =
registryName: hosts: raw:
let let
entries = lib.mapAttrs (_entryName: entry: entry.value) (replicatedEntries registryName raw); entries = lib.mapAttrs (_entryName: entry: entry.value) (replicatedEntries registryName raw);
in in
lib.mapAttrs (_hostName: _host: entries) hosts; lib.mapAttrs (_hostName: _host: entries) hosts;
validationAssertions = data: validationAssertions =
data:
lib.concatLists ( lib.concatLists (
lib.mapAttrsToList ( lib.mapAttrsToList (
registryName: registry: registryName: registry:
@@ -151,7 +170,8 @@ let
) definitions ) definitions
); );
assertValid = data: assertValid =
data:
let let
assertions = validationAssertions data; assertions = validationAssertions data;
failures = lib.filter (assertion: !assertion.assertion) assertions; failures = lib.filter (assertion: !assertion.assertion) assertions;
@@ -161,9 +181,12 @@ let
); );
data; data;
join = registry: host: entry: join =
registry: host: entry:
lib.filterAttrs (_name: value: value != null) ( lib.filterAttrs (_name: value: value != null) (
lib.mapAttrs (registryName: _registry: (registry.${registryName}.${host} or { }).${entry} or null) definitions lib.mapAttrs (
registryName: _registry: (registry.${registryName}.${host} or { }).${entry} or null
) definitions
); );
collectData = collectData =
@@ -180,7 +203,8 @@ let
in in
assertValid data; assertValid data;
withOperations = registry: withOperations =
registry:
registry registry
// { // {
join = host: entry: join registry host entry; join = host: entry: join registry host entry;
@@ -190,8 +214,10 @@ in
types = lib.mapAttrs (_name: definition: definition.type) definitions; types = lib.mapAttrs (_name: definition: definition.type) definitions;
module = { module = {
options.registry = lib.mapAttrs (_name: registry: registryOption registry) definitions; options.registry = lib.mapAttrs (_name: registryOption) definitions;
}; };
collected = withOperations (collectData { inherit hosts; }); collected = withOperations (collectData {
inherit hosts;
});
} }

View File

@@ -28,5 +28,14 @@ in
hash = builtins.hashString "sha256" name; hash = builtins.hashString "sha256" name;
octet = i: builtins.substring (i * 2) 2 hash; octet = i: builtins.substring (i * 2) 2 hash;
in in
lib.concatStringsSep ":" ([ "02" ] ++ map octet [ 0 1 2 3 4 ]); lib.concatStringsSep ":" (
[ "02" ]
++ map octet [
0
1
2
3
4
]
);
} }