refactor: simplify module composition
This commit is contained in:
@@ -1,22 +1,26 @@
|
|||||||
{ ... }:
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
metaLib = config.meta.lib;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
flake.modules.homeManager.bitwarden =
|
flake.modules.homeManager.bitwarden =
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
user = config.meta.user;
|
user = config.meta.user;
|
||||||
primaryEmail = builtins.head (lib.filter (email: email.primary) (builtins.attrValues user.emails));
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
programs.rbw = {
|
programs.rbw = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
base_url = "https://vault.jelles.net";
|
base_url = metaLib.repo.services.vaultwarden.url;
|
||||||
email = primaryEmail.address;
|
email = user.primaryEmail.address;
|
||||||
pinentry = pkgs.pinentry-gnome3;
|
pinentry = pkgs.pinentry-gnome3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
let
|
|
||||||
homeModules = config.flake.modules.homeManager;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
flake.modules.homeManager.ergon-workstation = {
|
|
||||||
imports = [ homeModules.workstation-base ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
user = config.meta.user;
|
user = config.meta.user;
|
||||||
primaryEmail = builtins.head (lib.filter (email: email.primary) (builtins.attrValues user.emails));
|
|
||||||
usesScopedIdentity = user != null && user.sourceControl.profiles != { };
|
usesScopedIdentity = user != null && user.sourceControl.profiles != { };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
// lib.optionalAttrs (!usesScopedIdentity) {
|
// lib.optionalAttrs (!usesScopedIdentity) {
|
||||||
user = {
|
user = {
|
||||||
name = user.realName;
|
name = user.realName;
|
||||||
email = primaryEmail.address;
|
email = user.primaryEmail.address;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-55
@@ -1,3 +1,10 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
metaLib = config.meta.lib;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.input =
|
flake.modules.nixos.input =
|
||||||
{
|
{
|
||||||
@@ -6,64 +13,15 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
hostInput = config.meta.host.input;
|
inputProfiles = metaLib.mkInputProfiles config.meta.host.input;
|
||||||
|
|
||||||
hasAnyConfiguredValue = attrs: lib.any (value: value != null) (lib.attrValues attrs);
|
|
||||||
libinputScrollMethodMap = {
|
|
||||||
edge = "edge";
|
|
||||||
"no-scroll" = "none";
|
|
||||||
"on-button-down" = "button";
|
|
||||||
"two-finger" = "twofinger";
|
|
||||||
};
|
|
||||||
libinputClickMethodMap = {
|
|
||||||
"button-areas" = "buttonareas";
|
|
||||||
clickfinger = "clickfinger";
|
|
||||||
};
|
|
||||||
|
|
||||||
hasMouseConfig = hasAnyConfiguredValue hostInput.mouse;
|
|
||||||
hasTouchpadConfig = hasAnyConfiguredValue hostInput.touchpad;
|
|
||||||
hasPointerConfig = hasMouseConfig || hasTouchpadConfig;
|
|
||||||
|
|
||||||
mouseConfig = lib.filterAttrs (_: value: value != null) {
|
|
||||||
accelProfile = hostInput.mouse.accelProfile;
|
|
||||||
accelSpeed =
|
|
||||||
if hostInput.mouse.accelSpeed == null then null else toString hostInput.mouse.accelSpeed;
|
|
||||||
leftHanded = hostInput.mouse.leftHanded;
|
|
||||||
middleEmulation = hostInput.mouse.middleEmulation;
|
|
||||||
naturalScrolling = hostInput.mouse.naturalScrolling;
|
|
||||||
scrollMethod =
|
|
||||||
if hostInput.mouse.scrollMethod == null then
|
|
||||||
null
|
|
||||||
else
|
|
||||||
libinputScrollMethodMap.${hostInput.mouse.scrollMethod};
|
|
||||||
};
|
|
||||||
|
|
||||||
touchpadConfig = lib.filterAttrs (_: value: value != null) {
|
|
||||||
accelProfile = hostInput.touchpad.accelProfile;
|
|
||||||
accelSpeed =
|
|
||||||
if hostInput.touchpad.accelSpeed == null then null else toString hostInput.touchpad.accelSpeed;
|
|
||||||
clickMethod =
|
|
||||||
if hostInput.touchpad.clickMethod == null then
|
|
||||||
null
|
|
||||||
else
|
|
||||||
libinputClickMethodMap.${hostInput.touchpad.clickMethod};
|
|
||||||
disableWhileTyping = hostInput.touchpad.disableWhileTyping;
|
|
||||||
leftHanded = hostInput.touchpad.leftHanded;
|
|
||||||
middleEmulation = hostInput.touchpad.middleEmulation;
|
|
||||||
naturalScrolling = hostInput.touchpad.naturalScrolling;
|
|
||||||
scrollMethod =
|
|
||||||
if hostInput.touchpad.scrollMethod == null then
|
|
||||||
null
|
|
||||||
else
|
|
||||||
libinputScrollMethodMap.${hostInput.touchpad.scrollMethod};
|
|
||||||
tapping = hostInput.touchpad.tapping;
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.libinput = lib.mkIf hasPointerConfig {
|
services.libinput = lib.mkIf inputProfiles.hasPointerConfig {
|
||||||
enable = true;
|
enable = true;
|
||||||
mouse = mouseConfig;
|
inherit (inputProfiles.libinput)
|
||||||
touchpad = touchpadConfig;
|
mouse
|
||||||
|
touchpad
|
||||||
|
;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
let
|
|
||||||
homeModules = config.flake.modules.homeManager;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
flake.modules.homeManager.kiri-workstation = {
|
|
||||||
imports = [
|
|
||||||
homeModules.workstation-base
|
|
||||||
homeModules.syncthing
|
|
||||||
homeModules.qbittorrent-client
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+89
-74
@@ -3,10 +3,41 @@ let
|
|||||||
mkNullableOption =
|
mkNullableOption =
|
||||||
type:
|
type:
|
||||||
lib.mkOption {
|
lib.mkOption {
|
||||||
inherit type;
|
type = lib.types.nullOr type;
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hasSinglePrimaryEmail =
|
||||||
|
user: builtins.length (lib.filter (email: email.primary) (builtins.attrValues user.emails)) == 1;
|
||||||
|
|
||||||
|
primaryEmailFallback = {
|
||||||
|
address = "";
|
||||||
|
primary = false;
|
||||||
|
type = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
emailType = lib.types.submodule (
|
||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
@@ -79,10 +110,7 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
projectScope = lib.mkOption {
|
projectScope = lib.mkOption {
|
||||||
type = lib.types.enum [
|
type = sourceControlScopeType;
|
||||||
"personal"
|
|
||||||
"work"
|
|
||||||
];
|
|
||||||
default = "personal";
|
default = "personal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -91,6 +119,10 @@ let
|
|||||||
|
|
||||||
userType = lib.types.submodule (
|
userType = lib.types.submodule (
|
||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
|
let
|
||||||
|
primaryEmails = lib.filter (email: email.primary) (builtins.attrValues config.emails);
|
||||||
|
primaryEmail = if primaryEmails == [ ] then primaryEmailFallback else builtins.head primaryEmails;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
@@ -118,11 +150,19 @@ let
|
|||||||
type = lib.types.attrsOf emailType;
|
type = lib.types.attrsOf emailType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
primaryEmail = lib.mkOption {
|
||||||
|
type = emailType;
|
||||||
|
readOnly = true;
|
||||||
|
description = "Derived primary email entry for this user.";
|
||||||
|
};
|
||||||
|
|
||||||
sourceControl = lib.mkOption {
|
sourceControl = lib.mkOption {
|
||||||
type = sourceControlType;
|
type = sourceControlType;
|
||||||
default = { };
|
default = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
config.primaryEmail = primaryEmail;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -179,28 +219,12 @@ let
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
accelProfile = mkNullableOption (
|
accelProfile = mkNullableOption (pointerAccelProfileType);
|
||||||
lib.types.nullOr (
|
accelSpeed = mkNullableOption lib.types.float;
|
||||||
lib.types.enum [
|
leftHanded = mkNullableOption lib.types.bool;
|
||||||
"adaptive"
|
middleEmulation = mkNullableOption lib.types.bool;
|
||||||
"flat"
|
naturalScrolling = mkNullableOption lib.types.bool;
|
||||||
]
|
scrollMethod = mkNullableOption pointerScrollMethodType;
|
||||||
)
|
|
||||||
);
|
|
||||||
accelSpeed = mkNullableOption (lib.types.nullOr lib.types.float);
|
|
||||||
leftHanded = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
middleEmulation = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
naturalScrolling = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
scrollMethod = mkNullableOption (
|
|
||||||
lib.types.nullOr (
|
|
||||||
lib.types.enum [
|
|
||||||
"no-scroll"
|
|
||||||
"two-finger"
|
|
||||||
"edge"
|
|
||||||
"on-button-down"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -209,38 +233,15 @@ let
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
accelProfile = mkNullableOption (
|
accelProfile = mkNullableOption (pointerAccelProfileType);
|
||||||
lib.types.nullOr (
|
accelSpeed = mkNullableOption lib.types.float;
|
||||||
lib.types.enum [
|
clickMethod = mkNullableOption touchpadClickMethodType;
|
||||||
"adaptive"
|
disableWhileTyping = mkNullableOption lib.types.bool;
|
||||||
"flat"
|
leftHanded = mkNullableOption lib.types.bool;
|
||||||
]
|
middleEmulation = mkNullableOption lib.types.bool;
|
||||||
)
|
naturalScrolling = mkNullableOption lib.types.bool;
|
||||||
);
|
scrollMethod = mkNullableOption pointerScrollMethodType;
|
||||||
accelSpeed = mkNullableOption (lib.types.nullOr lib.types.float);
|
tapping = mkNullableOption lib.types.bool;
|
||||||
clickMethod = mkNullableOption (
|
|
||||||
lib.types.nullOr (
|
|
||||||
lib.types.enum [
|
|
||||||
"button-areas"
|
|
||||||
"clickfinger"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
disableWhileTyping = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
leftHanded = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
middleEmulation = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
naturalScrolling = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
scrollMethod = mkNullableOption (
|
|
||||||
lib.types.nullOr (
|
|
||||||
lib.types.enum [
|
|
||||||
"no-scroll"
|
|
||||||
"two-finger"
|
|
||||||
"edge"
|
|
||||||
"on-button-down"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
tapping = mkNullableOption (lib.types.nullOr lib.types.bool);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -294,23 +295,37 @@ let
|
|||||||
);
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.meta = {
|
flake.modules.nixos.meta =
|
||||||
options.meta.host = lib.mkOption {
|
{ config, ... }:
|
||||||
type = hostType;
|
{
|
||||||
};
|
options.meta.host = lib.mkOption {
|
||||||
};
|
type = hostType;
|
||||||
|
|
||||||
flake.modules.homeManager.meta = {
|
|
||||||
options.meta = {
|
|
||||||
host = lib.mkOption {
|
|
||||||
type = lib.types.nullOr hostType;
|
|
||||||
default = null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
user = lib.mkOption {
|
config.assertions = lib.mapAttrsToList (userName: user: {
|
||||||
type = lib.types.nullOr userType;
|
assertion = hasSinglePrimaryEmail user;
|
||||||
default = null;
|
message = "User `${userName}` must define exactly one primary email entry.";
|
||||||
|
}) 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.optional (config.meta.user != null) {
|
||||||
|
assertion = hasSinglePrimaryEmail config.meta.user;
|
||||||
|
message = "User `${config.meta.user.name}` must define exactly one primary email entry.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
hostInput = config.meta.host.input;
|
|
||||||
|
|
||||||
outputs = lib.mapAttrs (
|
outputs = lib.mapAttrs (
|
||||||
_: display:
|
_: display:
|
||||||
{
|
{
|
||||||
@@ -50,44 +48,17 @@ in
|
|||||||
inherit (display) mode;
|
inherit (display) mode;
|
||||||
}
|
}
|
||||||
) config.meta.host.displays;
|
) config.meta.host.displays;
|
||||||
terminalPackage = metaLib.resolvePackagePath {
|
inputProfiles = metaLib.mkInputProfiles config.meta.host.input;
|
||||||
|
terminal = metaLib.resolveUserTerminal {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
path = config.meta.user.terminalPackagePath;
|
user = config.meta.user;
|
||||||
};
|
|
||||||
hasMainProgram = terminalPackage != null && terminalPackage ? meta.mainProgram;
|
|
||||||
|
|
||||||
mouseSettings = lib.filterAttrs (_: value: value != null) {
|
|
||||||
accel-profile = hostInput.mouse.accelProfile;
|
|
||||||
accel-speed = hostInput.mouse.accelSpeed;
|
|
||||||
left-handed = hostInput.mouse.leftHanded;
|
|
||||||
middle-emulation = hostInput.mouse.middleEmulation;
|
|
||||||
natural-scroll = hostInput.mouse.naturalScrolling;
|
|
||||||
scroll-method = hostInput.mouse.scrollMethod;
|
|
||||||
};
|
|
||||||
|
|
||||||
touchpadSettings = lib.filterAttrs (_: value: value != null) {
|
|
||||||
accel-profile = hostInput.touchpad.accelProfile;
|
|
||||||
accel-speed = hostInput.touchpad.accelSpeed;
|
|
||||||
click-method = hostInput.touchpad.clickMethod;
|
|
||||||
dwt = hostInput.touchpad.disableWhileTyping;
|
|
||||||
left-handed = hostInput.touchpad.leftHanded;
|
|
||||||
middle-emulation = hostInput.touchpad.middleEmulation;
|
|
||||||
natural-scroll = hostInput.touchpad.naturalScrolling;
|
|
||||||
scroll-method = hostInput.touchpad.scrollMethod;
|
|
||||||
tap = hostInput.touchpad.tapping;
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assertions = [
|
assertions = metaLib.mkTerminalAssertions {
|
||||||
{
|
inherit terminal;
|
||||||
assertion = terminalPackage != null;
|
user = config.meta.user;
|
||||||
message = "Unknown terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` for user `${config.meta.user.name}`.";
|
};
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = hasMainProgram;
|
|
||||||
message = "Terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` must define `meta.mainProgram`.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
home.sessionVariables.NIXOS_OZONE_WL = "1";
|
home.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||||
|
|
||||||
@@ -167,20 +138,20 @@ in
|
|||||||
xkb.options = "caps:escape";
|
xkb.options = "caps:escape";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs (mouseSettings != { }) {
|
// lib.optionalAttrs (inputProfiles.niri.mouse != { }) {
|
||||||
mouse = mouseSettings;
|
mouse = inputProfiles.niri.mouse;
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs (touchpadSettings != { }) {
|
// lib.optionalAttrs (inputProfiles.niri.touchpad != { }) {
|
||||||
touchpad = touchpadSettings;
|
touchpad = inputProfiles.niri.touchpad;
|
||||||
};
|
};
|
||||||
|
|
||||||
binds =
|
binds =
|
||||||
if hasMainProgram then
|
if terminal.hasMainProgram then
|
||||||
import ./_bindings.nix {
|
import ./_bindings.nix {
|
||||||
inherit
|
inherit
|
||||||
lib
|
lib
|
||||||
terminalPackage
|
|
||||||
;
|
;
|
||||||
|
terminalPackage = terminal.package;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
|
|||||||
@@ -38,18 +38,17 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
terminalPackage = metaLib.resolvePackagePath {
|
terminal = metaLib.resolveUserTerminal {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
path = config.meta.user.terminalPackagePath;
|
user = config.meta.user;
|
||||||
};
|
};
|
||||||
hasMainProgram = terminalPackage != null && terminalPackage ? meta.mainProgram;
|
|
||||||
baseSettings =
|
baseSettings =
|
||||||
if hasMainProgram then
|
if terminal.hasMainProgram then
|
||||||
import ./_noctalia-config.nix {
|
import ./_noctalia-config.nix {
|
||||||
inherit
|
inherit
|
||||||
lib
|
lib
|
||||||
terminalPackage
|
|
||||||
;
|
;
|
||||||
|
terminalPackage = terminal.package;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
@@ -57,16 +56,10 @@ in
|
|||||||
{
|
{
|
||||||
imports = [ inputs.noctalia.homeModules.default ];
|
imports = [ inputs.noctalia.homeModules.default ];
|
||||||
|
|
||||||
assertions = [
|
assertions = metaLib.mkTerminalAssertions {
|
||||||
{
|
inherit terminal;
|
||||||
assertion = terminalPackage != null;
|
user = config.meta.user;
|
||||||
message = "Unknown terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` for user `${config.meta.user.name}`.";
|
};
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = hasMainProgram;
|
|
||||||
message = "Terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` must define `meta.mainProgram`.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.noctalia-shell = {
|
programs.noctalia-shell = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -88,18 +81,17 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
terminalPackage = metaLib.resolvePackagePath {
|
terminal = metaLib.resolveUserTerminal {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
path = config.meta.user.terminalPackagePath;
|
user = config.meta.user;
|
||||||
};
|
};
|
||||||
hasMainProgram = terminalPackage != null && terminalPackage ? meta.mainProgram;
|
|
||||||
baseSettings =
|
baseSettings =
|
||||||
if hasMainProgram then
|
if terminal.hasMainProgram then
|
||||||
import ./_noctalia-config.nix {
|
import ./_noctalia-config.nix {
|
||||||
inherit
|
inherit
|
||||||
lib
|
lib
|
||||||
terminalPackage
|
|
||||||
;
|
;
|
||||||
|
terminalPackage = terminal.package;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
@@ -107,7 +99,7 @@ in
|
|||||||
{
|
{
|
||||||
imports = [ homeModules.noctalia ];
|
imports = [ homeModules.noctalia ];
|
||||||
programs.noctalia-shell.settings = lib.mkForce (
|
programs.noctalia-shell.settings = lib.mkForce (
|
||||||
if hasMainProgram then mkPortableSettings baseSettings else { }
|
if terminal.hasMainProgram then mkPortableSettings baseSettings else { }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
let
|
|
||||||
homeModules = config.flake.modules.homeManager;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
flake.modules.homeManager.personal-productivity = {
|
|
||||||
imports = [
|
|
||||||
homeModules.bitwarden
|
|
||||||
homeModules.email
|
|
||||||
homeModules.pim
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
metaLib = config.meta.lib;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
flake.modules.homeManager.pim =
|
flake.modules.homeManager.pim =
|
||||||
{
|
{
|
||||||
@@ -44,7 +51,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
remote = {
|
remote = {
|
||||||
url = "https://radicale.jelles.net/";
|
url = metaLib.repo.services.radicale.url;
|
||||||
type = "caldav";
|
type = "caldav";
|
||||||
userName = config.home.username;
|
userName = config.home.username;
|
||||||
passwordCommand = [
|
passwordCommand = [
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
metaLib = config.meta.lib;
|
metaLib = config.meta.lib;
|
||||||
|
service = metaLib.repo.services.actual;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.actual =
|
flake.modules.nixos.actual =
|
||||||
@@ -11,15 +12,17 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
openFirewall = false;
|
openFirewall = false;
|
||||||
settings = {
|
settings = {
|
||||||
port = 3000;
|
inherit (service) port;
|
||||||
hostname = "127.0.0.1";
|
hostname = service.host;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
(metaLib.mkCaddyReverseProxy {
|
(metaLib.mkCaddyReverseProxy {
|
||||||
domain = "finance.jelles.net";
|
inherit (service)
|
||||||
port = 3000;
|
domain
|
||||||
|
port
|
||||||
|
;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
let
|
||||||
|
metaLib = config.meta.lib;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.caddy = {
|
flake.modules.nixos.caddy = {
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
email = "mail@jelles.net";
|
email = metaLib.repo.contact.email;
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
flake.modules.nixos.deluge-service =
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sops.secrets.deluge-auth-file = { };
|
|
||||||
|
|
||||||
services.deluge = {
|
|
||||||
enable = true;
|
|
||||||
declarative = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.modules.homeManager.deluge-client =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
home.packages = [ pkgs.deluge ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
metaLib = config.meta.lib;
|
metaLib = config.meta.lib;
|
||||||
|
service = metaLib.repo.services.gitea;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.gitea =
|
flake.modules.nixos.gitea =
|
||||||
@@ -12,10 +13,10 @@ in
|
|||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
server = {
|
server = {
|
||||||
DOMAIN = "git.jelles.net";
|
DOMAIN = service.domain;
|
||||||
ROOT_URL = "https://git.jelles.net/";
|
ROOT_URL = service.url;
|
||||||
HTTP_PORT = 3001;
|
HTTP_PORT = service.port;
|
||||||
HTTP_ADDR = "127.0.0.1";
|
HTTP_ADDR = service.host;
|
||||||
|
|
||||||
START_SSH_SERVER = false;
|
START_SSH_SERVER = false;
|
||||||
SSH_PORT = 22;
|
SSH_PORT = 22;
|
||||||
@@ -31,8 +32,10 @@ in
|
|||||||
}
|
}
|
||||||
|
|
||||||
(metaLib.mkCaddyReverseProxy {
|
(metaLib.mkCaddyReverseProxy {
|
||||||
domain = "git.jelles.net";
|
inherit (service)
|
||||||
port = 3001;
|
domain
|
||||||
|
port
|
||||||
|
;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
flake.modules.nixos.qbittorrent = {
|
|
||||||
services.qbittorrent = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
torrentingPort = 43864;
|
|
||||||
webuiPort = 8123;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
metaLib = config.meta.lib;
|
metaLib = config.meta.lib;
|
||||||
|
service = metaLib.repo.services.radicale;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.radicale =
|
flake.modules.nixos.radicale =
|
||||||
@@ -10,7 +11,7 @@ in
|
|||||||
services.radicale = {
|
services.radicale = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
server.hosts = [ "127.0.0.1:5232" ];
|
server.hosts = [ "${service.host}:${toString service.port}" ];
|
||||||
|
|
||||||
auth = {
|
auth = {
|
||||||
type = "htpasswd";
|
type = "htpasswd";
|
||||||
@@ -24,8 +25,10 @@ in
|
|||||||
}
|
}
|
||||||
|
|
||||||
(metaLib.mkCaddyReverseProxy {
|
(metaLib.mkCaddyReverseProxy {
|
||||||
domain = "radicale.jelles.net";
|
inherit (service)
|
||||||
port = 5232;
|
domain
|
||||||
|
port
|
||||||
|
;
|
||||||
extraHeaders = [
|
extraHeaders = [
|
||||||
{
|
{
|
||||||
name = "X-Script-Name";
|
name = "X-Script-Name";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
let
|
let
|
||||||
metaLib = config.meta.lib;
|
metaLib = config.meta.lib;
|
||||||
|
service = metaLib.repo.services.vaultwarden;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.vaultwarden =
|
flake.modules.nixos.vaultwarden =
|
||||||
@@ -11,17 +12,19 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
backupDir = "/var/backup/vaultwarden";
|
backupDir = "/var/backup/vaultwarden";
|
||||||
config = {
|
config = {
|
||||||
DOMAIN = "https://vault.jelles.net";
|
DOMAIN = service.url;
|
||||||
SIGNUPS_ALLOWED = false;
|
SIGNUPS_ALLOWED = false;
|
||||||
ROCKET_PORT = 8100;
|
ROCKET_PORT = service.port;
|
||||||
ROCKET_LOG = "critical";
|
ROCKET_LOG = "critical";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
(metaLib.mkCaddyReverseProxy {
|
(metaLib.mkCaddyReverseProxy {
|
||||||
domain = "vault.jelles.net";
|
inherit (service)
|
||||||
port = 8100;
|
domain
|
||||||
|
port
|
||||||
|
;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,38 +11,22 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
terminalPackage = metaLib.resolvePackagePath {
|
terminal = metaLib.resolveUserTerminal {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
path = config.meta.user.terminalPackagePath;
|
user = config.meta.user;
|
||||||
};
|
};
|
||||||
hasTerminalPackage = terminalPackage != null;
|
|
||||||
hasMainProgram = hasTerminalPackage && terminalPackage ? meta.mainProgram;
|
|
||||||
terminalDesktopId = if hasMainProgram then "${terminalPackage.meta.mainProgram}.desktop" else null;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assertions = [
|
assertions = metaLib.mkTerminalAssertions {
|
||||||
{
|
inherit terminal;
|
||||||
assertion = hasTerminalPackage;
|
user = config.meta.user;
|
||||||
message = "Unknown terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` for user `${config.meta.user.name}`.";
|
requireDesktopEntry = true;
|
||||||
}
|
requireKitty = true;
|
||||||
{
|
};
|
||||||
assertion = hasMainProgram;
|
|
||||||
message = "Terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` must define `meta.mainProgram`.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion =
|
|
||||||
hasMainProgram && builtins.pathExists "${terminalPackage}/share/applications/${terminalDesktopId}";
|
|
||||||
message = "Terminal package `${lib.showAttrPath config.meta.user.terminalPackagePath}` must provide `${terminalDesktopId}`.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = hasMainProgram && terminalPackage.meta.mainProgram == "kitty";
|
|
||||||
message = "The terminal feature currently only supports kitty-specific Home Manager configuration.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
xdg.terminal-exec = {
|
xdg.terminal-exec = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings.default = lib.optional (terminalDesktopId != null) terminalDesktopId;
|
settings.default = lib.optional (terminal.desktopId != null) terminal.desktopId;
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.kitty = {
|
programs.kitty = {
|
||||||
|
|||||||
+28
-15
@@ -1,3 +1,10 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
metaLib = config.meta.lib;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
flake.modules.nixos.theme =
|
flake.modules.nixos.theme =
|
||||||
{
|
{
|
||||||
@@ -5,10 +12,12 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
cursorTheme = {
|
repoTheme = metaLib.repo.theme;
|
||||||
name = "phinger-cursors-light";
|
cursorTheme = repoTheme.cursor // {
|
||||||
package = pkgs.phinger-cursors;
|
package = metaLib.resolvePackagePath {
|
||||||
size = 24;
|
inherit pkgs;
|
||||||
|
path = repoTheme.cursor.packagePath;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -25,21 +34,25 @@
|
|||||||
flake.modules.homeManager.theme =
|
flake.modules.homeManager.theme =
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cursorTheme = {
|
repoTheme = metaLib.repo.theme;
|
||||||
name = "phinger-cursors-light";
|
cursorTheme = repoTheme.cursor // {
|
||||||
package = pkgs.phinger-cursors;
|
package = metaLib.resolvePackagePath {
|
||||||
size = 24;
|
inherit pkgs;
|
||||||
|
path = repoTheme.cursor.packagePath;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
kanagawaThemeSrc = pkgs.fetchFromGitHub {
|
kanagawaThemeSrc = pkgs.fetchFromGitHub {
|
||||||
owner = "Fausto-Korpsvart";
|
inherit (repoTheme.kanagawa)
|
||||||
repo = "Kanagawa-GKT-Theme";
|
hash
|
||||||
rev = "55ca4ba249eba21f861b9866b71ab41bb8930318";
|
owner
|
||||||
hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E=";
|
repo
|
||||||
|
rev
|
||||||
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
kanagawaOverride = {
|
kanagawaOverride = {
|
||||||
version = "unstable-2025-10-23";
|
version = repoTheme.kanagawa.version;
|
||||||
src = kanagawaThemeSrc;
|
src = kanagawaThemeSrc;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
@@ -59,14 +72,14 @@
|
|||||||
"sftp://orion Orion VPS"
|
"sftp://orion Orion VPS"
|
||||||
];
|
];
|
||||||
theme = {
|
theme = {
|
||||||
name = "Kanagawa-BL-LB";
|
name = repoTheme.kanagawa.gtkThemeName;
|
||||||
package = pkgs.kanagawa-gtk-theme.overrideAttrs (_: kanagawaOverride);
|
package = pkgs.kanagawa-gtk-theme.overrideAttrs (_: kanagawaOverride);
|
||||||
};
|
};
|
||||||
gtk4.theme = {
|
gtk4.theme = {
|
||||||
inherit (config.gtk.theme) name package;
|
inherit (config.gtk.theme) name package;
|
||||||
};
|
};
|
||||||
iconTheme = {
|
iconTheme = {
|
||||||
name = "Kanagawa";
|
name = repoTheme.kanagawa.iconThemeName;
|
||||||
package = pkgs.kanagawa-icon-theme.overrideAttrs (_: kanagawaOverride);
|
package = pkgs.kanagawa-icon-theme.overrideAttrs (_: kanagawaOverride);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,15 +33,17 @@ in
|
|||||||
flake.modules.homeManager.workstation-base = {
|
flake.modules.homeManager.workstation-base = {
|
||||||
imports = [
|
imports = [
|
||||||
homeModules.ai
|
homeModules.ai
|
||||||
|
homeModules.bitwarden
|
||||||
homeModules.clipboard
|
homeModules.clipboard
|
||||||
homeModules.dev-tools
|
homeModules.dev-tools
|
||||||
|
homeModules.email
|
||||||
homeModules.local-apps
|
homeModules.local-apps
|
||||||
homeModules.mpv
|
homeModules.mpv
|
||||||
homeModules.neovim
|
homeModules.neovim
|
||||||
homeModules.nh
|
homeModules.nh
|
||||||
homeModules.niri
|
homeModules.niri
|
||||||
homeModules.nix
|
homeModules.nix
|
||||||
homeModules.personal-productivity
|
homeModules.pim
|
||||||
homeModules.podman
|
homeModules.podman
|
||||||
homeModules.shell
|
homeModules.shell
|
||||||
homeModules.sops
|
homeModules.sops
|
||||||
|
|||||||
+11
-15
@@ -4,6 +4,11 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
hostNames = [
|
||||||
|
"orion"
|
||||||
|
"polaris"
|
||||||
|
"zenith"
|
||||||
|
];
|
||||||
nixosModules = config.flake.modules.nixos;
|
nixosModules = config.flake.modules.nixos;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -11,22 +16,13 @@ in
|
|||||||
|
|
||||||
systems = [ "x86_64-linux" ];
|
systems = [ "x86_64-linux" ];
|
||||||
|
|
||||||
flake.nixosConfigurations = {
|
flake.nixosConfigurations = inputs.nixpkgs.lib.genAttrs hostNames (
|
||||||
orion = inputs.nixpkgs.lib.nixosSystem {
|
name:
|
||||||
|
inputs.nixpkgs.lib.nixosSystem {
|
||||||
specialArgs = { inherit inputs; };
|
specialArgs = { inherit inputs; };
|
||||||
modules = [ nixosModules.orion ];
|
modules = [ nixosModules.${name} ];
|
||||||
};
|
}
|
||||||
|
);
|
||||||
polaris = inputs.nixpkgs.lib.nixosSystem {
|
|
||||||
specialArgs = { inherit inputs; };
|
|
||||||
modules = [ nixosModules.polaris ];
|
|
||||||
};
|
|
||||||
|
|
||||||
zenith = inputs.nixpkgs.lib.nixosSystem {
|
|
||||||
specialArgs = { inherit inputs; };
|
|
||||||
modules = [ nixosModules.zenith ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
perSystem =
|
perSystem =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|||||||
@@ -17,22 +17,17 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
terminalPackage = metaLib.resolvePackagePath {
|
terminal = metaLib.resolveUserTerminal {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
path = config.meta.host.users.kiri.terminalPackagePath;
|
user = config.meta.host.users.kiri;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assertions = [
|
assertions = metaLib.mkTerminalAssertions {
|
||||||
{
|
inherit terminal;
|
||||||
assertion = terminalPackage != null;
|
user = config.meta.host.users.kiri;
|
||||||
message = "Unknown terminal package `${lib.showAttrPath config.meta.host.users.kiri.terminalPackagePath}` for user `kiri`.";
|
requireTerminfo = true;
|
||||||
}
|
};
|
||||||
{
|
|
||||||
assertion = terminalPackage != null && lib.elem "terminfo" terminalPackage.outputs;
|
|
||||||
message = "Terminal package `${lib.showAttrPath config.meta.host.users.kiri.terminalPackagePath}` must provide a `terminfo` output for `orion`.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
users.users.kiri = {
|
users.users.kiri = {
|
||||||
linger = true;
|
linger = true;
|
||||||
@@ -43,15 +38,20 @@ in
|
|||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
]
|
]
|
||||||
++ lib.optional (terminalPackage != null && lib.elem "terminfo" terminalPackage.outputs) (
|
++ lib.optional terminal.hasTerminfo (lib.getOutput "terminfo" terminal.package);
|
||||||
lib.getOutput "terminfo" terminalPackage
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
flake.modules.nixos.orion = metaLib.mkHost {
|
flake.modules.nixos.orion = metaLib.mkHost {
|
||||||
name = "orion";
|
name = "orion";
|
||||||
users = {
|
users = {
|
||||||
inherit (metaLib.users) kiri;
|
kiri = {
|
||||||
|
account = metaLib.users.kiri;
|
||||||
|
homeImports = [
|
||||||
|
homeModules.shell
|
||||||
|
homeModules.git
|
||||||
|
homeModules.syncthing
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
@@ -66,15 +66,6 @@ in
|
|||||||
nixosModules.radicale
|
nixosModules.radicale
|
||||||
nixosModules.actual
|
nixosModules.actual
|
||||||
nixosModules.gitea
|
nixosModules.gitea
|
||||||
(metaLib.mkHostUser {
|
|
||||||
account = metaLib.users.kiri;
|
|
||||||
needsPassword = false;
|
|
||||||
homeImports = [
|
|
||||||
homeModules.shell
|
|
||||||
homeModules.git
|
|
||||||
homeModules.syncthing
|
|
||||||
];
|
|
||||||
})
|
|
||||||
./_hardware.nix
|
./_hardware.nix
|
||||||
./_disk.nix
|
./_disk.nix
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -39,31 +39,30 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
inherit (metaLib.users)
|
kiri = {
|
||||||
ergon
|
account = metaLib.users.kiri;
|
||||||
kiri
|
needsPassword = true;
|
||||||
;
|
homeImports = [
|
||||||
|
homeModules.workstation-base
|
||||||
|
homeModules.syncthing
|
||||||
|
homeModules.qbittorrent-client
|
||||||
|
homeModules.noctalia
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
ergon = {
|
||||||
|
account = metaLib.users.ergon;
|
||||||
|
needsPassword = true;
|
||||||
|
homeImports = [
|
||||||
|
homeModules.workstation-base
|
||||||
|
homeModules.noctalia
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
nixosModules.workstation-base
|
nixosModules.workstation-base
|
||||||
nixosModules.steam
|
nixosModules.steam
|
||||||
(metaLib.mkHostUser {
|
|
||||||
account = metaLib.users.kiri;
|
|
||||||
needsPassword = true;
|
|
||||||
homeImports = [
|
|
||||||
homeModules.kiri-workstation
|
|
||||||
homeModules.noctalia
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(metaLib.mkHostUser {
|
|
||||||
account = metaLib.users.ergon;
|
|
||||||
needsPassword = true;
|
|
||||||
homeImports = [
|
|
||||||
homeModules.ergon-workstation
|
|
||||||
homeModules.noctalia
|
|
||||||
];
|
|
||||||
})
|
|
||||||
./_hardware.nix
|
./_hardware.nix
|
||||||
]
|
]
|
||||||
++ (with inputs.nixos-hardware.nixosModules; [
|
++ (with inputs.nixos-hardware.nixosModules; [
|
||||||
|
|||||||
@@ -40,31 +40,30 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
inherit (metaLib.users)
|
kiri = {
|
||||||
ergon
|
account = metaLib.users.kiri;
|
||||||
kiri
|
needsPassword = true;
|
||||||
;
|
homeImports = [
|
||||||
|
homeModules.workstation-base
|
||||||
|
homeModules.syncthing
|
||||||
|
homeModules.qbittorrent-client
|
||||||
|
homeModules.noctalia-portable
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
ergon = {
|
||||||
|
account = metaLib.users.ergon;
|
||||||
|
needsPassword = true;
|
||||||
|
homeImports = [
|
||||||
|
homeModules.workstation-base
|
||||||
|
homeModules.noctalia-portable
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
nixosModules.workstation-base
|
nixosModules.workstation-base
|
||||||
nixosModules.laptop-power
|
nixosModules.laptop-power
|
||||||
(metaLib.mkHostUser {
|
|
||||||
account = metaLib.users.kiri;
|
|
||||||
needsPassword = true;
|
|
||||||
homeImports = [
|
|
||||||
homeModules.kiri-workstation
|
|
||||||
homeModules.noctalia-portable
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(metaLib.mkHostUser {
|
|
||||||
account = metaLib.users.ergon;
|
|
||||||
needsPassword = true;
|
|
||||||
homeImports = [
|
|
||||||
homeModules.ergon-workstation
|
|
||||||
homeModules.noctalia-portable
|
|
||||||
];
|
|
||||||
})
|
|
||||||
{
|
{
|
||||||
hardware.enableRedistributableFirmware = true;
|
hardware.enableRedistributableFirmware = true;
|
||||||
services.fwupd.enable = true;
|
services.fwupd.enable = true;
|
||||||
|
|||||||
+330
-45
@@ -15,20 +15,84 @@ let
|
|||||||
stateVersion ? "24.05",
|
stateVersion ? "24.05",
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
hostUsers = lib.mapAttrs (_: spec: spec.account) users;
|
||||||
|
|
||||||
|
userAssertions = lib.flatten (
|
||||||
|
lib.mapAttrsToList (userName: spec: [
|
||||||
|
{
|
||||||
|
assertion = userName == spec.account.name;
|
||||||
|
message = "Host `${name}` declares user `${userName}` with mismatched account name `${spec.account.name}`.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = builtins.isList spec.homeImports;
|
||||||
|
message = "Host `${name}` user `${userName}` must define `homeImports` as a list.";
|
||||||
|
}
|
||||||
|
]) users
|
||||||
|
);
|
||||||
|
|
||||||
|
passwordUserSpecs = lib.filterAttrs (_: spec: spec.needsPassword or false) users;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assertions = userAssertions;
|
||||||
|
|
||||||
meta.host = {
|
meta.host = {
|
||||||
inherit
|
inherit
|
||||||
displays
|
displays
|
||||||
input
|
input
|
||||||
name
|
name
|
||||||
sourceControl
|
sourceControl
|
||||||
users
|
|
||||||
;
|
;
|
||||||
|
users = hostUsers;
|
||||||
};
|
};
|
||||||
|
|
||||||
inherit imports;
|
inherit imports;
|
||||||
|
|
||||||
networking.hostName = name;
|
networking.hostName = name;
|
||||||
system.stateVersion = stateVersion;
|
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 = spec.account.name;
|
||||||
|
home = spec.account.homeDirectory;
|
||||||
|
isNormalUser = true;
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
extraGroups = [
|
||||||
|
"wheel"
|
||||||
|
"networkmanager"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (spec.needsPassword or false) {
|
||||||
|
hashedPasswordFile = config.sops.secrets."hashed-password-${userName}".path;
|
||||||
|
}
|
||||||
|
) users;
|
||||||
|
|
||||||
|
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 = spec.stateVersion or stateVersion;
|
||||||
|
};
|
||||||
|
}) users;
|
||||||
};
|
};
|
||||||
|
|
||||||
mkCaddyReverseProxy =
|
mkCaddyReverseProxy =
|
||||||
@@ -65,62 +129,259 @@ let
|
|||||||
}:
|
}:
|
||||||
lib.attrByPath path null pkgs;
|
lib.attrByPath path null pkgs;
|
||||||
|
|
||||||
mkHostUser =
|
repo = {
|
||||||
|
contact.email = "mail@jelles.net";
|
||||||
|
|
||||||
|
services = {
|
||||||
|
actual = {
|
||||||
|
domain = "finance.jelles.net";
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = 3000;
|
||||||
|
url = "https://finance.jelles.net";
|
||||||
|
};
|
||||||
|
|
||||||
|
gitea = {
|
||||||
|
domain = "git.jelles.net";
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = 3001;
|
||||||
|
url = "https://git.jelles.net/";
|
||||||
|
};
|
||||||
|
|
||||||
|
radicale = {
|
||||||
|
domain = "radicale.jelles.net";
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = 5232;
|
||||||
|
url = "https://radicale.jelles.net/";
|
||||||
|
};
|
||||||
|
|
||||||
|
vaultwarden = {
|
||||||
|
domain = "vault.jelles.net";
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = 8100;
|
||||||
|
url = "https://vault.jelles.net";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
theme = {
|
||||||
|
cursor = {
|
||||||
|
name = "phinger-cursors-light";
|
||||||
|
packagePath = [ "phinger-cursors" ];
|
||||||
|
size = 24;
|
||||||
|
};
|
||||||
|
|
||||||
|
kanagawa = {
|
||||||
|
gtkThemeName = "Kanagawa-BL-LB";
|
||||||
|
iconThemeName = "Kanagawa";
|
||||||
|
owner = "Fausto-Korpsvart";
|
||||||
|
repo = "Kanagawa-GKT-Theme";
|
||||||
|
rev = "55ca4ba249eba21f861b9866b71ab41bb8930318";
|
||||||
|
hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E=";
|
||||||
|
version = "unstable-2025-10-23";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
resolveUserTerminal =
|
||||||
{
|
{
|
||||||
account,
|
|
||||||
homeImports,
|
|
||||||
needsPassword ? false,
|
|
||||||
stateVersion ? "24.05",
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
user,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
name = account.name;
|
package = resolvePackagePath {
|
||||||
primaryEmails = lib.filter (email: email.primary) (builtins.attrValues account.emails);
|
inherit pkgs;
|
||||||
|
path = user.terminalPackagePath;
|
||||||
|
};
|
||||||
|
hasPackage = package != null;
|
||||||
|
hasMainProgram = hasPackage && package ? meta.mainProgram;
|
||||||
|
mainProgram = if hasMainProgram then package.meta.mainProgram else null;
|
||||||
|
desktopId = if mainProgram == null then null else "${mainProgram}.desktop";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assertions = [
|
inherit
|
||||||
|
desktopId
|
||||||
|
hasMainProgram
|
||||||
|
hasPackage
|
||||||
|
mainProgram
|
||||||
|
package
|
||||||
|
;
|
||||||
|
|
||||||
|
hasDesktopEntry =
|
||||||
|
desktopId != null && builtins.pathExists "${package}/share/applications/${desktopId}";
|
||||||
|
|
||||||
|
hasTerminfo = hasPackage && lib.elem "terminfo" package.outputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkTerminalAssertions =
|
||||||
|
{
|
||||||
|
terminal,
|
||||||
|
user,
|
||||||
|
requireDesktopEntry ? false,
|
||||||
|
requireKitty ? false,
|
||||||
|
requireMainProgram ? true,
|
||||||
|
requireTerminfo ? false,
|
||||||
|
}:
|
||||||
|
lib.flatten [
|
||||||
|
[
|
||||||
{
|
{
|
||||||
assertion = builtins.length primaryEmails == 1;
|
assertion = terminal.hasPackage;
|
||||||
message = "User ${name} must define exactly one primary email entry.";
|
message = "Unknown terminal package `${lib.showAttrPath user.terminalPackagePath}` for user `${user.name}`.";
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
(lib.optional requireMainProgram {
|
||||||
|
assertion = terminal.hasMainProgram;
|
||||||
|
message = "Terminal package `${lib.showAttrPath user.terminalPackagePath}` must define `meta.mainProgram`.";
|
||||||
|
})
|
||||||
|
(lib.optional requireDesktopEntry {
|
||||||
|
assertion = terminal.hasDesktopEntry;
|
||||||
|
message = "Terminal package `${lib.showAttrPath user.terminalPackagePath}` must provide `${terminal.desktopId}`.";
|
||||||
|
})
|
||||||
|
(lib.optional requireKitty {
|
||||||
|
assertion = terminal.hasMainProgram && terminal.mainProgram == "kitty";
|
||||||
|
message = "The terminal feature currently only supports kitty-specific Home Manager configuration.";
|
||||||
|
})
|
||||||
|
(lib.optional requireTerminfo {
|
||||||
|
assertion = terminal.hasTerminfo;
|
||||||
|
message = "Terminal package `${lib.showAttrPath user.terminalPackagePath}` must provide a `terminfo` output.";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
programs.zsh.enable = true;
|
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
|
||||||
|
);
|
||||||
|
|
||||||
sops.secrets = lib.optionalAttrs needsPassword {
|
mkInputProfiles =
|
||||||
"hashed-password-${name}".neededForUsers = true;
|
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";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.${name} = {
|
mouse = input.mouse;
|
||||||
name = account.name;
|
touchpad = input.touchpad;
|
||||||
home = account.homeDirectory;
|
|
||||||
isNormalUser = true;
|
libinputMouse = mapConfiguredAttrs {
|
||||||
shell = pkgs.zsh;
|
settings = mouse;
|
||||||
extraGroups = [
|
schema = {
|
||||||
"wheel"
|
accelProfile.path = [ "accelProfile" ];
|
||||||
"networkmanager"
|
accelSpeed = {
|
||||||
];
|
path = [ "accelSpeed" ];
|
||||||
}
|
transform = toString;
|
||||||
// lib.optionalAttrs needsPassword {
|
};
|
||||||
hashedPasswordFile = config.sops.secrets."hashed-password-${name}".path;
|
leftHanded.path = [ "leftHanded" ];
|
||||||
|
middleEmulation.path = [ "middleEmulation" ];
|
||||||
|
naturalScrolling.path = [ "naturalScrolling" ];
|
||||||
|
scrollMethod = {
|
||||||
|
path = [ "scrollMethod" ];
|
||||||
|
values = lib.mapAttrs (_: value: value.libinput) scrollMethodValues;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager.users.${name} = {
|
libinputTouchpad = mapConfiguredAttrs {
|
||||||
imports = homeImports;
|
settings = touchpad;
|
||||||
meta = {
|
schema = {
|
||||||
host = config.meta.host;
|
accelProfile.path = [ "accelProfile" ];
|
||||||
user = account;
|
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" ];
|
||||||
};
|
};
|
||||||
home = {
|
};
|
||||||
username = account.name;
|
|
||||||
homeDirectory = account.homeDirectory;
|
niriMouse = mapConfiguredAttrs {
|
||||||
inherit stateVersion;
|
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
|
in
|
||||||
{
|
{
|
||||||
@@ -138,16 +399,30 @@ in
|
|||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
options.meta.lib.mkHostUser = lib.mkOption {
|
options.meta.lib.resolvePackagePath = lib.mkOption {
|
||||||
type = lib.types.raw;
|
type = lib.types.raw;
|
||||||
description = "Internal helper for explicit per-host user assembly.";
|
description = "Internal helper to resolve package attr paths against the local pkgs set.";
|
||||||
internal = true;
|
internal = true;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
options.meta.lib.resolvePackagePath = lib.mkOption {
|
options.meta.lib.resolveUserTerminal = lib.mkOption {
|
||||||
type = lib.types.raw;
|
type = lib.types.raw;
|
||||||
description = "Internal helper to resolve package attr paths against the local pkgs set.";
|
description = "Internal helper to resolve and validate user terminal metadata.";
|
||||||
|
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;
|
internal = true;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
@@ -159,12 +434,22 @@ in
|
|||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
options.meta.lib.repo = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
description = "Internal shared repository metadata.";
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
|
||||||
config.meta.lib = {
|
config.meta.lib = {
|
||||||
inherit
|
inherit
|
||||||
|
mkInputProfiles
|
||||||
mkCaddyReverseProxy
|
mkCaddyReverseProxy
|
||||||
|
mkTerminalAssertions
|
||||||
mkHost
|
mkHost
|
||||||
mkHostUser
|
repo
|
||||||
resolvePackagePath
|
resolvePackagePath
|
||||||
|
resolveUserTerminal
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user