aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-20 11:43:02 +0200
committerDanilo M. <danix@danix.xyz>2026-10-20 11:43:02 +0200
commit5be93186f2a8ee04aa1fdc392a7e4bf0f513155e (patch)
treeeeeb4618dad73f51232eaf23d864cb95ab5d8c5f
parentdddf9edde7ad89ba358af482e7206749d9e16426 (diff)
downloadsb-builder-5be93186f2a8ee04aa1fdc392a7e4bf0f513155e.tar.gz
sb-builder-5be93186f2a8ee04aa1fdc392a7e4bf0f513155e.zip
Hints: Delete hint acts on the ticked packages, then offers Revert
Rows with only a stanza have no hint and are skipped. The deletes open the same dialog as a hint job: each removed hint's diff and Revert, which had no place in the GUI before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--README.md5
-rw-r--r--sb_builder/hints_tab.py30
-rw-r--r--sb_builder/mainwindow.py1
-rw-r--r--tests/test_gui.py12
4 files changed, 36 insertions, 12 deletions
diff --git a/README.md b/README.md
index 0659a12..366b740 100644
--- a/README.md
+++ b/README.md
@@ -65,9 +65,10 @@ Every key is optional. `File > Reload config` rereads the GUI config.
token) and ticks the outdated packages. **Update selected** rewrites their
hints on the VM (version, URLs, md5 of the downloaded source; **no download**
writes `DOWNLOAD="no"` instead; a hint sbshadow wrote, `DELREQUIRES` only,
- gets the `.info` version lines added). **Delete hint** keeps a `.bak`. The Packages detail pane has **New hint** for a package
+ gets the `.info` version lines added). **Delete hint** removes the ticked
+ packages' hints, each kept as a `.bak`. The Packages detail pane has **New hint** for a package
without one.
-- After a hint job a dialog shows the diff of each changed hint, with
+- After a hint job or a delete a dialog shows the diff of each changed hint, with
**Revert** per package and **Build these** (a slackrepo update preview).
neovim and openvino are refused for now: their bundled deps still need
mkhint on the VM.
diff --git a/sb_builder/hints_tab.py b/sb_builder/hints_tab.py
index bf2011a..b78ec69 100644
--- a/sb_builder/hints_tab.py
+++ b/sb_builder/hints_tab.py
@@ -38,6 +38,7 @@ HINT_JOBS = ("hint-update", "hint-new")
class HintsTab(QWidget):
start_requested = pyqtSignal(list) # job-start arguments
+ result_ready = pyqtSignal(dict) # {"ok", "failed"} of hint changes made here, for the dialog
def __init__(self, remote, cfg, stanzas=upstream.STANZAS, parent=None):
super().__init__(parent)
@@ -201,17 +202,26 @@ class HintsTab(QWidget):
if pairs:
self.start_requested.emit(["hint-update", *pairs] + (["--no-dl"] if self.no_dl.isChecked() else []))
- def delete(self):
- name = self.current()
- if name and QMessageBox.question(self, "Delete hint", f"Delete the hint of {name}? "
- "(kept as .bak, Revert restores it)") \
- == QMessageBox.StandardButton.Yes:
- self.remote.call(self._changed, "hint-delete", name)
+ def confirm(self, title, text):
+ return QMessageBox.question(self, title, text) == QMessageBox.StandardButton.Yes
- def _changed(self, _data, err):
- if err:
- QMessageBox.warning(self, "Hint", err)
- self.reload()
+ def delete(self):
+ """Delete the hints of the ticked packages, then the dialog to revert them."""
+ ticked = set(self.checked())
+ names = [r["name"] for r in self.rows if r["name"] in ticked and r["hint_path"]]
+ if not names or not self.confirm(
+ "Delete hint", f"Delete the hint of {len(names)} package(s): {', '.join(names)}?\n"
+ "Each is kept as .bak; the next dialog can revert it."):
+ return
+ result = {"ok": [], "failed": []}
+
+ def done(name, err):
+ (result["failed"].append([name, err]) if err else result["ok"].append(name))
+ if len(result["ok"]) + len(result["failed"]) == len(names):
+ self.reload()
+ self.result_ready.emit(result)
+ for name in names:
+ self.remote.call(lambda _d, err, n=name: done(n, err), "hint-delete", name)
class DiffColors(QSyntaxHighlighter):
diff --git a/sb_builder/mainwindow.py b/sb_builder/mainwindow.py
index 0331eb9..eeac61a 100644
--- a/sb_builder/mainwindow.py
+++ b/sb_builder/mainwindow.py
@@ -337,6 +337,7 @@ class MainWindow(QMainWindow):
if self.hints_tab is None:
self.hints_tab = HintsTab(self.remote, self.cfg)
self.hints_tab.start_requested.connect(lambda args: self.open_jobs().start(*args))
+ self.hints_tab.result_ready.connect(self.show_hint_result)
self.tabs.addTab(self.hints_tab, "Hints")
self.hints_tab.reload()
if name:
diff --git a/tests/test_gui.py b/tests/test_gui.py
index d45fffd..1f3f7b0 100644
--- a/tests/test_gui.py
+++ b/tests/test_gui.py
@@ -513,6 +513,18 @@ class SmokeTest(unittest.TestCase):
self.assertEqual(tab.table.item(row, 5).toolTip(), "HTTPError(404)")
self.assertIs(w.open_hints("foo"), tab)
self.assertEqual(tab.current(), "foo")
+ tab.check_rows(False)
+ tab.confirm = lambda title, text: self.fail("asked with nothing to delete")
+ tab.delete() # nothing ticked
+ tab.check_rows(True) # foo has a hint; nuclei and curl have only a stanza
+ asked = []
+ tab.confirm = lambda title, text: asked.append(text) or True
+ remote.answers["hint-diff"] = ({"bak": "A=1\n", "current": None}, None)
+ tab.delete()
+ self.assertIn("1 package(s): foo", asked[0])
+ self.assertEqual([c for c in remote.calls if c[0] == "hint-delete"], [("hint-delete", "foo")])
+ self.assertEqual(len(w.hint_dialogs), 1) # Revert lives there
+ self.assertIn("-A=1", w.hint_dialogs[0].diff.toPlainText())
def test_hint_job_end_opens_diff(self):
job = dict(JOB, id="20260101-000000-hint-update", kind="hint-update", args=["nuclei=3.12.0"])