From be69467c2caefddc1f04d5be71d36f6b8d9c13d3 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 21 Oct 2026 10:32:55 +0200 Subject: sbb-remote 0.11.0: rebuild-tree job (phase 3) New job kind rebuild-tree runs slackrepo_setup_SBo-danix.sh, which now builds the fresh tree beside the live one and swaps it in. The Jobs tab gets a Rebuild tree action behind a modal confirm. Co-Authored-By: Claude Opus 5.5 --- README.md | 7 +++++-- docs/design/2026-10-20-sb-builder-ui-design.md | 2 +- remote/sbb-remote | 10 ++++++++-- sb_builder/__init__.py | 2 +- sb_builder/jobs.py | 10 ++++++++++ tests/test_gui.py | 13 ++++++++++++- tests/test_remote.py | 5 +++++ 7 files changed, 42 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 13a5a9e..b93a826 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ The design, one spec per phase, is in `docs/design/`. - Desktop: Python 3.11 or newer, PyQt6 (with QtDBus), ssh access to the VM, optionally `virsh` for starting the VM and `nvchecker` for upstream checks - VM: Python 3.11 or newer, root ssh login, the - [slackrepo_setup](https://forge.slackware.nl/danix/slackrepo_setup) tools (`sbpull`, `sbshadow`) + [slackrepo_setup](https://forge.slackware.nl/danix/slackrepo_setup) tools (`sbpull`, `sbshadow`, + `slackrepo_setup_SBo-danix.sh`) ## VM setup @@ -137,7 +138,9 @@ reopens it. - **Jobs**: every job with its live log. **Pull overlay** (`sbpull `) and **Check shadowing** (`sbshadow`) run as previews; when one finds `shadow:` or `unshadow:` lines, its dialog offers **Apply shadowing**. - **Kill** stops the selected running job. + **Rebuild tree** (after a confirm) replaces the SBo-danix tree with a fresh + clone of upstream and the overlays (`slackrepo_setup_SBo-danix.sh`); the live + tree stays until the new one is ready. **Kill** stops the selected running job. - Real runs sign the repository. When the package signing key is locked (status bar 🔒), the GUI asks for its passphrase first and hands it to the VM's gpg-agent; it is never stored. diff --git a/docs/design/2026-10-20-sb-builder-ui-design.md b/docs/design/2026-10-20-sb-builder-ui-design.md index 826c6f9..80df13c 100644 --- a/docs/design/2026-10-20-sb-builder-ui-design.md +++ b/docs/design/2026-10-20-sb-builder-ui-design.md @@ -60,7 +60,7 @@ filter bar first), status bar. | Packages | Build, Update, Rebuild, Remove, Update all, New hint, Publish | Select visible, Clear, Refresh | | Hints | Check upstream, Update selected, Delete hint | Select visible, Clear, No download (checkable), Refresh | | Results | Show build log | Refresh | -| Jobs | Pull overlay (menu: one entry per overlay), Check shadowing, Run it, Kill | none | +| Jobs | Pull overlay (menu: one entry per overlay), Check shadowing, Rebuild tree, Run it, Kill | none | Disabled reasons (tooltips): diff --git a/remote/sbb-remote b/remote/sbb-remote index cabb8d1..ace4fb9 100755 --- a/remote/sbb-remote +++ b/remote/sbb-remote @@ -41,7 +41,7 @@ import time import tomllib import urllib.request -VERSION = "0.10.0" +VERSION = "0.11.0" DEFAULTS = { "state_dir": "/var/lib/sb-builder", "repo_dir": "/var/lib/sbopkg/SBo-danix", @@ -155,6 +155,12 @@ def kind_publish(cfg, args): return ["sb-publish"], {} +def kind_rebuild_tree(cfg, args): + if args: + raise Error("rebuild-tree takes no arguments") + return ["slackrepo_setup_SBo-danix.sh"], {} + + def _pkgmap(cfg): """{package: category/package} of the repo.""" return {os.path.basename(d): os.path.relpath(d, cfg["repo_dir"]) @@ -216,7 +222,7 @@ def _self_job(kind): KINDS = {"sbpull": kind_sbpull, "sbshadow": kind_sbshadow, - "slackrepo": kind_slackrepo, "publish": kind_publish, + "slackrepo": kind_slackrepo, "publish": kind_publish, "rebuild-tree": kind_rebuild_tree, **{k: _self_job(k) for k in ("hint-update", "hint-new", "fix-current")}} diff --git a/sb_builder/__init__.py b/sb_builder/__init__.py index 267ce94..87e7f4e 100644 --- a/sb_builder/__init__.py +++ b/sb_builder/__init__.py @@ -16,4 +16,4 @@ """sb-builder: Qt6 GUI driving the SlackBuild tooling on a build VM.""" -VERSION = "0.10.0" # must match remote/sbb-remote VERSION +VERSION = "0.11.0" # must match remote/sbb-remote VERSION diff --git a/sb_builder/jobs.py b/sb_builder/jobs.py index 111d804..9bfa2e3 100644 --- a/sb_builder/jobs.py +++ b/sb_builder/jobs.py @@ -134,6 +134,8 @@ class JobsTab(QWidget): self.actions = [self.act_pull, action(self, "Check shadowing", "edit-find", SP.SP_FileDialogContentsView, lambda: self.start("sbshadow", "--no")), + action(self, "Rebuild tree", "edit-clear-all", SP.SP_DialogResetButton, + self.rebuild_tree), self.act_run, self.act_kill] self.view_actions = [] @@ -206,6 +208,14 @@ class JobsTab(QWidget): self.pending = args self.remote.call(self._started, "job-start", *args) + def confirm(self, question): + return QMessageBox.question(self, "Confirm", question) == QMessageBox.StandardButton.Yes + + def rebuild_tree(self): + if self.confirm("Replace SBo-danix with a fresh clone of upstream and the overlays, " + "then reapply shadowing?"): + self.start("rebuild-tree") + def kill(self): if QMessageBox.question(self, "Kill job", f"Send SIGTERM to {self.current}?") \ == QMessageBox.StandardButton.Yes: diff --git a/tests/test_gui.py b/tests/test_gui.py index c89dc86..aa6d681 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -602,6 +602,17 @@ class SmokeTest(unittest.TestCase): d.run_btn.click() self.assertIn(("job-start", "sbshadow", "--yes"), remote.calls) + def test_rebuild_tree_confirms(self): + w, remote = self.window(**{"job-start": ({"id": "20260101-000001-rebuild-tree"}, None)}) + tab = w.jobs_tab + act = next(a for a in tab.actions if a.text() == "Rebuild tree") + tab.confirm = lambda q: False + act.trigger() + self.assertNotIn(("job-start", "rebuild-tree"), remote.calls) + tab.confirm = lambda q: True + act.trigger() + self.assertIn(("job-start", "rebuild-tree"), remote.calls) + def test_jobs_tab_badge(self): w, remote = self.window(jobs=({"jobs": [JOB]}, None)) w.poll_jobs() @@ -705,7 +716,7 @@ class SmokeTest(unittest.TestCase): ["Select visible", "Clear", "No download", "Refresh"]), "Results": (["Show build log"], ["Refresh"]), "Repository": ([], ["Refresh"]), - "Jobs": (["Pull overlay", "Check shadowing", "Run it", "Kill"], []), + "Jobs": (["Pull overlay", "Check shadowing", "Rebuild tree", "Run it", "Kill"], []), } for i in range(w.tabs.count()): w.tabs.setCurrentIndex(i) diff --git a/tests/test_remote.py b/tests/test_remote.py index 3ac584a..44d3a90 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -177,6 +177,11 @@ class KindsTest(Base): with self.assertRaises(sbb.Error): sbb.KINDS["publish"](self.cfg, ["x"]) + def test_rebuild_tree(self): + self.assertEqual(sbb.KINDS["rebuild-tree"](self.cfg, []), (["slackrepo_setup_SBo-danix.sh"], {})) + with self.assertRaises(sbb.Error): + sbb.KINDS["rebuild-tree"](self.cfg, ["--yes"]) + def test_rejects_bad_args(self): for kind, args in (("sbpull", ["evil", "--no"]), ("sbpull", ["personal"]), ("sbpull", ["personal", "--force"]), ("sbshadow", []), -- cgit v1.2.3