"""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, symlinks: dict[str, str] | None = None, user: str = "alex", ) -> None: super().__init__(f"user:{name}") self._files = files or {} self._directories = directories or {} self._symlinks = symlinks 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() } def symlinks(self) -> dict[str, str | decman.Symlink]: return { link_name: decman.Symlink(target=target, owner=self.user) for link_name, target in self._symlinks.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/rofi/breeze-dark.rasi": "config/user/common/rofi/breeze-dark.rasi", "/home/alex/.config/rofi/config.rasi": "config/user/common/rofi/config.rasi", "/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" ), }, symlinks={ "/home/alex/.config/hypr/intel-drm": ( "/dev/dri/by-path/pci-0000:00:02.0-card" ), }, ) ] 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/modprobe.d/nvidia-runtime-pm.conf": "config/system/laptop/modprobe.d/nvidia-runtime-pm.conf", "/etc/udev/rules.d/80-nvidia-runtime-pm.rules": "config/system/laptop/udev/80-nvidia-runtime-pm.rules", "/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(), ]