From 993950b7733ba9300915955ec6e51e1f21dad806 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 19 Oct 2026 21:28:54 +0200 Subject: Results tab with build logs; count only real packages sbb-remote 0.4.0: results lists slackrepo's last attempt per package (newest first, with built version and whether a log dir exists), and build-log returns the end of a package's build.log (512 KB) plus its resource.log, accepting only category/pkg paths. Result counts skip the legacy buildresults rows keyed by package file name: the 213 "bad" on the Dashboard matched no package. GUI: a Results tab (chips per result, table sorted by attempt time, detail pane, log viewer window that keeps the failure at the end), opened from the ribbon or by clicking a result in the Dashboard bar or legend, filtered to it. Co-Authored-By: Claude Opus 5.5 --- remote/sbb-remote | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'remote/sbb-remote') diff --git a/remote/sbb-remote b/remote/sbb-remote index d82120a..a3b83a6 100755 --- a/remote/sbb-remote +++ b/remote/sbb-remote @@ -38,7 +38,7 @@ import tempfile import time import tomllib -VERSION = "0.3.0" +VERSION = "0.4.0" DEFAULTS = { "state_dir": "/var/lib/sb-builder", "repo_dir": "/var/lib/sbopkg/SBo-danix", @@ -50,6 +50,7 @@ DEFAULTS = { "hintdir": "/etc/slackrepo/SBo-danix/hintfiles", "default_hintdir": "", "genreprc": "/root/.genreprc", + "slackrepo_logdir": "/var/log/slackrepo/SBo-danix", } FLAGS = ("--yes", "--no") JOB_ID = re.compile(r"^\d{8}-\d{6}-[a-z]+(-\d+)?$") @@ -57,6 +58,8 @@ PKG = re.compile(r"^[^/]+/([^/]+)/\1\.SlackBuild$") PKGNAME = re.compile(r"^[A-Za-z0-9._+-]+$") ACTIONS = ("build", "rebuild", "update", "remove") PRESET = "/usr/libexec/gpg-preset-passphrase" +ITEM = re.compile(r"^[A-Za-z0-9._+-]+/[A-Za-z0-9._+-]+$") # category/pkg +LOG_TAIL = 512 * 1024 # bytes of build.log returned; the failure is at the end ACTIVE = ("starting", "running") START_GRACE = 10 # seconds a job may sit in "starting" before it counts as lost @@ -346,7 +349,9 @@ def _packages(cfg): def _slackrepo(cfg): db = sqlite3.connect(f"file:{cfg['slackrepo_db']}?mode=ro", uri=True) try: - results = dict(db.execute("select result, count(*) from buildresults group by result")) + # legacy rows keyed by package file name, not category/pkg, match nothing: skip + results = dict(db.execute("select result, count(*) from buildresults" + " where itemid like '%/%' group by result")) built = db.execute("select count(distinct itemid) from revisions where dep = '/'").fetchone()[0] finally: db.close() @@ -478,6 +483,42 @@ def _builds(cfg): return built, results +def cmd_results(cfg): + """Last build attempt per package, newest first.""" + db = sqlite3.connect(f"file:{cfg['slackrepo_db']}?mode=ro", uri=True) + try: + rows = db.execute(""" + select b.itemid, b.result, cast(b.time as integer), r.version + from buildresults b left join revisions r on r.itemid = b.itemid and r.dep = '/' + where b.itemid like '%/%' order by cast(b.time as integer) desc""").fetchall() + finally: + db.close() + logdir = cfg["slackrepo_logdir"] + return {"rows": [[i, res, t, v, os.path.isdir(os.path.join(logdir, i))] + for i, res, t, v in rows]} + + +def _tail(path, limit): + with open(path, "rb") as f: + f.seek(0, os.SEEK_END) + size = f.tell() + f.seek(max(0, size - limit)) + return f.read().decode(errors="replace"), size > limit + + +def cmd_build_log(cfg, item=None): + if not ITEM.match(item or "") or ".." in item: + raise Error(f"bad package path: {item}") + d = os.path.join(cfg["slackrepo_logdir"], item) + build = os.path.join(d, "build.log") + if not os.path.isfile(build): + raise Error(f"no build log for {item}") + text, truncated = _tail(build, LOG_TAIL) + resource = os.path.join(d, "resource.log") + return {"build": text, "truncated": truncated, "mtime": int(os.path.getmtime(build)), + "resource": _tail(resource, LOG_TAIL)[0] if os.path.isfile(resource) else None} + + COLUMNS = ["path", "version", "info_version", "hint_version", "built_version", "built_time", "result", "maintainer", "requires", "summary", "hint_path", "hints"] @@ -577,6 +618,8 @@ COMMANDS = { "job-follow": cmd_job_follow, "job-kill": cmd_job_kill, "inventory": cmd_inventory, + "results": cmd_results, + "build-log": cmd_build_log, "gpg-status": cmd_gpg_status, "gpg-unlock": cmd_gpg_unlock, "_run": cmd_run, -- cgit v1.2.3