diff --git a/CHANGELOG.md b/CHANGELOG.md index e47820e..85b4438 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to RigDoctor are recorded here. Format follows (`MAJOR.MINOR.PATCH`, pre-1.0). `__version__` and `pyproject.toml` must match the git release tag (so the auto-updater, D18, can compare versions). +## [0.10.2] - 2026-05-22 +### Changed +- When an Environment **Apply**/**Install** fails, the status now shows the **real reason** + (cancelled at the password prompt vs. the system rejecting the change, e.g. a BIOS/kernel- + locked PCIe ASPM policy) instead of a vague "cancelled, or needs privileges". + ## [0.10.1] - 2026-05-22 ### Fixed - **Environment-page contrast.** The combo-box **drop-down list** was rendering light-on-light diff --git a/pyproject.toml b/pyproject.toml index 7f0b07c..4930e12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "rigdoctor" -version = "0.10.1" +version = "0.10.2" description = "Modular hardware monitoring & crash diagnostics for Linux gamers." readme = "README.md" requires-python = ">=3.11" diff --git a/src/rigdoctor/__init__.py b/src/rigdoctor/__init__.py index 49185aa..2a05370 100644 --- a/src/rigdoctor/__init__.py +++ b/src/rigdoctor/__init__.py @@ -1,3 +1,3 @@ """RigDoctor — modular hardware monitoring & crash diagnostics for Linux gamers.""" -__version__ = "0.10.1" +__version__ = "0.10.2" diff --git a/src/rigdoctor/gui/environment_page.py b/src/rigdoctor/gui/environment_page.py index 598497b..3e04b85 100644 --- a/src/rigdoctor/gui/environment_page.py +++ b/src/rigdoctor/gui/environment_page.py @@ -19,9 +19,20 @@ from PySide6.QtWidgets import ( from .widgets import finding_card +def _fail_reason(out: str) -> str: + """Turn the failed command's output into a short, human reason.""" + low = (out or "").lower() + if "not authorized" in low or "dismissed" in low or "authentication" in low: + return "cancelled at the password prompt" + if "operation not permitted" in low or "invalid argument" in low or "permission denied" in low: + return "the system rejected the change (it may be locked by BIOS/kernel)" + last = next((ln.strip() for ln in reversed((out or "").splitlines()) if ln.strip()), "") + return (last[:80] or "no privileges, or cancelled") + + class EnvironmentPage(QWidget): _result = Signal(object) # list[Finding] - _action_done = Signal(object) # (label, rc) — install or apply finished + _action_done = Signal(object) # (label, rc, output) — install or apply finished def __init__(self) -> None: super().__init__() @@ -117,8 +128,8 @@ class EnvironmentPage(QWidget): def _work_install(self, component) -> None: from ..core import installer - rc, _out = installer.install_packages(list(component.apt)) - self._action_done.emit((component.name, rc)) + rc, out = installer.install_packages(list(component.apt)) + self._action_done.emit((component.name, rc, out)) def _apply(self, fix_id: str, value: str) -> None: if self._busy: @@ -131,15 +142,15 @@ class EnvironmentPage(QWidget): def _work_apply(self, fix_id: str, value: str) -> None: from ..core import fixes - rc, _out = fixes.apply(fix_id, value) - self._action_done.emit((value, rc)) + rc, out = fixes.apply(fix_id, value) + self._action_done.emit((value, rc, out)) def _on_action_done(self, result) -> None: - label, rc = result + label, rc, out = result self._busy = False if rc == 0: self._status.setText(f"{label} applied — re-checking…") self._run() # re-run so the finding reflects the new state else: self._run_btn.setEnabled(True) - self._status.setText(f"'{label}' failed (cancelled, or needs privileges)") + self._status.setText(f"'{label}' failed — {_fail_reason(out)}")