"""Build a `.deb` for RigDoctor (M9 / D8) — dependency-light, no debhelper. Pure-Python app, so it's `Architecture: all`: we stage the package into dist-packages, drop the two launchers in /usr/bin, install the desktop entry + icon, write a DEBIAN/control, and call `dpkg-deb`. The core is stdlib (`Depends: python3`); the GUI/tray deps are **Recommends** (`python3-pyside6`, `python3-pyte`) so `apt install rigdoctor` gives the full app by default, while `--no-install-recommends` yields a CLI-only install. Run: `python packaging/make_deb.py` → `dist/rigdoctor__all.deb`. """ from __future__ import annotations import shutil import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] DIST = ROOT / "dist" MAINTAINER = "Jessey van Offeren " HOMEPAGE = "https://git.jesseyvanofferen.com/jessey/rigdoctor" def _version() -> str: text = (ROOT / "src" / "rigdoctor" / "__init__.py").read_text(encoding="utf-8") for line in text.splitlines(): if line.startswith("__version__"): return line.split('"')[1] raise SystemExit("could not read __version__") _LAUNCHER = """\ #!/usr/bin/python3 import sys from {module} import main sys.exit(main()) """ _DESKTOP = """\ [Desktop Entry] Type=Application Name=RigDoctor Comment=Hardware monitoring & crash diagnostics for Linux gamers Exec=rigdoctor-gui Icon=rigdoctor Terminal=false Categories=System;Monitor;Utility; StartupWMClass=rigdoctor """ _CONTROL = """\ Package: rigdoctor Version: {version} Architecture: all Maintainer: {maintainer} Section: utils Priority: optional Depends: python3 (>= 3.11) Recommends: python3-pyside6, python3-pyte Homepage: {homepage} Description: Hardware monitoring & crash diagnostics for Linux gamers RigDoctor monitors GPU/CPU temperatures, load, and sensors, captures crash diagnostics while gaming, scans logs (Xid/SMART/kernel) for problems, and can explain them in plain language. The CLI and background daemon are pure Python (stdlib only); the optional desktop GUI and system-tray applet use PySide6, pulled in via Recommends. Install with --no-install-recommends for CLI only. """ def _write(path: Path, text: str, mode: int = 0o644) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(text, encoding="utf-8") path.chmod(mode) def build() -> Path: version = _version() DIST.mkdir(exist_ok=True) stage = DIST / f"rigdoctor_{version}_all" if stage.exists(): shutil.rmtree(stage) # Python package → dist-packages (importable system-wide), minus bytecode. pkg_dst = stage / "usr/lib/python3/dist-packages/rigdoctor" shutil.copytree(ROOT / "src" / "rigdoctor", pkg_dst, ignore=shutil.ignore_patterns("__pycache__", "*.pyc")) # Launchers. _write(stage / "usr/bin/rigdoctor", _LAUNCHER.format(module="rigdoctor.cli"), 0o755) _write(stage / "usr/bin/rigdoctor-gui", _LAUNCHER.format(module="rigdoctor.gui.app"), 0o755) # Desktop entry + icon. _write(stage / "usr/share/applications/rigdoctor.desktop", _DESKTOP) icon = ROOT / "src" / "rigdoctor" / "gui" / "assets" / "rigdoctor.svg" _write(stage / "usr/share/icons/hicolor/scalable/apps/rigdoctor.svg", icon.read_text(encoding="utf-8")) # Refresh the desktop database on install/remove (best-effort). _write(stage / "DEBIAN/postinst", "#!/bin/sh\nset -e\nupdate-desktop-database -q 2>/dev/null || true\n", 0o755) _write(stage / "DEBIAN/postrm", "#!/bin/sh\nset -e\nupdate-desktop-database -q 2>/dev/null || true\n", 0o755) _write(stage / "DEBIAN/control", _CONTROL.format(version=version, maintainer=MAINTAINER, homepage=HOMEPAGE)) out = DIST / f"rigdoctor_{version}_all.deb" subprocess.run(["dpkg-deb", "--root-owner-group", "--build", str(stage), str(out)], check=True) shutil.rmtree(stage) return out if __name__ == "__main__": path = build() print(f"built {path}") sys.exit(0)