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.
98 lines
4.7 KiB
Python
Executable File
98 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Generate disjoint, concern-scoped package lists from the current machine."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Final
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PACKAGES = ROOT / "packages"
|
|
|
|
# A concern is reusable; a machine profile composes concerns elsewhere.
|
|
# Every installed explicit package must be assigned exactly once on this laptop.
|
|
CONCERNS: Final = {
|
|
"common/core": """base base-devel linux linux-firmware linux-headers cryptsetup refind
|
|
arch-install-scripts git yadm openssh man-db jq ripgrep fd fzf 7zip unzip rsync
|
|
ntfs-3g os-prober fwupd fish zsh zellij zoxide htop glances starship cowsay ex-vi-compat
|
|
mtools dmidecode libsmbios catdoc odt2txt hunspell-de""",
|
|
"common/wayland": """hyprland hypridle hyprlock xdg-desktop-portal-hyprland
|
|
pipewire-alsa pipewire-pulse wireplumber pavucontrol pamixer mako waybar wofi grim
|
|
slurp satty wl-clipboard wlr-randr alacritty kitty tmux neovim vim yazi ueberzugpp
|
|
flameshot playerctl rofi bluez bluez-utils blueman gnome-keyring xorg-xwayland
|
|
noctalia-git ranger-git""",
|
|
"common/fonts": """noto-fonts noto-fonts-cjk noto-fonts-emoji ttf-jetbrains-mono-nerd
|
|
ttf-icomoon-feather ttf-meslo-nerd-font-powerlevel10k""",
|
|
"common/development": """nodejs npm yarn python python-pip pyenv uv rust cargo go ruby
|
|
jdk-openjdk docker docker-compose podman vagrant virtualbox virtualbox-host-dkms
|
|
cloudflared openbsd-netcat pycharm postman-bin mongodb-compass-bin pi engram-bin
|
|
decman yay gti fcron""",
|
|
"common/productivity": """brave-bin firefox chromium thunderbird obsidian bitwarden
|
|
nextcloud-client signal-desktop telegram-desktop libreoffice-fresh evince okular
|
|
nomacs zotero-bin qalculate-gtk qalculate-qt qbittorrent teams teamspeak3 cerebro-bin chatgtk
|
|
torbrowser-launcher spotify""",
|
|
"common/media": """vlc mpv smplayer audacity imagemagick steam cudnn""",
|
|
"common/research": """biber r texlive-basic texlive-bibtexextra texlive-binextra
|
|
texlive-context texlive-fontsextra texlive-fontsrecommended texlive-fontutils
|
|
texlive-formatsextra texlive-games texlive-humanities texlive-latex texlive-latexextra
|
|
texlive-latexrecommended texlive-luatex texlive-mathscience texlive-metapost
|
|
texlive-music texlive-pictures texlive-plaingeneric texlive-pstricks texlive-publishers
|
|
texlive-xetex resvg""",
|
|
"common/network": """networkmanager network-manager-applet avahi nss-mdns gvfs-smb
|
|
cups cups-pdf mullvad-vpn-beta-bin""",
|
|
"common/hardware": """keyd mesa-utils nvidia-open nvtop vulkan-tools""",
|
|
"desktop/local": """bun fakeroot geoclue github-cli gtk4-layer-shell lsof
|
|
lvm2 mpv numlockx nvidia-container-toolkit nvidia-settings ollama-cuda opencode
|
|
perl-yaml-tiny pipewire powerline qpwgraph ranger retry rustup screengrab seahorse
|
|
sudo sway texlive-bin texlive-meta tree ttf-meslo-nerd unrar vlc-plugins-all
|
|
vulkan-radeon wdisplays wget xournalpp beads downgrade nomacs-git yay-debug
|
|
zsa-keymapp-bin""",
|
|
"laptop/hardware": """intel-ucode thermald tlp tlp-pd tlp-rdw powertop psensor lm_sensors
|
|
ddcutil intel-gpu-tools intel-media-driver vulkan-intel
|
|
nvidia-prime envycontrol light nwg-displays
|
|
wireless_tools caffeine woeusb""",
|
|
"common/services": """sddm pcmanfm libva-utils""",
|
|
}
|
|
|
|
|
|
def explicit(command: str) -> set[str]:
|
|
return set(
|
|
subprocess.run(
|
|
["pacman", command], check=True, text=True, stdout=subprocess.PIPE
|
|
).stdout.split()
|
|
)
|
|
|
|
|
|
def write(path: Path, values: set[str]) -> None:
|
|
resolved = path.resolve()
|
|
package_root = PACKAGES.resolve()
|
|
if package_root not in resolved.parents:
|
|
raise ValueError(f"refusing to write outside packages: {path}")
|
|
resolved.parent.mkdir(parents=True, exist_ok=True)
|
|
resolved.write_text("\n".join(sorted(values)) + "\n", encoding="utf-8")
|
|
|
|
|
|
def main() -> None:
|
|
official, aur = explicit("-Qqen"), explicit("-Qqem")
|
|
assigned: set[str] = set()
|
|
for name, raw in CONCERNS.items():
|
|
selected = set(raw.split()) & (official | aur)
|
|
overlap = selected & assigned
|
|
if overlap:
|
|
raise SystemExit(f"duplicate ownership in {name}: {sorted(overlap)}")
|
|
assigned |= selected
|
|
write(PACKAGES / f"{name}-repo.txt", selected & official)
|
|
write(PACKAGES / f"{name}-aur.txt", selected & aur)
|
|
remaining = (official | aur) - assigned
|
|
if remaining:
|
|
raise SystemExit(
|
|
"unclassified explicit packages; add them to a named concern: "
|
|
+ ", ".join(sorted(remaining))
|
|
)
|
|
print(f"assigned={len(assigned)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|