ed063ab1fe
Capture desktop-specific system, session, Noctalia, and Pi integration alongside shared laptop support. Retire obsolete X11 configuration and make package ownership explicit for repeatable Decman deployments.
295 lines
11 KiB
Python
295 lines
11 KiB
Python
"""System files and concern-scoped unit enablement for machine profiles."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import decman
|
|
from decman.plugins import systemd
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MANIFESTS = ROOT / "manifests"
|
|
|
|
|
|
def _units(*names: str) -> set[str]:
|
|
units: set[str] = set()
|
|
for name in names:
|
|
units |= {
|
|
line.strip()
|
|
for line in (MANIFESTS / name).read_text(encoding="utf-8").splitlines()
|
|
if line.strip()
|
|
}
|
|
return units
|
|
|
|
|
|
class UserConfigConcern(decman.Module):
|
|
"""Home-directory configuration owned by a named local user."""
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
files: dict[str, str | tuple[str, int]] | None = None,
|
|
directories: dict[str, str] | None = None,
|
|
user: str = "alex",
|
|
) -> None:
|
|
super().__init__(f"user:{name}")
|
|
self._files = files or {}
|
|
self._directories = directories or {}
|
|
self.user = user
|
|
|
|
def files(self) -> dict[str, decman.File]:
|
|
return {
|
|
target: decman.File(
|
|
source_file=str(
|
|
ROOT / (source[0] if isinstance(source, tuple) else source)
|
|
),
|
|
owner=self.user,
|
|
permissions=source[1] if isinstance(source, tuple) else 0o644,
|
|
)
|
|
for target, source in self._files.items()
|
|
}
|
|
|
|
def directories(self) -> dict[str, decman.Directory]:
|
|
return {
|
|
target: decman.Directory(
|
|
source_directory=str(ROOT / source),
|
|
bin_files=True,
|
|
owner=self.user,
|
|
permissions=0o644,
|
|
)
|
|
for target, source in self._directories.items()
|
|
}
|
|
|
|
|
|
class SystemConcern(decman.Module):
|
|
"""One host/system concern with explicit files and unit manifests."""
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
files: dict[str, str | tuple[str, int]] | None = None,
|
|
system_manifests: tuple[str, ...] = (),
|
|
user_manifests: tuple[str, ...] = (),
|
|
user: str = "alex",
|
|
) -> None:
|
|
super().__init__(f"system:{name}")
|
|
self._files = files or {}
|
|
self._system_manifests = system_manifests
|
|
self._user_manifests = user_manifests
|
|
self.user = user
|
|
|
|
def files(self) -> dict[str, decman.File]:
|
|
return {
|
|
target: decman.File(
|
|
source_file=str(
|
|
ROOT / (source[0] if isinstance(source, tuple) else source)
|
|
),
|
|
permissions=source[1] if isinstance(source, tuple) else 0o644,
|
|
)
|
|
for target, source in self._files.items()
|
|
}
|
|
|
|
def on_change(self, store: decman.Store) -> None:
|
|
if self.name == "system:locale":
|
|
decman.prg(["locale-gen"])
|
|
if self.name == "system:boot":
|
|
decman.prg(["mkinitcpio", "-P"])
|
|
|
|
@systemd.units
|
|
def system_units(self) -> set[str]:
|
|
return _units(*self._system_manifests)
|
|
|
|
@systemd.user_units
|
|
def user_units(self) -> dict[str, set[str]]:
|
|
return {self.user: _units(*self._user_manifests)}
|
|
|
|
|
|
def common_user_config() -> list[UserConfigConcern]:
|
|
return [
|
|
UserConfigConcern(
|
|
"common-config",
|
|
{
|
|
"/home/alex/.config/environment.d/pi-status-bridge.conf": (
|
|
"config/user/common/environment.d/pi-status-bridge.conf"
|
|
),
|
|
"/home/alex/.config/fish/config.fish": "config/user/common/fish/config.fish",
|
|
"/home/alex/.config/hypr/hypridle.conf": "config/user/common/hypr/hypridle.conf",
|
|
"/home/alex/.config/hypr/hyprland.lua": "config/user/common/hypr/hyprland.lua",
|
|
"/home/alex/.config/hypr/hyprlock.conf": "config/user/common/hypr/hyprlock.conf",
|
|
"/home/alex/.config/kitty/kitty.conf": "config/user/common/kitty/kitty.conf",
|
|
"/home/alex/.config/mimeapps.list": "config/user/common/mime/mimeapps.list",
|
|
"/home/alex/.config/noctalia/10-base.toml": "config/user/common/noctalia/10-base.toml",
|
|
"/home/alex/.config/noctalia/palettes/Ember OLED.json": (
|
|
"config/user/common/noctalia/palettes/Ember OLED.json"
|
|
),
|
|
"/home/alex/.config/systemd/user/idle-inhibitor-monitor.service": (
|
|
"config/user/common/systemd/user/idle-inhibitor-monitor.service"
|
|
),
|
|
"/home/alex/.config/systemd/user/pi-status-bridge.service": (
|
|
"config/user/common/systemd/user/pi-status-bridge.service"
|
|
),
|
|
"/home/alex/.config/systemd/user/ssh-agent.service": (
|
|
"config/user/common/systemd/user/ssh-agent.service"
|
|
),
|
|
"/home/alex/.config/user-dirs.dirs": "config/user/common/user-dirs/user-dirs.dirs",
|
|
"/home/alex/.local/bin/idle-inhibitor-monitor": (
|
|
"config/user/common/bin/idle-inhibitor-monitor",
|
|
0o755,
|
|
),
|
|
"/home/alex/.local/bin/pi-status-ui": (
|
|
"config/user/common/bin/pi-status-ui",
|
|
0o755,
|
|
),
|
|
"/home/alex/.local/bin/wayshell-blanker": (
|
|
"config/user/common/bin/wayshell-blanker",
|
|
0o755,
|
|
),
|
|
},
|
|
{
|
|
"/home/alex/.config/alacritty": "config/user/common/alacritty",
|
|
"/home/alex/.config/yazi": "config/user/common/yazi",
|
|
"/home/alex/.local/share/noctalia/plugins/knowledge-lookup": (
|
|
"config/user/common/noctalia/plugins/knowledge-lookup"
|
|
),
|
|
"/home/alex/.local/share/noctalia/plugins/pi-status-bridge": (
|
|
"config/user/common/noctalia/plugins/pi-status-bridge"
|
|
),
|
|
"/home/alex/.local/share/noctalia/plugins/system-status": (
|
|
"config/user/common/noctalia/plugins/system-status"
|
|
),
|
|
},
|
|
)
|
|
]
|
|
|
|
|
|
def laptop_user_config() -> list[UserConfigConcern]:
|
|
return [
|
|
UserConfigConcern(
|
|
"laptop-config",
|
|
{
|
|
"/home/alex/.config/hypr/machine.lua": "config/user/laptop/hypr/machine.lua",
|
|
"/home/alex/.config/noctalia/90-machine.toml": (
|
|
"config/user/laptop/noctalia/90-machine.toml"
|
|
),
|
|
"/home/alex/.config/noctalia/99-extend.toml": (
|
|
"config/user/laptop/noctalia/99-extend.toml"
|
|
),
|
|
},
|
|
)
|
|
]
|
|
|
|
|
|
def desktop_user_config() -> list[UserConfigConcern]:
|
|
return [
|
|
UserConfigConcern(
|
|
"desktop-config",
|
|
{
|
|
"/home/alex/.config/hypr/machine.lua": "config/user/desktop/hypr/machine.lua",
|
|
"/home/alex/.config/noctalia/90-machine.toml": (
|
|
"config/user/desktop/noctalia/90-machine.toml"
|
|
),
|
|
},
|
|
)
|
|
]
|
|
|
|
|
|
def common_system() -> list[SystemConcern | UserConfigConcern]:
|
|
return [
|
|
SystemConcern(
|
|
"package-policy",
|
|
{
|
|
"/etc/pacman.conf": "config/system/common/pacman/pacman.conf",
|
|
"/etc/makepkg.conf": "config/system/common/makepkg/makepkg.conf",
|
|
},
|
|
),
|
|
SystemConcern(
|
|
"locale",
|
|
{
|
|
"/etc/locale.conf": "config/system/common/locale/locale.conf",
|
|
"/etc/locale.gen": "config/system/common/locale/locale.gen",
|
|
},
|
|
),
|
|
SystemConcern(
|
|
"keyboard",
|
|
{
|
|
"/etc/vconsole.conf": "config/system/common/keyboard/vconsole.conf",
|
|
"/etc/X11/xorg.conf.d/00-keyboard.conf": "config/system/common/keyboard/x11.conf",
|
|
},
|
|
),
|
|
SystemConcern("base", system_manifests=("common/base-system.txt",)),
|
|
SystemConcern("network", system_manifests=("common/network-system.txt",)),
|
|
SystemConcern("desktop", user_manifests=("common/desktop-user.txt",)),
|
|
SystemConcern("local", user_manifests=("common/local-user.txt",)),
|
|
SystemConcern(
|
|
"network-services", system_manifests=("common/network-services-system.txt",)
|
|
),
|
|
SystemConcern(
|
|
"development", system_manifests=("common/development-system.txt",)
|
|
),
|
|
SystemConcern("privacy", system_manifests=("common/privacy-system.txt",)),
|
|
*common_user_config(),
|
|
]
|
|
|
|
|
|
def laptop_system() -> list[SystemConcern | UserConfigConcern]:
|
|
return [
|
|
*common_system(),
|
|
SystemConcern(
|
|
"laptop",
|
|
{
|
|
"/etc/keyd/default.conf": "config/system/common/keyd.conf",
|
|
"/etc/NetworkManager/conf.d/wifi-powersave.conf": "config/system/laptop/wifi-powersave.conf",
|
|
"/etc/modprobe.d/iwlwifi.conf": "config/system/laptop/iwlwifi.conf",
|
|
"/etc/X11/xorg.conf.d/30-touchpad.conf": "config/system/laptop/touchpad.conf",
|
|
"/etc/tlp.conf": "config/system/laptop/power/tlp.conf",
|
|
"/etc/systemd/sleep.conf.d/90-laptop.conf": "config/system/laptop/sleep.conf.d/90-laptop.conf",
|
|
"/etc/systemd/logind.conf.d/90-noctalia-battery-idle.conf": "config/system/laptop/systemd/90-noctalia-battery-idle.conf",
|
|
"/boot/EFI/refind/refind.conf": (
|
|
"config/system/laptop/refind/refind.conf",
|
|
0o755,
|
|
),
|
|
"/boot/refind_linux.conf": (
|
|
"config/system/laptop/refind/refind_linux.conf",
|
|
0o755,
|
|
),
|
|
},
|
|
system_manifests=("laptop/hardware-system.txt",),
|
|
),
|
|
SystemConcern(
|
|
"boot",
|
|
{"/etc/mkinitcpio.conf": "config/system/laptop/boot/mkinitcpio.conf"},
|
|
),
|
|
*laptop_user_config(),
|
|
]
|
|
|
|
|
|
def desktop_system() -> list[SystemConcern | UserConfigConcern]:
|
|
"""Desktop: shared policy plus this host's boot, GPU, input, and session state."""
|
|
return [
|
|
*common_system(),
|
|
SystemConcern(
|
|
"desktop-host",
|
|
{
|
|
"/etc/fstab": "config/system/desktop/storage/fstab",
|
|
"/etc/hostname": "config/system/desktop/identity/hostname",
|
|
"/etc/keyd/default.conf": "config/system/desktop/input/keyd.conf",
|
|
"/etc/modprobe.d/nvidia-pm.conf": "config/system/desktop/nvidia/nvidia-pm.conf",
|
|
"/etc/NetworkManager/NetworkManager.conf": (
|
|
"config/system/desktop/network/NetworkManager.conf"
|
|
),
|
|
"/etc/sddm.conf.d/10-theme.conf": "config/system/desktop/sddm/10-theme.conf",
|
|
"/etc/udev/rules.d/50-zsa.rules": "config/system/desktop/input/50-zsa.rules",
|
|
},
|
|
system_manifests=("desktop/hardware-system.txt",),
|
|
),
|
|
SystemConcern(
|
|
"boot",
|
|
{
|
|
"/boot/EFI/refind/refind.conf": "config/system/desktop/boot/refind.conf",
|
|
"/boot/refind_linux.conf": "config/system/desktop/boot/refind_linux.conf",
|
|
"/etc/mkinitcpio.conf": "config/system/desktop/boot/mkinitcpio.conf",
|
|
},
|
|
),
|
|
*desktop_user_config(),
|
|
]
|