Rebase to flake parts #6
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# Monitor layout for 14900k (ported from NixOS-New `hosts/clients/14900k/home.nix`).
|
# Monitor layout for 14900k (ported from NixOS-New `hosts/clients/14900k/home.nix`).
|
||||||
# Niri: `chiasson.desktop.niri.extraSettings.extraConfig` (wrapper-modules / system package).
|
# Niri: `chiasson.desktop.niri.extraSettings` (`extraConfig` KDL + `binds` merged with defaults).
|
||||||
# Hyprland: `chiasson.desktop.hyprland.settings` (merged in HM when `chiasson.desktop.hyprland.enable`).
|
# Hyprland: `chiasson.desktop.hyprland.settings` (merged in HM when `chiasson.desktop.hyprland.enable`).
|
||||||
|
|
||||||
#TODO[epic=Moderate] Clean this up, move to host's configuration.nix.
|
#TODO[epic=Moderate] Clean this up, move to host's configuration.nix.
|
||||||
@@ -8,7 +8,8 @@ let
|
|||||||
gpuPassthrough = config.chiasson.system.vm.gpuPassthrough.enable;
|
gpuPassthrough = config.chiasson.system.vm.gpuPassthrough.enable;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
chiasson.desktop.niri.extraSettings.extraConfig =
|
chiasson.desktop.niri.extraSettings = {
|
||||||
|
extraConfig =
|
||||||
if gpuPassthrough then
|
if gpuPassthrough then
|
||||||
''
|
''
|
||||||
output "DP-1" {
|
output "DP-1" {
|
||||||
@@ -18,7 +19,7 @@ in
|
|||||||
focus-at-startup
|
focus-at-startup
|
||||||
}
|
}
|
||||||
output "HDMI-A-2" {
|
output "HDMI-A-2" {
|
||||||
mode "1920x1080@60"
|
mode "2560x1080@60"
|
||||||
scale 1.0
|
scale 1.0
|
||||||
position x=0 y=0
|
position x=0 y=0
|
||||||
}
|
}
|
||||||
@@ -44,6 +45,14 @@ in
|
|||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
binds."XF86Tools".spawn = [
|
||||||
|
"wpctl"
|
||||||
|
"set-mute"
|
||||||
|
"@DEFAULT_AUDIO_SOURCE@"
|
||||||
|
"toggle"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
chiasson.desktop.hyprland.settings = lib.mkIf config.chiasson.desktop.hyprland.enable (
|
chiasson.desktop.hyprland.settings = lib.mkIf config.chiasson.desktop.hyprland.enable (
|
||||||
let
|
let
|
||||||
monitorList =
|
monitorList =
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Epson ET-2760 on Wi‑Fi via IPP/mDNS.
|
||||||
|
# Import from configuration.nix when you need printing (see commented import there).
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
services.printing = {
|
||||||
|
enable = true;
|
||||||
|
webInterface = true;
|
||||||
|
drivers = with pkgs; [
|
||||||
|
epson-escpr2
|
||||||
|
epson-escpr
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
nssmdns4 = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 631 ];
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
./_private/platform.nix
|
./_private/platform.nix
|
||||||
./_private/nvidia.nix
|
./_private/nvidia.nix
|
||||||
./_private/peripherals.nix
|
./_private/peripherals.nix
|
||||||
|
# ./_private/printing-epson.nix
|
||||||
./_private/displays.nix
|
./_private/displays.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Pi5 + DSI DRM KDL snippets (`desktop.niri.raspberryPi5DrmWorkaround`) — lives in `flake.lib`.
|
||||||
|
{ ... }:
|
||||||
|
let
|
||||||
|
drmExtraConfig = ''
|
||||||
|
debug {
|
||||||
|
render-drm-device "/dev/dri/renderD128"
|
||||||
|
ignore-drm-device "/dev/dri/card1"
|
||||||
|
ignore-drm-device "/dev/dri/card2"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
flake.lib.pi5NiriKdl = {
|
||||||
|
inherit drmExtraConfig;
|
||||||
|
|
||||||
|
# Keep in sync with DMS greeter niri template when upstream edits it.
|
||||||
|
dankGreeterCompositorConfig = ''
|
||||||
|
hotkey-overlay {
|
||||||
|
skip-at-startup
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
DMS_RUN_GREETER "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
${drmExtraConfig}
|
||||||
|
|
||||||
|
gestures {
|
||||||
|
hot-corners {
|
||||||
|
off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
background-color "#000000"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# Pure helpers: catalog → NixOS/HM/SSH shapes (`self.lib.usersMerge lib`).
|
||||||
|
{ ... }: {
|
||||||
|
flake.lib.usersMerge =
|
||||||
|
lib:
|
||||||
|
let
|
||||||
|
userHm = user: user.homeManager or { };
|
||||||
|
userSsh = user: user.ssh or { };
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
resolveHomeManagerModule =
|
||||||
|
moduleSpec:
|
||||||
|
let
|
||||||
|
t = builtins.typeOf moduleSpec;
|
||||||
|
in
|
||||||
|
if t == "path" || t == "string" then import moduleSpec else moduleSpec;
|
||||||
|
|
||||||
|
selectedUsersAttr =
|
||||||
|
{ catalog, enabled, hostOverrides }:
|
||||||
|
lib.listToAttrs (
|
||||||
|
map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = lib.recursiveUpdate catalog.${name} (hostOverrides.${name} or { });
|
||||||
|
}) enabled
|
||||||
|
);
|
||||||
|
|
||||||
|
missingEnabledNames = catalog: enabled: builtins.filter (name: !(builtins.hasAttr name catalog)) enabled;
|
||||||
|
|
||||||
|
strayHomeUserKeys = homeUsers: enabled:
|
||||||
|
builtins.filter (k: !(builtins.elem k enabled)) (builtins.attrNames homeUsers);
|
||||||
|
|
||||||
|
mkNixosUser =
|
||||||
|
name: user:
|
||||||
|
{
|
||||||
|
isNormalUser = user.isNormalUser or true;
|
||||||
|
description = user.description or name;
|
||||||
|
extraGroups = user.extraGroups or [ ];
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (user ? hashedPasswordFile && user.hashedPasswordFile != null) {
|
||||||
|
hashedPasswordFile = user.hashedPasswordFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
hmWiredNames =
|
||||||
|
selectedUsers:
|
||||||
|
lib.attrNames (
|
||||||
|
lib.filterAttrs (_: user:
|
||||||
|
let
|
||||||
|
hm = userHm user;
|
||||||
|
in
|
||||||
|
(hm.enable or false) && (hm.module or null) != null
|
||||||
|
) selectedUsers
|
||||||
|
);
|
||||||
|
|
||||||
|
rbwOutboundSnippet =
|
||||||
|
name: user:
|
||||||
|
let
|
||||||
|
outboundCfg = ((userSsh user).outbound or { }).rbw or { };
|
||||||
|
in
|
||||||
|
lib.mkIf (outboundCfg.enable or false) {
|
||||||
|
chiasson.ssh.outbound.rbw.enable = true;
|
||||||
|
chiasson.ssh.outbound.rbw.user = name;
|
||||||
|
chiasson.ssh.outbound.rbw.hosts =
|
||||||
|
if (outboundCfg.hosts or "all") == "all" then [ "all" ] else outboundCfg.hosts;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkHmUserModule =
|
||||||
|
{ name, user, hostExtraModules }:
|
||||||
|
let
|
||||||
|
hm = userHm user;
|
||||||
|
hmModule = resolveHomeManagerModule hm.module;
|
||||||
|
in
|
||||||
|
lib.mkMerge (
|
||||||
|
[
|
||||||
|
hmModule
|
||||||
|
(rbwOutboundSnippet name user)
|
||||||
|
]
|
||||||
|
++ (hm.extraModules or [ ])
|
||||||
|
++ hostExtraModules
|
||||||
|
);
|
||||||
|
|
||||||
|
inboundAuthorizedOrNull =
|
||||||
|
user:
|
||||||
|
let
|
||||||
|
inboundCfg = (userSsh user).inbound or { };
|
||||||
|
in
|
||||||
|
if !(inboundCfg.enable or false) then
|
||||||
|
null
|
||||||
|
else if (inboundCfg.authorizedHosts or "all") == "all" then
|
||||||
|
"all"
|
||||||
|
else
|
||||||
|
inboundCfg.authorizedHosts;
|
||||||
|
|
||||||
|
inboundHostsAttr =
|
||||||
|
selectedUsers:
|
||||||
|
lib.pipe selectedUsers [
|
||||||
|
(lib.mapAttrs (_: inboundAuthorizedOrNull))
|
||||||
|
(lib.filterAttrs (_: v: v != null))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
{ self, ... }: {
|
||||||
|
flake.homeManagerModules.sshOutboundRbw = {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.ssh.outbound.rbw;
|
||||||
|
inventory = self.lib.sshInventory;
|
||||||
|
selectedHostNames =
|
||||||
|
if cfg.hosts == [ "all" ] then
|
||||||
|
builtins.attrNames inventory.activeHosts
|
||||||
|
else
|
||||||
|
cfg.hosts;
|
||||||
|
missing = builtins.filter (name: !(builtins.hasAttr name inventory.hosts)) selectedHostNames;
|
||||||
|
selectedHosts = builtins.listToAttrs (
|
||||||
|
builtins.map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = inventory.hosts.${name};
|
||||||
|
}) selectedHostNames
|
||||||
|
);
|
||||||
|
sshConfigTemplate = inventory.mkSshConfigTemplate {
|
||||||
|
selectedHosts = selectedHosts;
|
||||||
|
user = cfg.user;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.ssh.outbound.rbw = {
|
||||||
|
enable = lib.mkEnableOption "Generated `~/.ssh/config` + rbw agent socket.";
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = config.home.username;
|
||||||
|
description = "`User` in generated `Host` blocks.";
|
||||||
|
};
|
||||||
|
hosts = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "all" ];
|
||||||
|
description = "Inventory hosts to emit (or `[ \"all\" ]`).";
|
||||||
|
};
|
||||||
|
manageSshConfig = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Write `~/.ssh/config` from the template.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = missing == [ ];
|
||||||
|
message = "ssh.outbound.rbw: unknown host keys: ${builtins.concatStringsSep ", " missing}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
home.packages = [ pkgs.rbw pkgs.pinentry-qt ];
|
||||||
|
home.sessionVariables.SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/rbw/ssh-agent-socket";
|
||||||
|
home.file = inventory.mkIdentityFiles selectedHosts;
|
||||||
|
|
||||||
|
programs.ssh.enable = lib.mkIf cfg.manageSshConfig false;
|
||||||
|
home.activation.rbwSshConfig = lib.mkIf cfg.manageSshConfig (lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
mkdir -p "$HOME/.ssh"
|
||||||
|
chmod 700 "$HOME/.ssh"
|
||||||
|
RBW_SSH_SOCK="/run/user/$(id -u)/rbw/ssh-agent-socket"
|
||||||
|
cat > "$HOME/.ssh/config" <<'EOF'
|
||||||
|
${sshConfigTemplate}
|
||||||
|
EOF
|
||||||
|
sed -i "s|__RBW_SSH_SOCK__|$RBW_SSH_SOCK|g" "$HOME/.ssh/config"
|
||||||
|
chmod 600 "$HOME/.ssh/config"
|
||||||
|
'');
|
||||||
|
|
||||||
|
systemd.user.services.rbw-agent-bootstrap = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Bootstrap rbw SSH agent";
|
||||||
|
PartOf = [ "graphical-session.target" ];
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.bash}/bin/bash -lc '${pkgs.rbw}/bin/rbw unlocked >/dev/null 2>&1 || true'";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
home.activation.rbwPinentryConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
${pkgs.rbw}/bin/rbw config set pinentry "${pkgs.pinentry-qt}/bin/pinentry-qt" >/dev/null 2>&1 || true
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{ self, ... }: {
|
||||||
|
flake.nixosModules.sshInbound = {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.ssh.inbound;
|
||||||
|
inventory = self.lib.sshInventory;
|
||||||
|
resolveSelection =
|
||||||
|
selection:
|
||||||
|
if selection == "all" then
|
||||||
|
inventory.authorizedKeys
|
||||||
|
else
|
||||||
|
let
|
||||||
|
missing = builtins.filter (name: !(builtins.hasAttr name inventory.hosts)) selection;
|
||||||
|
in
|
||||||
|
if missing != [ ] then
|
||||||
|
throw "ssh.inbound: unknown host keys: ${builtins.concatStringsSep ", " missing}"
|
||||||
|
else
|
||||||
|
lib.unique (
|
||||||
|
builtins.filter (key: key != null) (
|
||||||
|
builtins.map (hostName: inventory.hosts.${hostName}.publicKey) selection
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.ssh.inbound = {
|
||||||
|
enable = lib.mkEnableOption "Apply `authorizedKeys` from the SSH inventory.";
|
||||||
|
userAuthorizedHosts = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.either (lib.types.enum [ "all" ]) (lib.types.listOf lib.types.str));
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
olivier = "all";
|
||||||
|
admin = [ "14900k" "t2mbp" ];
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Per user: `"all"` or a list of inventory host names whose keys land in `authorized_keys`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
users.users = lib.mapAttrs
|
||||||
|
(_user: selection: {
|
||||||
|
openssh.authorizedKeys.keys = resolveSelection selection;
|
||||||
|
})
|
||||||
|
cfg.userAuthorizedHosts;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemAudio =
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system.audio;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.audio = {
|
||||||
|
enable = lib.mkEnableOption ''
|
||||||
|
PipeWire (ALSA + Pulse), RTKit, optional WirePlumber tweak to kill idle suspend pop on devices.
|
||||||
|
'';
|
||||||
|
|
||||||
|
rtkit.enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable `security.rtkit.enable` (recommended with PipeWire).";
|
||||||
|
};
|
||||||
|
|
||||||
|
pipewire = {
|
||||||
|
alsa = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "PipeWire ALSA support.";
|
||||||
|
};
|
||||||
|
support32Bit = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "32-bit ALSA support on x86_64.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
pulse.enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "PipeWire PulseAudio compatibility (`pulseaudio` clients).";
|
||||||
|
};
|
||||||
|
jack.enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "PipeWire JACK support (e.g. pro-audio / low-latency apps).";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
preventIdleSuspend = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
WirePlumber + clock hints so ALSA nodes do not sleep (~0.5s glitch on resume otherwise).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
services.pulseaudio.enable = false;
|
||||||
|
security.rtkit.enable = cfg.rtkit.enable;
|
||||||
|
|
||||||
|
services.pipewire = lib.mkMerge [
|
||||||
|
{
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = cfg.pipewire.alsa.enable;
|
||||||
|
alsa.support32Bit = cfg.pipewire.alsa.support32Bit;
|
||||||
|
pulse.enable = cfg.pipewire.pulse.enable;
|
||||||
|
}
|
||||||
|
(lib.mkIf cfg.pipewire.jack.enable {
|
||||||
|
jack.enable = true;
|
||||||
|
})
|
||||||
|
(lib.mkIf cfg.preventIdleSuspend {
|
||||||
|
extraConfig.pipewire = {
|
||||||
|
"context.properties" = {
|
||||||
|
"default.clock.quantum" = 1024;
|
||||||
|
"default.clock.min-quantum" = 32;
|
||||||
|
"default.clock.max-quantum" = 8192;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(lib.mkIf cfg.preventIdleSuspend {
|
||||||
|
environment.etc."wireplumber/wireplumber.conf.d/99-prevent-suspend.conf".text = ''
|
||||||
|
monitor.alsa.rules = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{ node.name = "~alsa_output.*" }
|
||||||
|
{ node.name = "~alsa_input.*" }
|
||||||
|
]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
session.suspend-timeout-seconds = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{ self, inputs, ... }: {
|
||||||
|
flake.nixosModules.system = {
|
||||||
|
imports = [
|
||||||
|
inputs.nur.modules.nixos.default
|
||||||
|
self.nixosModules.systemLocalization
|
||||||
|
self.nixosModules.systemFonts
|
||||||
|
self.nixosModules.systemNetworking
|
||||||
|
self.nixosModules.systemRemoteDesktop
|
||||||
|
self.nixosModules.systemLocalsend
|
||||||
|
self.nixosModules.systemMonitorInput
|
||||||
|
self.nixosModules.systemSpotify
|
||||||
|
self.nixosModules.systemPackagesDefaults
|
||||||
|
self.nixosModules.systemDocker
|
||||||
|
self.nixosModules.systemFlatpak
|
||||||
|
self.nixosModules.systemAudio
|
||||||
|
self.nixosModules.systemIdeapadMrubyOverlay
|
||||||
|
self.nixosModules.systemGaming
|
||||||
|
self.nixosModules.systemUconsoleKernelBuilder
|
||||||
|
self.nixosModules.systemLibrepods
|
||||||
|
self.nixosModules.systemPalera1n
|
||||||
|
self.nixosModules.systemCaching
|
||||||
|
inputs.swiftshare.nixosModules.systemServiceSwiftshare
|
||||||
|
self.nixosModules.systemServiceImmich
|
||||||
|
self.nixosModules.systemVM
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemFonts = {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system.fonts;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.fonts = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Bundled fonts + fontconfig defaults.";
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.package;
|
||||||
|
default = with pkgs; [
|
||||||
|
noto-fonts
|
||||||
|
noto-fonts-cjk-sans
|
||||||
|
noto-fonts-color-emoji
|
||||||
|
liberation_ttf
|
||||||
|
fira-code
|
||||||
|
fira-code-symbols
|
||||||
|
mplus-outline-fonts.githubRelease
|
||||||
|
dina-font
|
||||||
|
proggyfonts
|
||||||
|
nerd-fonts.fira-code
|
||||||
|
nerd-fonts.droid-sans-mono
|
||||||
|
nerd-fonts.jetbrains-mono
|
||||||
|
];
|
||||||
|
description = "System font packages to install.";
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultFonts = {
|
||||||
|
monospace = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "FiraCode Nerd Font" "Fira Code" "DejaVu Sans Mono" ];
|
||||||
|
description = "Default monospace font fallback chain.";
|
||||||
|
};
|
||||||
|
sansSerif = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "Noto Sans" "DejaVu Sans" ];
|
||||||
|
description = "Default sans-serif font fallback chain.";
|
||||||
|
};
|
||||||
|
serif = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "Noto Serif" "DejaVu Serif" ];
|
||||||
|
description = "Default serif font fallback chain.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
fonts.packages = cfg.packages;
|
||||||
|
fonts.fontconfig = {
|
||||||
|
enable = true;
|
||||||
|
defaultFonts = {
|
||||||
|
monospace = cfg.defaultFonts.monospace;
|
||||||
|
sansSerif = cfg.defaultFonts.sansSerif;
|
||||||
|
serif = cfg.defaultFonts.serif;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# DDC/CI helper + i2c-dev + ddcutil (implementation under `package/`).
|
||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemMonitorInput =
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system.monitorInput;
|
||||||
|
monitorInputPkg = pkgs.callPackage ./package { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.monitorInput.enable = lib.mkEnableOption ''
|
||||||
|
`i2c-dev`, ddcutil, and `monitor-input` for DDC/CI input switching.
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
boot.kernelModules = [ "i2c-dev" ];
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.ddcutil
|
||||||
|
monitorInputPkg
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# DDC/CI monitor input control: list displays, get/set input by bus or name.
|
||||||
|
{ pkgs }:
|
||||||
|
let
|
||||||
|
script = builtins.readFile ./monitor-input.sh;
|
||||||
|
unwrapped = pkgs.writeShellScriptBin "monitor-input" script;
|
||||||
|
in
|
||||||
|
pkgs.runCommand "monitor-input" { nativeBuildInputs = [ pkgs.makeWrapper ]; } ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp ${unwrapped}/bin/monitor-input $out/bin/monitor-input
|
||||||
|
chmod +x $out/bin/monitor-input
|
||||||
|
wrapProgram $out/bin/monitor-input --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.ddcutil ]}
|
||||||
|
''
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
VCP_INPUT=0x60
|
||||||
|
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/monitor-input"
|
||||||
|
CACHE_FILE="$CACHE_DIR/displays"
|
||||||
|
CACHE_TTL=60
|
||||||
|
|
||||||
|
# Output one line per DDC-capable display: BUS MODEL MFG (from ddcutil detect, cached for CACHE_TTL seconds).
|
||||||
|
list_ddc_displays() {
|
||||||
|
mkdir -p "$CACHE_DIR"
|
||||||
|
local now ts
|
||||||
|
now=$(date +%s)
|
||||||
|
ts=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0)
|
||||||
|
if [[ -s "$CACHE_FILE" ]] && (( ts + CACHE_TTL > now )); then
|
||||||
|
cat "$CACHE_FILE"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
ddcutil detect 2>/dev/null | awk '
|
||||||
|
/^Display [0-9]+$/ { bus=""; model=""; mfg=""; next }
|
||||||
|
/^Invalid display|^ DDC communication failed/ { next }
|
||||||
|
/^ I2C bus:/ { if (match($0, /i2c-[0-9]+/)) bus=substr($0, RSTART+4, RLENGTH-4); next }
|
||||||
|
/^ Mfg id:[[:space:]]+/ { mfg=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", mfg); next }
|
||||||
|
/^ Model:[[:space:]]+/ { model=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", model); next }
|
||||||
|
/^ VCP version:/ { if (bus != "") print bus "\t" model "\t" mfg }
|
||||||
|
' | tee "$CACHE_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve DISP (bus number or name substring) to bus number. Exits 1 if not found or ambiguous.
|
||||||
|
# When DISP is numeric, use it directly (no slow ddcutil detect).
|
||||||
|
resolve_display() {
|
||||||
|
local disp="$1"
|
||||||
|
if [[ "$disp" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "$disp"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local bus r
|
||||||
|
bus=$(list_ddc_displays | awk -v disp="$disp" '
|
||||||
|
BEGIN { d = tolower(disp); found = 0 }
|
||||||
|
{
|
||||||
|
if (index(tolower($2), d) || index(tolower($3), d)) {
|
||||||
|
if (found) exit 2
|
||||||
|
found = $1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END { if (found) print found; exit (found ? 0 : 1) }
|
||||||
|
')
|
||||||
|
r=$?
|
||||||
|
[[ $r -eq 2 ]] && { echo "monitor-input: '$disp' matches multiple displays (use bus number)" >&2; return 1; }
|
||||||
|
[[ $r -eq 0 && -n "$bus" ]] || { echo "monitor-input: no DDC display matching '$disp'" >&2; return 1; }
|
||||||
|
echo "$bus"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map input name to VCP 0x60 value (common assignments; use hex for others).
|
||||||
|
input_to_hex() {
|
||||||
|
case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
|
||||||
|
dp|dp1) echo "0x0f" ;;
|
||||||
|
dp2) echo "0x10" ;;
|
||||||
|
hdmi|hdmi1) echo "0x11" ;;
|
||||||
|
hdmi2) echo "0x12" ;;
|
||||||
|
0x*) echo "$1" ;;
|
||||||
|
*) echo "monitor-input: unknown input '$1' (use dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN)" >&2; return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
list)
|
||||||
|
echo "Bus Model Mfg"
|
||||||
|
list_ddc_displays
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[[ -n "${1:-}" ]] || { echo "Usage: monitor-input list | monitor-input <display> get|set [input]" >&2; exit 1; }
|
||||||
|
case "${2:-}" in
|
||||||
|
get)
|
||||||
|
bus=$(resolve_display "$1") || exit 1
|
||||||
|
exec ddcutil --bus "$bus" getvcp "$VCP_INPUT"
|
||||||
|
;;
|
||||||
|
set)
|
||||||
|
[[ -n "${3:-}" ]] || { echo "Usage: monitor-input <display> set <input>" >&2; exit 1; }
|
||||||
|
bus=$(resolve_display "$1") || exit 1
|
||||||
|
hex=$(input_to_hex "$3") || exit 1
|
||||||
|
exec ddcutil --bus "$bus" setvcp "$VCP_INPUT" "$hex"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: monitor-input list" >&2
|
||||||
|
echo " monitor-input <display> get" >&2
|
||||||
|
echo " monitor-input <display> set <input>" >&2
|
||||||
|
echo " display: bus number (e.g. 23) or name match (e.g. benq, zowie, lg, 34GL750)" >&2
|
||||||
|
echo " input: dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemPackagesDefaults =
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.defaultPackages = {
|
||||||
|
enabled = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable shared default CLI/system package set.";
|
||||||
|
};
|
||||||
|
packages = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.package;
|
||||||
|
default = with pkgs; [
|
||||||
|
git
|
||||||
|
wget
|
||||||
|
unzip
|
||||||
|
jq
|
||||||
|
pfetch
|
||||||
|
];
|
||||||
|
description = "Default packages to install on all hosts.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
options.chiasson.system.extraPackages = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.package;
|
||||||
|
default = [ ];
|
||||||
|
description = "Additional packages to install on all hosts.";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.chiasson.system.allowUnfree = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Allow unfree packages from nixpkgs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkMerge [
|
||||||
|
(lib.mkIf cfg.defaultPackages.enabled {
|
||||||
|
environment.systemPackages = cfg.defaultPackages.packages;
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.extraPackages != [ ]) {
|
||||||
|
environment.systemPackages = cfg.extraPackages;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
nixpkgs.config.allowUnfree = cfg.allowUnfree;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# checkm8 jailbreak CLI from upstream binaries; needs root. usbmuxd + idevice* help with USB iOS.
|
||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemPalera1n =
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system.palera1n;
|
||||||
|
|
||||||
|
version = "2.2.1";
|
||||||
|
|
||||||
|
srcFor =
|
||||||
|
{
|
||||||
|
x86_64-linux = pkgs.fetchurl {
|
||||||
|
url = "https://github.com/palera1n/palera1n/releases/download/v${version}/palera1n-linux-x86_64";
|
||||||
|
sha256 = "0l9ipabbiggkzvpy8hyi681kalln3z3396xsx4lz1393jw3c8dm2";
|
||||||
|
};
|
||||||
|
aarch64-linux = pkgs.fetchurl {
|
||||||
|
url = "https://github.com/palera1n/palera1n/releases/download/v${version}/palera1n-linux-arm64";
|
||||||
|
sha256 = "12n0136g218b5ndq2s7ssymab4i6pbb55l681b94zs9m9lvacfa1";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
.${pkgs.stdenv.hostPlatform.system} or null;
|
||||||
|
|
||||||
|
palera1n =
|
||||||
|
if srcFor == null then
|
||||||
|
null
|
||||||
|
else
|
||||||
|
pkgs.stdenvNoCC.mkDerivation {
|
||||||
|
pname = "palera1n";
|
||||||
|
inherit version;
|
||||||
|
src = srcFor;
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
install -Dm755 $src $out/bin/palera1n
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "iOS jailbreak tool for checkm8 devices (A8–A11)";
|
||||||
|
homepage = "https://palera.in";
|
||||||
|
license = licenses.mit;
|
||||||
|
sourceProvenance = with sourceTypes; [ binaryNativeCode ];
|
||||||
|
platforms = [ "x86_64-linux" "aarch64-linux" ];
|
||||||
|
mainProgram = "palera1n";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.palera1n = {
|
||||||
|
enable = lib.mkEnableOption ''
|
||||||
|
palera1n from GitHub releases + usbmuxd / libimobiledevice toggles (defaults on).
|
||||||
|
'';
|
||||||
|
|
||||||
|
usbmuxd = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "usbmuxd for iOS USB.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
libimobiledevice = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "idevice* tools on PATH.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||||
|
(lib.mkIf (palera1n == null) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = false;
|
||||||
|
message = "system.palera1n: no upstream binary for ${pkgs.stdenv.hostPlatform.system}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(lib.mkIf (palera1n != null) {
|
||||||
|
environment.systemPackages = [ palera1n ];
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.enable && cfg.usbmuxd.enable) {
|
||||||
|
services.usbmuxd.enable = true;
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.enable && cfg.libimobiledevice.enable) {
|
||||||
|
environment.systemPackages = [ pkgs.libimobiledevice ];
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.usersCatalogOptions =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
options.chiasson.users = {
|
||||||
|
catalog = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
User records merged from `usersCatalogDefaults`; override with `hostOverrides` or `mkForce`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
enabled = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = "Catalog names to materialize as `users.users` on this machine.";
|
||||||
|
};
|
||||||
|
hostOverrides = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
`recursiveUpdate`d onto catalog users.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
extraModules = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.listOf lib.types.unspecified);
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Per-user Home Manager `extraModules` keyed by catalog user name.
|
||||||
|
Keys must match `chiasson.users.enabled`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
homeManager = {
|
||||||
|
autoWire = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Create HM users from the catalog when true.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Catalog → NixOS `users.users` + Home Manager + SSH inbound.
|
||||||
|
{ self, ... }: {
|
||||||
|
flake.nixosModules.users =
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
usersLib = self.lib.usersMerge lib;
|
||||||
|
selectUsers =
|
||||||
|
c:
|
||||||
|
let
|
||||||
|
uc = c.chiasson.users;
|
||||||
|
in
|
||||||
|
usersLib.selectedUsersAttr {
|
||||||
|
catalog = uc.catalog;
|
||||||
|
enabled = uc.enabled;
|
||||||
|
hostOverrides = uc.hostOverrides;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
self.nixosModules.sshInbound
|
||||||
|
self.nixosModules.usersCatalogOptions
|
||||||
|
self.nixosModules.usersCatalogDefaults
|
||||||
|
{ _module.args = { inherit self usersLib selectUsers; }; }
|
||||||
|
self.nixosModules.usersHomeIntegration
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.usersHomeIntegration =
|
||||||
|
{ config, options, lib, self, usersLib, selectUsers, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.users;
|
||||||
|
selected = selectUsers config;
|
||||||
|
missing = usersLib.missingEnabledNames cfg.catalog cfg.enabled;
|
||||||
|
stray = usersLib.strayHomeUserKeys cfg.extraModules cfg.enabled;
|
||||||
|
names = usersLib.hmWiredNames selected;
|
||||||
|
hmAvailable = lib.hasAttrByPath [ "home-manager" "users" ] options;
|
||||||
|
hmUsersAttr = lib.listToAttrs (
|
||||||
|
map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = usersLib.mkHmUserModule {
|
||||||
|
inherit name;
|
||||||
|
user = selected.${name};
|
||||||
|
hostExtraModules = cfg.extraModules.${name} or [ ];
|
||||||
|
};
|
||||||
|
}) names
|
||||||
|
);
|
||||||
|
inboundUsersAttr = usersLib.inboundHostsAttr selected;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkMerge [
|
||||||
|
{
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = missing == [ ];
|
||||||
|
message = "chiasson.users.enabled references unknown catalog users: ${builtins.concatStringsSep ", " missing}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = stray == [ ];
|
||||||
|
message = "chiasson.users.extraModules has keys not in chiasson.users.enabled: ${builtins.concatStringsSep ", " stray}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
users.users = lib.mapAttrs (name: user: usersLib.mkNixosUser name user) selected;
|
||||||
|
}
|
||||||
|
(lib.optionalAttrs hmAvailable {
|
||||||
|
"home-manager".useGlobalPkgs = lib.mkIf (cfg.homeManager.autoWire && names != [ ]) true;
|
||||||
|
"home-manager".sharedModules = lib.mkIf (cfg.homeManager.autoWire && names != [ ]) [ self.homeManagerModules.sshOutboundRbw ];
|
||||||
|
"home-manager".users = lib.mkIf (cfg.homeManager.autoWire && names != [ ]) hmUsersAttr;
|
||||||
|
})
|
||||||
|
(lib.mkIf (inboundUsersAttr != { }) {
|
||||||
|
chiasson.ssh.inbound.enable = true;
|
||||||
|
chiasson.ssh.inbound.userAuthorizedHosts = inboundUsersAttr;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user