aboutsummaryrefslogtreecommitdiffstats
path: root/sb_builder/packages.py
diff options
context:
space:
mode:
Diffstat (limited to 'sb_builder/packages.py')
-rw-r--r--sb_builder/packages.py41
1 files changed, 34 insertions, 7 deletions
diff --git a/sb_builder/packages.py b/sb_builder/packages.py
index f1a7224..0a669bb 100644
--- a/sb_builder/packages.py
+++ b/sb_builder/packages.py
@@ -17,6 +17,7 @@
"""Packages tab: search the inventory, read a package's hints, start slackrepo previews."""
import html
+import re
from PyQt6.QtCore import QAbstractTableModel, QModelIndex, QSortFilterProxyModel, Qt, pyqtSignal
from PyQt6.QtGui import QColor, QKeySequence, QShortcut
@@ -29,22 +30,48 @@ from .fmt import NA, fmt_time
from .ui import SP, action, chip, enable, group_label, search_field
OVERLAYS = ("personal", "pentesting")
-STATUSES = ("ok", "failed", "never", "outdated")
+STATUSES = ("ok", "failed", "never", "outdated", "newer")
COLUMNS = ("", "name", "category", "version", "built", "status", "maintainer")
-STATUS_COLOR = {"ok": STATUS["ok"], "failed": STATUS["failed"], "outdated": STATUS["aborted"]}
+STATUS_COLOR = {"ok": STATUS["ok"], "failed": STATUS["failed"], "outdated": STATUS["aborted"],
+ "newer": STATUS["bad"]}
FIELDS = {"cat": "category", "maint": "maintainer", "req": "requires", "status": "status"}
+PRE_RELEASE = ("alpha", "beta", "pre", "rc", "dev")
+
+
+def _runs(v):
+ return [int(r) if r.isdigit() else r.lower() for r in re.findall(r"\d+|[A-Za-z]+", v)]
+
+
+def vercmp(a, b):
+ """-1, 0 or 1: a older, equal, newer than b.
+
+ Digit runs compare as numbers, letter runs as text, a number beats a
+ letter. Past the shorter version, a pre-release word makes the longer one
+ older (1.0rc1 < 1.0), anything else newer (1.0.1, 4.3.5b > their base).
+ """
+ # ponytail: single-letter pre-releases (1.0b1) count as newer than 1.0;
+ # snapshots (20240101_ab12cd) order by date, their hash part arbitrarily
+ ra, rb = _runs(a), _runs(b)
+ for x, y in zip(ra, rb):
+ if x != y:
+ if type(x) is type(y):
+ return -1 if x < y else 1
+ return 1 if isinstance(x, int) else -1
+ if len(ra) == len(rb):
+ return 0
+ sign, nxt = (1, ra[len(rb)]) if len(ra) > len(rb) else (-1, rb[len(ra)])
+ return -sign if nxt in PRE_RELEASE else sign
def status(row):
- # ponytail: outdated compares versions only; slackrepo also rebuilds on
- # SlackBuild or dependency changes, which its preview shows
+ # ponytail: compares versions only; slackrepo also rebuilds on SlackBuild
+ # or dependency changes, which its preview shows
if not row["built_version"] and not row["result"]:
return "never"
if row["result"] in ("failed", "bad", "aborted"):
return "failed"
- if row["built_version"] != row["version"]:
- return "outdated"
- return "ok"
+ c = vercmp(row["built_version"] or "", row["version"] or "")
+ return "outdated" if c < 0 else "newer" if c > 0 else "ok"
def overlay(row):