Compare commits

...

2 Commits

Author SHA1 Message Date
kiri 0500aab3cb refactor: further progress 2026-04-25 00:19:20 +02:00
kiri 55fbe82a42 refactor: orion and base 2026-04-24 21:57:43 +02:00
34 changed files with 819 additions and 1202 deletions
+64 -71
View File
@@ -1,58 +1,69 @@
{ lib, ... }:
{
config,
...
}:
let
userSpecs = {
kiri = {
realName = "Jelle Spreeuwenberg";
homeDirectory = "/home/kiri";
emails = {
personal = {
address = "mail@jelles.net";
primary = true;
scope = "personal";
type = "mxrouting";
};
old = {
address = "mail@jellespreeuwenberg.nl";
scope = null;
type = "mxrouting";
};
uni = {
address = "j.spreeuwenberg@student.tue.nl";
scope = null;
type = "office365";
};
work = {
address = "jelle.spreeuwenberg@yookr.org";
scope = "work";
type = "office365";
};
};
sourceControl = { };
};
ergon = {
realName = "Jelle Spreeuwenberg";
homeDirectory = "/home/ergon";
emails = {
personal = {
address = "mail@jelles.net";
scope = "personal";
type = "mxrouting";
};
work = {
address = "jelle.spreeuwenberg@yookr.org";
primary = true;
scope = "work";
type = "office365";
};
};
sourceControl.projectScope = "work";
};
};
accounts = lib.mapAttrs (name: spec: spec // { inherit name; }) userSpecs;
homeModules = config.flake.modules.homeManager;
in
{
repo = {
accounts = {
kiri = {
realName = "Jelle Spreeuwenberg";
workstationModule = {
imports = [
homeModules.workstation-base
homeModules.syncthing
homeModules.qbittorrent-client
];
};
emails = {
personal = {
address = "mail@jelles.net";
primary = true;
scope = "personal";
type = "mxrouting";
};
old = {
address = "mail@jellespreeuwenberg.nl";
scope = null;
type = "mxrouting";
};
uni = {
address = "j.spreeuwenberg@student.tue.nl";
scope = null;
type = "office365";
};
work = {
address = "jelle.spreeuwenberg@yookr.org";
scope = "work";
type = "office365";
};
};
};
ergon = {
realName = "Jelle Spreeuwenberg";
sourceControl.projectScope = "work";
workstationModule = {
imports = [ homeModules.workstation-base ];
};
emails = {
personal = {
address = "mail@jelles.net";
scope = "personal";
type = "mxrouting";
};
work = {
address = "jelle.spreeuwenberg@yookr.org";
primary = true;
scope = "work";
type = "office365";
};
};
};
};
contact.email = "mail@jelles.net";
desktop = {
@@ -173,22 +184,4 @@ let
};
};
};
in
{
options.meta.lib.repo = lib.mkOption {
type = lib.types.attrs;
description = "Internal shared repository metadata.";
internal = true;
readOnly = true;
};
options.meta.lib.accounts = lib.mkOption {
type = lib.types.attrs;
description = "Canonical account attrsets shared by host definitions.";
internal = true;
readOnly = true;
};
config.meta.lib.repo = repo;
config.meta.lib.accounts = accounts;
}
+1 -1
View File
@@ -61,7 +61,7 @@ in
"context-remaining"
"five-hour-limit"
];
projects.${config.meta.user.nixosConfigurationPath}.trust_level = "trusted";
projects.${config.meta.user.account.nixosConfigurationPath}.trust_level = "trusted";
sandbox_mode = "workspace-write";
personality = "pragmatic";
features.undo = true;
+4 -4
View File
@@ -3,7 +3,7 @@
...
}:
let
metaRepo = config.meta.lib.repo;
repo = config.repo;
in
{
flake.modules.homeManager.bitwarden =
@@ -13,14 +13,14 @@ in
...
}:
let
user = config.meta.user;
account = config.meta.user.account;
in
{
programs.rbw = {
enable = true;
settings = {
base_url = metaRepo.services.vaultwarden.url;
email = user.primaryEmail.address;
base_url = repo.services.vaultwarden.url;
email = account.primaryEmail.address;
pinentry = pkgs.pinentry-gnome3;
};
};
+4 -4
View File
@@ -7,7 +7,7 @@
...
}:
let
user = config.meta.user;
account = config.meta.user.account;
mkOffice365Account =
{
address,
@@ -17,7 +17,7 @@
{
enable = true;
inherit address primary;
realName = user.realName;
realName = account.realName;
userName = address;
thunderbird = {
enable = true;
@@ -37,7 +37,7 @@
{
enable = true;
inherit address primary;
realName = user.realName;
realName = account.realName;
userName = address;
thunderbird.enable = true;
imap = {
@@ -81,6 +81,6 @@
};
};
accounts.email.accounts = lib.mapAttrs (_: mkEmailAccount) user.emails;
accounts.email.accounts = lib.mapAttrs (_: mkEmailAccount) account.emails;
};
}
+3 -3
View File
@@ -6,7 +6,7 @@
...
}:
let
user = config.meta.user;
account = config.meta.user.account;
in
{
programs.git = {
@@ -19,8 +19,8 @@
settings = {
init.defaultBranch = "main";
user = {
name = user.realName;
email = user.primaryEmail.address;
name = account.realName;
email = account.primaryEmail.address;
};
};
};
-27
View File
@@ -1,27 +0,0 @@
{
config,
...
}:
let
metaLib = config.meta.lib;
in
{
flake.modules.nixos.input =
{
lib,
config,
...
}:
let
inputProfiles = metaLib.mkInputProfiles config.meta.host.input;
in
{
services.libinput = lib.mkIf inputProfiles.hasPointerConfig {
enable = true;
inherit (inputProfiles.libinput)
mouse
touchpad
;
};
};
}
+5 -4
View File
@@ -1,18 +1,19 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.homeManager.local-apps =
{ pkgs, ... }:
let
browserPackage = config.meta.lib.resolvePackagePath {
browserPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = metaRepo.desktop.browser.packagePath;
path = repo.desktop.browser.packagePath;
};
in
{
home.sessionVariables.BROWSER = metaRepo.desktop.browser.command;
home.sessionVariables.BROWSER = repo.desktop.browser.command;
home.packages =
with pkgs;
-386
View File
@@ -1,386 +0,0 @@
{ lib, ... }:
let
nonEmptyStrType = lib.types.addCheck lib.types.str (value: lib.stringLength value > 0);
mkNullableOption =
type:
lib.mkOption {
type = lib.types.nullOr type;
default = null;
};
hasSinglePrimaryEmail =
user: builtins.length (lib.filter (email: email.primary) (builtins.attrValues user.emails)) == 1;
scopeEmailCount =
scope: user:
builtins.length (lib.filter (email: email.scope == scope) (builtins.attrValues user.emails));
hasAtMostOneScopedEmail = scope: user: scopeEmailCount scope user <= 1;
requiredSourceControlScopes =
user:
lib.unique [
"personal"
user.sourceControl.projectScope
];
hasRequiredScopedEmail = scope: user: scopeEmailCount scope user == 1;
scopeEmailAddress =
scope: user:
let
emails = lib.filter (email: email.scope == scope) (builtins.attrValues user.emails);
in
if emails == [ ] then "" else (builtins.head emails).address;
primaryEmailFallback = {
address = "";
primary = false;
scope = null;
type = "mxrouting";
};
emailProviderType = lib.types.enum [
"mxrouting"
"office365"
];
sourceControlScopeType = lib.types.enum [
"personal"
"work"
];
pointerAccelProfileType = lib.types.enum [
"adaptive"
"flat"
];
pointerScrollMethodType = lib.types.enum [
"no-scroll"
"two-finger"
"edge"
"on-button-down"
];
touchpadClickMethodType = lib.types.enum [
"button-areas"
"clickfinger"
];
emailType = lib.types.submodule (
{ ... }:
{
options = {
address = lib.mkOption {
type = lib.types.str;
};
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
type = lib.mkOption {
type = emailProviderType;
};
scope = mkNullableOption sourceControlScopeType;
};
}
);
sourceControlHostKeyType = lib.types.submodule (
{ ... }:
{
options = {
publicKey = lib.mkOption {
type = lib.types.nullOr nonEmptyStrType;
default = null;
};
privateKeyPath = mkNullableOption nonEmptyStrType;
};
}
);
sourceControlHostUserType = lib.types.submodule (
{ ... }:
{
options = {
personal = mkNullableOption sourceControlHostKeyType;
work = mkNullableOption sourceControlHostKeyType;
};
}
);
hostSourceControlType = lib.types.submodule (
{ ... }:
{
options.users = lib.mkOption {
type = lib.types.attrsOf sourceControlHostUserType;
default = { };
};
}
);
sourceControlType = lib.types.submodule (
{ ... }:
{
options = {
projectScope = lib.mkOption {
type = sourceControlScopeType;
default = "personal";
};
scopes = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ ... }:
{
options.email = lib.mkOption {
type = lib.types.str;
readOnly = true;
};
}
)
);
readOnly = true;
description = "Derived source-control identities keyed by scope.";
};
};
}
);
userType = lib.types.submodule (
{ config, ... }:
let
primaryEmails = lib.filter (email: email.primary) (builtins.attrValues config.emails);
primaryEmail = if primaryEmails == [ ] then primaryEmailFallback else builtins.head primaryEmails;
in
{
options = {
name = lib.mkOption {
type = lib.types.str;
};
realName = lib.mkOption {
type = lib.types.str;
};
homeDirectory = lib.mkOption {
type = lib.types.str;
};
nixosConfigurationPath = lib.mkOption {
type = lib.types.str;
default = "${config.homeDirectory}/.config/nixos";
};
emails = lib.mkOption {
type = lib.types.attrsOf emailType;
};
primaryEmail = lib.mkOption {
type = emailType;
readOnly = true;
description = "Derived primary email entry for this user.";
};
sourceControl = lib.mkOption {
type = sourceControlType;
default = { };
};
};
config = {
primaryEmail = primaryEmail;
sourceControl.scopes = lib.genAttrs (requiredSourceControlScopes config) (scope: {
email = scopeEmailAddress scope config;
});
};
}
);
displayModeType = lib.types.submodule (
{ ... }:
{
options = {
width = lib.mkOption {
type = lib.types.int;
};
height = lib.mkOption {
type = lib.types.int;
};
refresh = lib.mkOption {
type = lib.types.float;
};
};
}
);
displayType = lib.types.submodule (
{ ... }:
{
options = {
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
x = lib.mkOption {
type = lib.types.int;
};
y = lib.mkOption {
type = lib.types.int;
};
scale = lib.mkOption {
type = lib.types.nullOr lib.types.float;
default = null;
};
mode = lib.mkOption {
type = lib.types.nullOr displayModeType;
default = null;
};
};
}
);
mouseInputType = lib.types.submodule (
{ ... }:
{
options = {
accelProfile = mkNullableOption (pointerAccelProfileType);
accelSpeed = mkNullableOption lib.types.float;
leftHanded = mkNullableOption lib.types.bool;
middleEmulation = mkNullableOption lib.types.bool;
naturalScrolling = mkNullableOption lib.types.bool;
scrollMethod = mkNullableOption pointerScrollMethodType;
};
}
);
touchpadInputType = lib.types.submodule (
{ ... }:
{
options = {
accelProfile = mkNullableOption (pointerAccelProfileType);
accelSpeed = mkNullableOption lib.types.float;
clickMethod = mkNullableOption touchpadClickMethodType;
disableWhileTyping = mkNullableOption lib.types.bool;
leftHanded = mkNullableOption lib.types.bool;
middleEmulation = mkNullableOption lib.types.bool;
naturalScrolling = mkNullableOption lib.types.bool;
scrollMethod = mkNullableOption pointerScrollMethodType;
tapping = mkNullableOption lib.types.bool;
};
}
);
inputType = lib.types.submodule (
{ ... }:
{
options = {
mouse = lib.mkOption {
type = mouseInputType;
default = { };
};
touchpad = lib.mkOption {
type = touchpadInputType;
default = { };
};
};
}
);
hostType = lib.types.submodule (
{ ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
};
displays = lib.mkOption {
type = lib.types.attrsOf displayType;
default = { };
};
input = lib.mkOption {
type = inputType;
default = { };
};
users = lib.mkOption {
type = lib.types.attrsOf userType;
default = { };
};
sourceControl = lib.mkOption {
type = hostSourceControlType;
default = { };
};
};
}
);
mkUserEmailAssertions =
userName: user:
[
{
assertion = hasSinglePrimaryEmail user;
message = "User `${userName}` must define exactly one primary email entry.";
}
]
++ (map
(scope: {
assertion = hasAtMostOneScopedEmail scope user;
message = "User `${userName}` may define at most one `${scope}` scoped email entry.";
})
[
"personal"
"work"
]
)
++ map (scope: {
assertion = hasRequiredScopedEmail scope user;
message = "User `${userName}` must define exactly one `${scope}` scoped email entry.";
}) (requiredSourceControlScopes user);
in
{
flake.modules.nixos.meta =
{ config, ... }:
{
options.meta.host = lib.mkOption {
type = hostType;
};
config.assertions = lib.flatten (lib.mapAttrsToList mkUserEmailAssertions config.meta.host.users);
};
flake.modules.homeManager.meta =
{ config, ... }:
{
options.meta = {
host = lib.mkOption {
type = lib.types.nullOr hostType;
default = null;
};
user = lib.mkOption {
type = lib.types.nullOr userType;
default = null;
};
};
config.assertions = lib.optionals (config.meta.user != null) (
mkUserEmailAssertions config.meta.user.name config.meta.user
);
};
}
+3 -3
View File
@@ -1,6 +1,6 @@
{ config, ... }:
let
repoTheme = config.meta.lib.repo.theme.kanagawa;
repoTheme = config.repo.theme.kanagawa;
in
{
flake.modules.homeManager.neovim =
@@ -113,8 +113,8 @@ in
# Hostname/ConfigDir needed for nixd
nixdExtras = {
nixpkgs = "import ${pkgs.path} {}";
nixos_options = ''(builtins.getFlake "path://${config.meta.user.nixosConfigurationPath}").nixosConfigurations.${config.meta.host.name}.options'';
home_manager_options = ''(builtins.getFlake "path://${config.meta.user.nixosConfigurationPath}").nixosConfigurations.${config.meta.host.name}.options.home-manager.users.type.getSubOptions []'';
nixos_options = ''(builtins.getFlake "path://${config.meta.user.account.nixosConfigurationPath}").nixosConfigurations.${config.meta.machine.name}.options'';
home_manager_options = ''(builtins.getFlake "path://${config.meta.user.account.nixosConfigurationPath}").nixosConfigurations.${config.meta.machine.name}.options.home-manager.users.type.getSubOptions []'';
};
themeSetup = import ./_kanagawa-theme.nix {
+1 -1
View File
@@ -4,7 +4,7 @@
{
programs.nh = {
enable = true;
flake = config.meta.user.nixosConfigurationPath;
flake = config.meta.user.account.nixosConfigurationPath;
};
};
}
+28 -24
View File
@@ -4,8 +4,8 @@
...
}:
let
metaLib = config.meta.lib;
metaRepo = metaLib.repo;
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.nixos.niri =
@@ -31,11 +31,15 @@ in
...
}:
let
repoTheme = metaRepo.theme.kanagawa;
browserCommand = metaRepo.desktop.browser.command;
fileManagerPackage = metaLib.resolvePackagePath {
repoTheme = repo.theme.kanagawa;
browserCommand = repo.desktop.browser.command;
fileManagerPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = metaRepo.desktop.fileManager.packagePath;
path = repo.desktop.fileManager.packagePath;
};
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
outputs = lib.mapAttrs (
_: display:
@@ -51,19 +55,24 @@ in
// lib.optionalAttrs (display.scale != null) {
inherit (display) scale;
}
// lib.optionalAttrs (display.mode != null) {
inherit (display) mode;
// lib.optionalAttrs (display.width != null && display.height != null && display.refresh != null) {
mode = {
inherit (display)
width
height
refresh
;
};
}
) config.meta.host.displays;
inputProfiles = metaLib.mkInputProfiles config.meta.host.input;
terminal = metaLib.resolveRepoTerminal {
inherit pkgs;
};
) config.meta.machine.displays;
in
{
assertions = metaLib.mkTerminalAssertions {
inherit terminal;
};
assertions = [
{
assertion = fileManagerPackage != null;
message = "Unknown file manager package `${lib.showAttrPath repo.desktop.fileManager.packagePath}`.";
}
];
home.sessionVariables.NIXOS_OZONE_WL = "1";
@@ -138,27 +147,22 @@ in
input = {
focus-follows-mouse.enable = true;
mouse."accel-speed" = 0.4;
keyboard = {
repeat-delay = 300;
repeat-rate = 50;
xkb.options = "caps:escape";
};
}
// lib.optionalAttrs (inputProfiles.niri.mouse != { }) {
mouse = inputProfiles.niri.mouse;
}
// lib.optionalAttrs (inputProfiles.niri.touchpad != { }) {
touchpad = inputProfiles.niri.touchpad;
};
binds =
if terminal.hasPackage then
if terminalPackage != null then
import ./_bindings.nix {
inherit
browserCommand
lib
;
terminalPackage = terminal.package;
terminalPackage = terminalPackage;
}
else
{ };
+47 -52
View File
@@ -4,8 +4,9 @@
...
}:
let
homeModules = config.flake.modules.homeManager;
metaLib = config.meta.lib;
repo = config.repo;
repoHelpers = repo.helpers;
mkNoctaliaSettings =
{
lib,
@@ -17,6 +18,25 @@ let
terminalPackage
;
};
mkBaseSettings =
{
lib,
pkgs,
}:
let
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
in
if terminalPackage == null then
{ }
else
mkNoctaliaSettings {
inherit lib terminalPackage;
};
mkPortableSettings =
baseSettings:
lib.recursiveUpdate baseSettings {
@@ -40,55 +60,20 @@ let
};
in
{
flake.modules.homeManager.noctalia-base =
{
config,
lib,
pkgs,
...
}:
let
terminal = metaLib.resolveRepoTerminal {
inherit pkgs;
};
baseSettings =
if terminal.hasPackage then
mkNoctaliaSettings {
inherit lib;
terminalPackage = terminal.package;
}
else
{ };
in
{
options.meta.lib.noctaliaBaseSettings = lib.mkOption {
type = lib.types.attrs;
internal = true;
readOnly = true;
};
config = {
meta.lib.noctaliaBaseSettings = baseSettings;
assertions = metaLib.mkTerminalAssertions {
inherit terminal;
};
};
};
flake.modules.homeManager.noctalia =
{
config,
inputs,
lib,
pkgs,
...
}:
let
baseSettings = mkBaseSettings {
inherit lib pkgs;
};
in
{
imports = [
homeModules.noctalia-base
inputs.noctalia.homeModules.default
];
imports = [ inputs.noctalia.homeModules.default ];
programs.noctalia-shell = {
enable = true;
@@ -98,23 +83,33 @@ in
}
);
settings = config.meta.lib.noctaliaBaseSettings;
settings = baseSettings;
};
};
flake.modules.homeManager.noctalia-portable =
{
config,
inputs,
lib,
pkgs,
...
}:
let
baseSettings = mkBaseSettings {
inherit lib pkgs;
};
in
{
imports = [ homeModules.noctalia ];
programs.noctalia-shell.settings = lib.mkForce (
if config.meta.lib.noctaliaBaseSettings == { } then
{ }
else
mkPortableSettings config.meta.lib.noctaliaBaseSettings
);
imports = [ inputs.noctalia.homeModules.default ];
programs.noctalia-shell = {
enable = true;
package = lib.mkForce (
inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
calendarSupport = true;
}
);
settings = if baseSettings == { } then { } else mkPortableSettings baseSettings;
};
};
}
+2 -2
View File
@@ -3,7 +3,7 @@
...
}:
let
metaRepo = config.meta.lib.repo;
repo = config.repo;
in
{
flake.modules.homeManager.pim =
@@ -51,7 +51,7 @@ in
};
remote = {
url = metaRepo.services.radicale.url;
url = repo.services.radicale.url;
type = "caldav";
userName = config.home.username;
passwordCommand = [
+4 -4
View File
@@ -1,8 +1,8 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
metaLib = config.meta.lib;
service = metaRepo.services.actual;
repo = config.repo;
repoHelpers = repo.helpers;
service = repo.services.actual;
in
{
flake.modules.nixos.actual =
@@ -19,7 +19,7 @@ in
};
}
(metaLib.mkCaddyReverseProxy {
(repoHelpers.mkCaddyReverseProxy {
inherit (service)
domain
port
+2 -2
View File
@@ -1,12 +1,12 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
repo = config.repo;
in
{
flake.modules.nixos.caddy = {
services.caddy = {
enable = true;
email = metaRepo.contact.email;
email = repo.contact.email;
openFirewall = true;
};
};
+4 -4
View File
@@ -1,8 +1,8 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
metaLib = config.meta.lib;
service = metaRepo.services.gitea;
repo = config.repo;
repoHelpers = repo.helpers;
service = repo.services.gitea;
in
{
flake.modules.nixos.gitea =
@@ -32,7 +32,7 @@ in
services.openssh.settings.AllowUsers = [ "gitea" ];
}
(metaLib.mkCaddyReverseProxy {
(repoHelpers.mkCaddyReverseProxy {
inherit (service)
domain
port
+1 -1
View File
@@ -20,7 +20,7 @@
settings = {
PermitRootLogin = "no";
PasswordAuthentication = false;
AllowUsers = builtins.attrNames config.meta.host.users;
AllowUsers = builtins.attrNames config.meta.machine.users;
};
};
};
+4 -4
View File
@@ -1,8 +1,8 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
metaLib = config.meta.lib;
service = metaRepo.services.radicale;
repo = config.repo;
repoHelpers = repo.helpers;
service = repo.services.radicale;
in
{
flake.modules.nixos.radicale =
@@ -25,7 +25,7 @@ in
};
}
(metaLib.mkCaddyReverseProxy {
(repoHelpers.mkCaddyReverseProxy {
inherit (service)
domain
port
+4 -4
View File
@@ -1,8 +1,8 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
metaLib = config.meta.lib;
service = metaRepo.services.vaultwarden;
repo = config.repo;
repoHelpers = repo.helpers;
service = repo.services.vaultwarden;
in
{
flake.modules.nixos.vaultwarden =
@@ -21,7 +21,7 @@ in
};
}
(metaLib.mkCaddyReverseProxy {
(repoHelpers.mkCaddyReverseProxy {
inherit (service)
domain
port
+17
View File
@@ -0,0 +1,17 @@
{ lib, ... }:
{
flake.modules.nixos.sops-password =
{ config, ... }:
{
sops.secrets = lib.mapAttrs' (
userName: _:
lib.nameValuePair "hashed-password-${userName}" {
neededForUsers = true;
}
) config.meta.machine.users;
users.users = lib.mapAttrs (userName: _: {
hashedPasswordFile = config.sops.secrets."hashed-password-${userName}".path;
}) config.meta.machine.users;
};
}
+21 -12
View File
@@ -10,22 +10,19 @@ in
...
}:
let
host = config.meta.host;
machine = config.meta.machine;
user = config.meta.user;
sourceControl = user.sourceControl;
sourceControlScopes = sourceControl.scopes;
hostSourceControlUsers = host.sourceControl.users;
hostUserSourceControl = hostSourceControlUsers.${user.name} or { };
account = user.account;
sourceControl = account.sourceControl;
scopeConfig = scope: hostUserSourceControl.${scope} or null;
scopeIdentity = scope: sourceControlScopes.${scope} or null;
scopeConfig = scope: user.sourceControl.${scope} or null;
emailForScope =
scope:
let
identity = scopeIdentity scope;
scopedEmails = lib.filter (email: email.scope == scope) (builtins.attrValues account.emails);
in
if identity == null then null else identity.email;
if builtins.length scopedEmails == 1 then (builtins.head scopedEmails).address else null;
scopeHasSigningKey =
scope:
@@ -51,7 +48,12 @@ in
in
if keyConfig == null then null else keyConfig.publicKey;
scopesInUse = builtins.attrNames sourceControlScopes;
scopesInUse = lib.unique [
"personal"
sourceControl.projectScope
];
missingEmailScopes = builtins.filter (scope: emailForScope scope == null) scopesInUse;
allowedSignersLines = map (scope: "${emailForScope scope} ${publicKeyForScope scope}") (
builtins.filter (scope: emailForScope scope != null && scopeHasSigningKey scope) scopesInUse
@@ -62,7 +64,7 @@ in
lib.recursiveUpdate
{
user = {
name = user.realName;
name = account.realName;
email = emailForScope scope;
};
}
@@ -75,7 +77,7 @@ in
gitRoots = [
{
root = user.nixosConfigurationPath;
root = account.nixosConfigurationPath;
scope = "personal";
}
{
@@ -87,6 +89,13 @@ in
{
imports = [ homeModules.git ];
assertions = [
{
assertion = missingEmailScopes == [ ];
message = "Missing source-control email scope for `${account.name}`: ${lib.concatStringsSep ", " missingEmailScopes}.";
}
];
xdg.configFile."git/allowed_signers".text = lib.concatStringsSep "\n" (
allowedSignersLines ++ [ "" ]
);
+25 -13
View File
@@ -1,19 +1,31 @@
{
config,
lib,
...
}:
let
syncthingMesh = lib.listToAttrs (
lib.concatMap (
machine:
lib.mapAttrsToList (
userName: user:
let
name = "${userName}@${machine.name}";
in
{
inherit name;
value = {
inherit name;
id = user.syncthingId;
};
}
) (lib.filterAttrs (_: user: user.syncthingId != null) machine.users)
) (builtins.attrValues config.repo.machines)
);
in
{
flake.modules.homeManager.syncthing =
{ ... }:
let
syncthingMesh = {
"kiri@orion" = {
name = "kiri@orion";
id = "NNRNQKZ-OWPHSVA-B6KKBHE-SDYLSTV-7SVHGPR-NEWLKPL-4MWNJG4-G5FHUAI";
};
"kiri@polaris" = {
name = "kiri@polaris";
id = "6HBAKXB-DB3B4H2-BODCAXF-KD23H5W-6X5LGLC-ZJHZHLG-7U7YMGO-BB6IXQ3";
};
};
in
{
services.syncthing = {
enable = true;
+24 -10
View File
@@ -1,32 +1,46 @@
{ config, ... }:
let
metaLib = config.meta.lib;
metaRepo = metaLib.repo;
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.homeManager.terminal =
{
config,
lib,
pkgs,
...
}:
let
repoTheme = metaRepo.theme.kanagawa;
repoTheme = repo.theme.kanagawa;
palette = repoTheme.palette;
terminal = metaLib.resolveRepoTerminal {
terminalPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repo.desktop.terminal.packagePath;
};
terminalDesktopId = repo.desktop.terminal.desktopId;
in
{
assertions = metaLib.mkTerminalAssertions {
inherit terminal;
requireDesktopEntry = true;
};
assertions = [
{
assertion = terminalPackage != null;
message = "Unknown terminal package `${lib.showAttrPath repo.desktop.terminal.packagePath}`.";
}
{
assertion = repo.desktop.terminal.command == "kitty";
message = "The terminal feature currently only supports kitty.";
}
{
assertion =
terminalPackage == null
|| terminalDesktopId == null
|| builtins.pathExists "${terminalPackage}/share/applications/${terminalDesktopId}";
message = "Terminal package `${lib.showAttrPath repo.desktop.terminal.packagePath}` must provide `${terminalDesktopId}`.";
}
];
xdg.terminal-exec = {
enable = true;
settings.default = lib.optional (terminal.desktopId != null) terminal.desktopId;
settings.default = lib.optional (terminalDesktopId != null) terminalDesktopId;
};
programs.kitty = {
+6 -6
View File
@@ -3,8 +3,8 @@
...
}:
let
metaLib = config.meta.lib;
metaRepo = metaLib.repo;
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.nixos.theme =
@@ -13,9 +13,9 @@ in
...
}:
let
repoTheme = metaRepo.theme;
repoTheme = repo.theme;
cursorTheme = repoTheme.cursor // {
package = metaLib.resolvePackagePath {
package = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repoTheme.cursor.packagePath;
};
@@ -35,9 +35,9 @@ in
flake.modules.homeManager.theme =
{ config, pkgs, ... }:
let
repoTheme = metaRepo.theme;
repoTheme = repo.theme;
cursorTheme = repoTheme.cursor // {
package = metaLib.resolvePackagePath {
package = repoHelpers.resolvePackagePath {
inherit pkgs;
path = repoTheme.cursor.packagePath;
};
+2 -2
View File
@@ -1,6 +1,6 @@
{ config, ... }:
let
metaRepo = config.meta.lib.repo;
repo = config.repo;
in
{
flake.modules.homeManager.vicinae =
@@ -10,7 +10,7 @@ in
...
}:
let
repoTheme = metaRepo.theme.kanagawa;
repoTheme = repo.theme.kanagawa;
palette = repoTheme.palette;
in
{
+3 -4
View File
@@ -4,18 +4,17 @@ let
homeModules = config.flake.modules.homeManager;
in
{
flake.modules.nixos.workstation = {
flake.modules.nixos.workstation-base = {
imports = [
nixosModules.audio
nixosModules.bluetooth
nixosModules.flatpak
nixosModules.fonts
nixosModules.host-base
nixosModules.input
nixosModules.networking
nixosModules.niri
nixosModules.plymouth
nixosModules.printing
nixosModules.sops-password
nixosModules.sddm
nixosModules.sops-admin-key-file
nixosModules.standard-boot
@@ -30,7 +29,7 @@ in
environment.localBinInPath = true;
};
flake.modules.homeManager.workstation = {
flake.modules.homeManager.workstation-base = {
imports = [
homeModules.ai
homeModules.bitwarden
+6 -6
View File
@@ -1,19 +1,19 @@
{ config, ... }:
let
metaLib = config.meta.lib;
metaRepo = metaLib.repo;
repo = config.repo;
repoHelpers = repo.helpers;
in
{
flake.modules.homeManager.xdg =
{ config, pkgs, ... }:
let
browserPackage = metaLib.resolvePackagePath {
browserPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = metaRepo.desktop.browser.packagePath;
path = repo.desktop.browser.packagePath;
};
fileManagerPackage = metaLib.resolvePackagePath {
fileManagerPackage = repoHelpers.resolvePackagePath {
inherit pkgs;
path = metaRepo.desktop.fileManager.packagePath;
path = repo.desktop.fileManager.packagePath;
};
homeDir = config.home.homeDirectory;
localDir = "${homeDir}/.local";
+4 -10
View File
@@ -3,12 +3,6 @@
config,
...
}:
let
hostNames = builtins.attrNames (
inputs.nixpkgs.lib.filterAttrs (_: type: type == "directory") (builtins.readDir ./hosts)
);
nixosModules = config.flake.modules.nixos;
in
{
imports = [
inputs.flake-parts.flakeModules.modules
@@ -17,13 +11,13 @@ in
systems = [ "x86_64-linux" ];
flake.nixosConfigurations = inputs.nixpkgs.lib.genAttrs hostNames (
name:
flake.nixosConfigurations = builtins.mapAttrs (
_: machine:
inputs.nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ nixosModules.${name} ];
modules = [ (machine.buildFunction machine) ];
}
);
) config.repo.machines;
perSystem =
{ pkgs, ... }:
+29 -52
View File
@@ -5,27 +5,38 @@
}:
let
nixosModules = config.flake.modules.nixos;
homeModules = config.flake.modules.homeManager;
metaLib = config.meta.lib;
accounts = config.repo.accounts;
in
{
flake.modules.nixos.orion-admin =
repo.machines.orion = {
buildFunction = config.repo.helpers.mkHost;
module = nixosModules.orion;
users.kiri = {
account = accounts.kiri;
syncthingId = "NNRNQKZ-OWPHSVA-B6KKBHE-SDYLSTV-7SVHGPR-NEWLKPL-4MWNJG4-G5FHUAI";
};
stateVersion = "24.05";
hmStateVersion = "24.05";
};
flake.modules.nixos.orion =
{ ... }:
{
config,
lib,
pkgs,
...
}:
let
terminal = metaLib.resolveRepoTerminal {
inherit pkgs;
};
in
{
assertions = metaLib.mkTerminalAssertions {
inherit terminal;
requireTerminfo = true;
};
imports = [
nixosModules.sops-host-ssh-key
nixosModules.openssh
nixosModules.caddy
nixosModules.server-firewall
nixosModules.ssh-agent-auth
nixosModules.vaultwarden
nixosModules.radicale
nixosModules.actual
nixosModules.gitea
./_hardware.nix
./_disk.nix
];
users.users.kiri = {
linger = true;
@@ -33,39 +44,5 @@ in
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAU2LydkXRTtNFY7oyX8JQURwXLVhB71DeK8XzrXeFX1 openpgp:0xA490D93A"
];
};
environment.systemPackages = [
]
++ lib.optional terminal.hasTerminfo (lib.getOutput "terminfo" terminal.package);
};
flake.modules.nixos.orion = metaLib.mkHost {
name = "orion";
users = {
kiri = {
account = metaLib.accounts.kiri;
homeImports = [
homeModules.shell
homeModules.git
homeModules.syncthing
];
};
};
imports = [
nixosModules.host-base
nixosModules.sops-host-ssh-key
nixosModules.openssh
nixosModules.caddy
nixosModules.server-firewall
nixosModules.ssh-agent-auth
nixosModules.orion-admin
nixosModules.vaultwarden
nixosModules.radicale
nixosModules.actual
nixosModules.gitea
./_hardware.nix
./_disk.nix
];
};
}
+37 -40
View File
@@ -6,18 +6,24 @@
let
nixosModules = config.flake.modules.nixos;
homeModules = config.flake.modules.homeManager;
metaLib = config.meta.lib;
workstationHomeImports = [ homeModules.workstation ];
kiriHomeImports = workstationHomeImports ++ [
homeModules.syncthing
homeModules.qbittorrent-client
homeModules.noctalia
];
ergonHomeImports = workstationHomeImports ++ [ homeModules.noctalia ];
accounts = config.repo.accounts;
in
{
flake.modules.nixos.polaris = metaLib.mkHost {
name = "polaris";
repo.machines.polaris = {
buildFunction = config.repo.helpers.mkWorkstationHost;
module = nixosModules.polaris;
users = {
kiri = {
account = accounts.kiri;
syncthingId = "6HBAKXB-DB3B4H2-BODCAXF-KD23H5W-6X5LGLC-ZJHZHLG-7U7YMGO-BB6IXQ3";
};
ergon.account = accounts.ergon;
};
stateVersion = "24.05";
hmStateVersion = "24.05";
displays = {
"LG Electronics LG ULTRAGEAR 103NTYT8R290" = {
@@ -31,35 +37,26 @@ in
y = 0;
};
};
input = {
mouse.accelSpeed = 0.4;
};
users = {
kiri = {
account = metaLib.accounts.kiri;
needsPassword = true;
homeImports = kiriHomeImports;
};
ergon = {
account = metaLib.accounts.ergon;
needsPassword = true;
homeImports = ergonHomeImports;
};
};
imports = [
nixosModules.workstation
nixosModules.steam
./_hardware.nix
]
++ (with inputs.nixos-hardware.nixosModules; [
common-pc
common-pc-ssd
common-cpu-amd
common-gpu-amd
]);
};
flake.modules.nixos.polaris =
{ ... }:
{
imports = [
nixosModules.qbittorrent-client
nixosModules.steam
./_hardware.nix
]
++ (with inputs.nixos-hardware.nixosModules; [
common-pc
common-pc-ssd
common-cpu-amd
common-gpu-amd
]);
home-manager.users = {
kiri.imports = [ homeModules.noctalia ];
ergon.imports = [ homeModules.noctalia ];
};
};
}
+56 -72
View File
@@ -6,87 +6,71 @@
let
nixosModules = config.flake.modules.nixos;
homeModules = config.flake.modules.homeManager;
metaLib = config.meta.lib;
workstationHomeImports = [ homeModules.workstation ];
portableNoctalia = homeModules.noctalia-portable;
kiriHomeImports = workstationHomeImports ++ [
homeModules.syncthing
homeModules.qbittorrent-client
portableNoctalia
];
ergonHomeImports = workstationHomeImports ++ [
portableNoctalia
(
{ pkgs, ... }:
{
home.packages = [
pkgs.usql
];
programs.git.ignores = [
# Devenv stuff
"devenv.*"
".devenv*"
".direnv"
"pre-commit-config.yaml"
".envrc"
];
}
)
];
accounts = config.repo.accounts;
in
{
flake.modules.nixos.zenith = metaLib.mkHost {
name = "zenith";
repo.machines.zenith = {
buildFunction = config.repo.helpers.mkWorkstationHost;
module = nixosModules.zenith;
displays = {
"California Institute of Technology 0x1410 Unknown" = {
primary = true;
x = 0;
y = 0;
scale = 1.5;
mode = {
width = 3072;
height = 1920;
refresh = 120.002;
users = {
kiri.account = accounts.kiri;
ergon = {
account = accounts.ergon;
sourceControl = {
personal.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPdR3KP2U84i7f7MlRqcML/3YyMw8JL3hdm637SkMUwO ergon@zenith#personal";
work.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIHJz5uHKm0/TiMNh/cmzrODHNZ8NgEEZe+47XnJwQGk ergon@zenith#work";
};
};
};
input = {
mouse.accelSpeed = 0.4;
};
sourceControl.users = {
ergon = {
personal.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPdR3KP2U84i7f7MlRqcML/3YyMw8JL3hdm637SkMUwO ergon@zenith#personal";
work.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIHJz5uHKm0/TiMNh/cmzrODHNZ8NgEEZe+47XnJwQGk ergon@zenith#work";
displays = {
"California Institute of Technology 0x1410 Unknown" = {
primary = true;
scale = 1.5;
width = 3072;
height = 1920;
refresh = 120.002;
};
};
users = {
kiri = {
account = metaLib.accounts.kiri;
needsPassword = true;
homeImports = kiriHomeImports;
};
ergon = {
account = metaLib.accounts.ergon;
needsPassword = true;
homeImports = ergonHomeImports;
};
};
imports = [
nixosModules.workstation
nixosModules.laptop-power
{
hardware.enableRedistributableFirmware = true;
services.fwupd.enable = true;
}
./_hardware.nix
inputs.nixos-hardware.nixosModules.lenovo-yoga-7-14ARH7-amdgpu
];
stateVersion = "24.05";
hmStateVersion = "24.05";
};
flake.modules.nixos.zenith =
{ ... }:
{
imports = [
nixosModules.qbittorrent-client
nixosModules.laptop-power
{
hardware.enableRedistributableFirmware = true;
services.fwupd.enable = true;
}
./_hardware.nix
inputs.nixos-hardware.nixosModules.lenovo-yoga-7-14ARH7-amdgpu
];
home-manager.users = {
kiri.imports = [ homeModules.noctalia-portable ];
ergon.imports = [
homeModules.noctalia-portable
(
{ pkgs, ... }:
{
home.packages = [ pkgs.usql ];
programs.git.ignores = [
"devenv.*"
".devenv*"
".direnv"
"pre-commit-config.yaml"
".envrc"
];
}
)
];
};
};
}
-374
View File
@@ -1,374 +0,0 @@
{
config,
lib,
...
}:
let
normalizeHostUser =
spec:
{
homeImports = [ ];
needsPassword = false;
stateVersion = null;
}
// spec;
mkHost =
{
name,
displays ? { },
input ? { },
sourceControl ? { },
users ? { },
imports ? [ ],
stateVersion ? "24.05",
}:
{
config,
pkgs,
...
}:
let
hostUserSpecs = lib.mapAttrs (_: spec: normalizeHostUser spec) users;
hostUsers = lib.mapAttrs (_: spec: spec.account) hostUserSpecs;
passwordUserSpecs = lib.filterAttrs (_: spec: spec.needsPassword) hostUserSpecs;
in
{
meta.host = {
inherit
displays
input
name
sourceControl
;
users = hostUsers;
};
inherit imports;
networking.hostName = name;
system.stateVersion = stateVersion;
programs.zsh.enable = true;
sops.secrets = lib.mapAttrs' (
userName: _:
lib.nameValuePair "hashed-password-${userName}" {
neededForUsers = true;
}
) passwordUserSpecs;
users.users = lib.mapAttrs (
userName: spec:
{
name = userName;
home = spec.account.homeDirectory;
isNormalUser = true;
shell = pkgs.zsh;
extraGroups = [
"wheel"
"networkmanager"
];
}
// lib.optionalAttrs spec.needsPassword {
hashedPasswordFile = config.sops.secrets."hashed-password-${userName}".path;
}
) hostUserSpecs;
home-manager.users = lib.mapAttrs (_: spec: {
imports = spec.homeImports;
meta = {
host = config.meta.host;
user = spec.account;
};
home = {
username = spec.account.name;
homeDirectory = spec.account.homeDirectory;
stateVersion = if spec.stateVersion == null then stateVersion else spec.stateVersion;
};
}) hostUserSpecs;
};
mkCaddyReverseProxy =
{
domain,
port,
extraHeaders ? [ ],
extraConfigText ? "",
}:
let
headerLines = map (header: " header_up ${header.name} ${header.value}") extraHeaders;
extraConfigLines = map (line: " ${line}") (
lib.filter (line: line != "") (lib.splitString "\n" extraConfigText)
);
bodyLines = headerLines ++ extraConfigLines;
body = lib.concatStringsSep "\n" bodyLines;
in
{
services.caddy.virtualHosts.${domain}.extraConfig =
if body == "" then
"reverse_proxy :${toString port}"
else
''
reverse_proxy :${toString port} {
${body}
}
'';
};
resolvePackagePath =
{
pkgs,
path,
}:
lib.attrByPath path null pkgs;
resolveRepoTerminal =
{
pkgs,
}:
let
terminal = config.meta.lib.repo.desktop.terminal;
package = resolvePackagePath {
inherit pkgs;
path = terminal.packagePath;
};
in
{
inherit
package
;
inherit (terminal)
command
desktopId
packagePath
;
hasPackage = package != null;
hasDesktopEntry =
package != null && builtins.pathExists "${package}/share/applications/${terminal.desktopId}";
hasTerminfo = package != null && lib.elem "terminfo" package.outputs;
};
mkTerminalAssertions =
{
terminal,
requireDesktopEntry ? false,
requireTerminfo ? false,
}:
lib.flatten [
[
{
assertion = terminal.hasPackage;
message = "Unknown terminal package `${lib.showAttrPath terminal.packagePath}` in `meta.lib.repo.desktop.terminal`.";
}
{
assertion = terminal.command == "kitty";
message = "The repo terminal is currently expected to be kitty.";
}
]
(lib.optional requireDesktopEntry {
assertion = terminal.hasDesktopEntry;
message = "Terminal package `${lib.showAttrPath terminal.packagePath}` must provide `${terminal.desktopId}`.";
})
(lib.optional requireTerminfo {
assertion = terminal.hasTerminfo;
message = "Terminal package `${lib.showAttrPath terminal.packagePath}` must provide a `terminfo` output.";
})
];
mapConfiguredAttrs =
{
settings,
schema,
}:
lib.filterAttrs (_: value: value != null) (
lib.mapAttrs (
_: spec:
let
value = lib.getAttrFromPath spec.path settings;
in
if value == null then
null
else if spec ? values then
spec.values.${value}
else if spec ? transform then
spec.transform value
else
value
) schema
);
mkInputProfiles =
input:
let
scrollMethodValues = {
edge = {
libinput = "edge";
niri = "edge";
};
"no-scroll" = {
libinput = "none";
niri = "no-scroll";
};
"on-button-down" = {
libinput = "button";
niri = "on-button-down";
};
"two-finger" = {
libinput = "twofinger";
niri = "two-finger";
};
};
mouse = input.mouse;
touchpad = input.touchpad;
libinputMouse = mapConfiguredAttrs {
settings = mouse;
schema = {
accelProfile.path = [ "accelProfile" ];
accelSpeed = {
path = [ "accelSpeed" ];
transform = toString;
};
leftHanded.path = [ "leftHanded" ];
middleEmulation.path = [ "middleEmulation" ];
naturalScrolling.path = [ "naturalScrolling" ];
scrollMethod = {
path = [ "scrollMethod" ];
values = lib.mapAttrs (_: value: value.libinput) scrollMethodValues;
};
};
};
libinputTouchpad = mapConfiguredAttrs {
settings = touchpad;
schema = {
accelProfile.path = [ "accelProfile" ];
accelSpeed = {
path = [ "accelSpeed" ];
transform = toString;
};
clickMethod = {
path = [ "clickMethod" ];
values = {
"button-areas" = "buttonareas";
clickfinger = "clickfinger";
};
};
disableWhileTyping.path = [ "disableWhileTyping" ];
leftHanded.path = [ "leftHanded" ];
middleEmulation.path = [ "middleEmulation" ];
naturalScrolling.path = [ "naturalScrolling" ];
scrollMethod = {
path = [ "scrollMethod" ];
values = lib.mapAttrs (_: value: value.libinput) scrollMethodValues;
};
tapping.path = [ "tapping" ];
};
};
niriMouse = mapConfiguredAttrs {
settings = mouse;
schema = {
"accel-profile".path = [ "accelProfile" ];
"accel-speed".path = [ "accelSpeed" ];
"left-handed".path = [ "leftHanded" ];
"middle-emulation".path = [ "middleEmulation" ];
"natural-scroll".path = [ "naturalScrolling" ];
"scroll-method" = {
path = [ "scrollMethod" ];
values = lib.mapAttrs (_: value: value.niri) scrollMethodValues;
};
};
};
niriTouchpad = mapConfiguredAttrs {
settings = touchpad;
schema = {
"accel-profile".path = [ "accelProfile" ];
"accel-speed".path = [ "accelSpeed" ];
"click-method".path = [ "clickMethod" ];
dwt.path = [ "disableWhileTyping" ];
"left-handed".path = [ "leftHanded" ];
"middle-emulation".path = [ "middleEmulation" ];
"natural-scroll".path = [ "naturalScrolling" ];
"scroll-method" = {
path = [ "scrollMethod" ];
values = lib.mapAttrs (_: value: value.niri) scrollMethodValues;
};
tap.path = [ "tapping" ];
};
};
in
{
hasPointerConfig = libinputMouse != { } || libinputTouchpad != { };
libinput = {
mouse = libinputMouse;
touchpad = libinputTouchpad;
};
niri = {
mouse = niriMouse;
touchpad = niriTouchpad;
};
};
in
{
options.meta.lib.mkHost = lib.mkOption {
type = lib.types.raw;
description = "Internal host constructor shared between flake-parts modules.";
internal = true;
readOnly = true;
};
options.meta.lib.mkCaddyReverseProxy = lib.mkOption {
type = lib.types.raw;
description = "Internal Caddy reverse proxy helper shared between flake-parts modules.";
internal = true;
readOnly = true;
};
options.meta.lib.resolvePackagePath = lib.mkOption {
type = lib.types.raw;
description = "Internal helper to resolve package attr paths against the local pkgs set.";
internal = true;
readOnly = true;
};
options.meta.lib.resolveRepoTerminal = lib.mkOption {
type = lib.types.raw;
description = "Internal helper to resolve and validate the repo-standard terminal.";
internal = true;
readOnly = true;
};
options.meta.lib.mkTerminalAssertions = lib.mkOption {
type = lib.types.raw;
description = "Internal helper for terminal-related assertions shared across modules.";
internal = true;
readOnly = true;
};
options.meta.lib.mkInputProfiles = lib.mkOption {
type = lib.types.raw;
description = "Internal helper to normalize host input metadata for libinput and Niri.";
internal = true;
readOnly = true;
};
config.meta.lib = {
inherit
mkInputProfiles
mkCaddyReverseProxy
mkTerminalAssertions
mkHost
resolvePackagePath
resolveRepoTerminal
;
};
}
+113
View File
@@ -0,0 +1,113 @@
{ lib, config, ... }:
let
nixosModules = config.flake.modules.nixos;
resolvePackagePath =
{
pkgs,
path,
}:
lib.attrByPath path null pkgs;
mkCaddyReverseProxy =
{
domain,
port,
extraHeaders ? [ ],
extraConfigText ? "",
}:
let
headerLines = map (header: " header_up ${header.name} ${header.value}") extraHeaders;
extraConfigLines = map (line: " ${line}") (
lib.filter (line: line != "") (lib.splitString "\n" extraConfigText)
);
bodyLines = headerLines ++ extraConfigLines;
body = lib.concatStringsSep "\n" bodyLines;
in
{
services.caddy.virtualHosts.${domain}.extraConfig =
if body == "" then
"reverse_proxy :${toString port}"
else
''
reverse_proxy :${toString port} {
${body}
}
'';
};
mkHost =
machine:
{ pkgs, ... }:
{
imports = [
nixosModules.host-base
machine.module
];
meta.machine = machine;
networking.hostName = machine.name;
system.stateVersion = machine.stateVersion;
programs.zsh.enable = true;
users.users = lib.mapAttrs (_: user: {
isNormalUser = true;
home = user.account.homeDirectory;
extraGroups = [
"wheel"
"networkmanager"
];
shell = pkgs.zsh;
}) machine.users;
home-manager.users = lib.mapAttrs (name: user: {
imports = [ user.account.baseModule ];
meta = {
inherit machine user;
};
home = {
username = name;
homeDirectory = user.account.homeDirectory;
stateVersion = machine.hmStateVersion;
};
}) machine.users;
};
mkWorkstationHost =
machine:
{ ... }:
{
imports = [
(mkHost machine)
nixosModules.workstation-base
];
users.users = lib.mapAttrs (_: _: {
extraGroups = [ "networkmanager" ];
}) machine.users;
home-manager.users = lib.mapAttrs (_: user: {
imports = [ user.account.workstationModule ];
}) machine.users;
};
in
{
options.repo.helpers = lib.mkOption {
type = lib.types.attrsOf lib.types.raw;
internal = true;
readOnly = true;
};
config.repo.helpers = {
inherit
mkCaddyReverseProxy
mkHost
mkWorkstationHost
resolvePackagePath
;
};
}
+295
View File
@@ -0,0 +1,295 @@
{ lib, ... }:
let
sourceControlScopeType = lib.types.enum [
"personal"
"work"
];
emailProviderType = lib.types.enum [
"mxrouting"
"office365"
];
emailType = lib.types.submodule (
{ ... }:
{
options = {
address = lib.mkOption {
type = lib.types.str;
};
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
type = lib.mkOption {
type = emailProviderType;
};
scope = lib.mkOption {
type = lib.types.nullOr sourceControlScopeType;
default = null;
};
};
}
);
sourceControlAccountType = lib.types.submodule (
{ ... }:
{
options.projectScope = lib.mkOption {
type = sourceControlScopeType;
default = "personal";
};
}
);
accountType = lib.types.submodule (
{ name, config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
};
realName = lib.mkOption {
type = lib.types.str;
};
homeDirectory = lib.mkOption {
type = lib.types.str;
default = "/home/${config.name}";
};
nixosConfigurationPath = lib.mkOption {
type = lib.types.str;
default = "${config.homeDirectory}/.config/nixos";
};
emails = lib.mkOption {
type = lib.types.attrsOf emailType;
default = { };
};
baseModule = lib.mkOption {
type = lib.types.deferredModule;
default = { };
};
workstationModule = lib.mkOption {
type = lib.types.deferredModule;
default = { };
};
sourceControl = lib.mkOption {
type = sourceControlAccountType;
default = { };
};
primaryEmail = lib.mkOption {
type = lib.types.nullOr emailType;
description = "Derived primary email entry for this user.";
default =
let
emails = builtins.attrValues config.emails;
in
lib.findFirst (email: email.primary) null emails;
};
};
}
);
displayType = lib.types.submodule (
{ ... }:
{
options = {
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
x = lib.mkOption {
type = lib.types.int;
default = 0;
};
y = lib.mkOption {
type = lib.types.int;
default = 0;
};
scale = lib.mkOption {
type = lib.types.nullOr lib.types.float;
default = null;
};
width = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
};
height = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
};
refresh = lib.mkOption {
type = lib.types.nullOr lib.types.float;
default = null;
};
};
}
);
sourceControlMachineKeyType = lib.types.submodule (
{ ... }:
{
options = {
publicKey = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
privateKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
};
}
);
sourceControlMachineUserType = lib.types.submodule (
{ ... }:
{
options = {
personal = lib.mkOption {
type = lib.types.nullOr sourceControlMachineKeyType;
default = null;
};
work = lib.mkOption {
type = lib.types.nullOr sourceControlMachineKeyType;
default = null;
};
};
}
);
machineUserType = lib.types.submodule (
{ ... }:
{
options = {
account = lib.mkOption {
type = accountType;
};
sourceControl = lib.mkOption {
type = sourceControlMachineUserType;
default = { };
};
syncthingId = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
};
}
);
machineType = lib.types.submodule (
{ name, config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
};
module = lib.mkOption {
type = lib.types.deferredModule;
default = { };
};
buildFunction = lib.mkOption {
type = lib.types.functionTo lib.types.deferredModule;
};
stateVersion = lib.mkOption {
type = lib.types.str;
};
hmStateVersion = lib.mkOption {
type = lib.types.str;
default = config.stateVersion;
};
displays = lib.mkOption {
type = lib.types.attrsOf displayType;
default = { };
};
users = lib.mkOption {
type = lib.types.attrsOf machineUserType;
default = { };
};
};
}
);
in
{
options.repo = {
accounts = lib.mkOption {
type = lib.types.attrsOf accountType;
default = { };
};
machines = lib.mkOption {
type = lib.types.attrsOf machineType;
default = { };
};
contact = lib.mkOption {
type = lib.types.raw;
default = { };
};
desktop = lib.mkOption {
type = lib.types.raw;
default = { };
};
services = lib.mkOption {
type = lib.types.raw;
default = { };
};
theme = lib.mkOption {
type = lib.types.raw;
default = { };
};
};
config.flake.modules.nixos.meta =
{ ... }:
{
options.meta.machine = lib.mkOption {
type = machineType;
};
};
config.flake.modules.homeManager.meta =
{ ... }:
{
options.meta = {
machine = lib.mkOption {
type = machineType;
};
user = lib.mkOption {
type = machineUserType;
};
};
};
}