1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# Updates module
A drawer tile and page that answer one question per row: what do I do next
to bring this machine up to date. It replaces two places that showed the same
facts less clearly: the conky updates card, a copy of `nvtable`'s table where
installed-behind and repo-behind share a row and are told apart by colour,
and the homepage ChangeLog widget, which shows the latest upstream -current
entry rather than what this machine is missing.
## Sources and what they mean
Four versions per tracked package:
- **U, upstream**: `~/.config/nvchecker/new_ver.json`.
- **R, recipe**: `VERSION=` in `<pkg>.info` under the three repos of
`~/Programming/GIT/slackbuilds-superrepo` (`sbo-slackbuilds`,
`my-slackbuilds`, `Slackware-Pentesting-Suite`), falling back to the
SlackBuilds.org clone at `/var/lib/sbopkg/SBo-git`. A recipe from that clone
is tagged `SBo`: it is not the user's SlackBuild, and a bump of it happens
through a slackrepo `.hint` file on the build VM, which is not visible from
here.
- **B, built**: `PACKAGES.TXT` of the user's binary repo, the directory named
by the `danix` entry of `MIRRORPLUS` in `/etc/slackpkg/slackpkgplus.conf`.
- **I, installed**: `/var/log/packages`, then appimage-updater's
`installed.json`, then `flatpak list --app`, in that order, as `nvtable`
does.
nvtable's two alias tables (stanza name to installed name, stanza name to
SlackBuild directory) are ported into the script as dicts.
For Slackware itself, the mirror is the `file://` line active in
`/etc/slackpkg/mirrors`. Its `PACKAGES.TXT` and `ChangeLog.txt` are compared
against `/var/log/packages`. `/var/lib/slackpkg/ChangeLog.txt` is not used:
`slackpkg update` replaces it without installing anything, so a diff against
it reads "nothing pending" after an update that was never applied.
## Sections
In page order. A package appears in exactly one section, the first that
matches, so a row shows the next step and nothing after it.
1. **Slackware**, three groups, all from the mirror:
- *Upgrade*: an installed package whose name is on the mirror with a
different version or build.
- *New*: of the ChangeLog's `Added.` and `Removed.` lines for the package,
the newest says `Added.`; it is on the mirror and not installed. These
are slackpkg's `install-new` semantics. Other lines (`Upgraded.`,
`Rebuilt.`) are ignored, or a package added and later upgraded would
never count as new.
- *Removed*: of the same lines, the newest says `Removed.`,
it is installed, and it is not on the mirror. The row carries the date of
that ChangeLog entry.
Installed packages whose build tag matches a pattern in
`/etc/slackpkg/blacklist` (`_SBo`, `_danix`, `alien` and the rest) are
skipped in all three, as slackpkg skips them; so are blacklisted names.
2. **Upgrade here**: B newer than I. The package is built and sitting in the
repo.
3. **Awaiting build**: R is at or past U, B is older than U, and the package
is installed. The SlackBuild, the user's or SBo's, is current and only
needs building.
4. **Upstream newer**: U newer than the newest of R, B and I. The SlackBuild or its hint
needs bumping, then a build. An `SBo` recipe that lags upstream lands
here: the bump is a hint file on the build VM. Shown when the package is
installed, or when the recipe is the user's (repo work either way).
5. **App updates**: I comes from AppImage or flatpak and is older than U.
"Newer" and "older" are version order, never equality: an installed 2.1.278
against an SBo recipe of 2.1.267 is not an upgrade. A tracked package that is
not installed and whose recipe is current is not shown.
## `updatesctl`
`desktop/modules/updates/updatesctl`, `/usr/bin/python3`, standard library
only. It prints one JSON document:
{
"checked": <mtime of new_ver.json, epoch seconds>,
"slackware": {"upgrade": [...], "new": [...], "removed": [...]},
"upgrade": [...], "build": [...], "upstream": [...], "apps": [...],
"errors": {"mirror": "unreachable", ...}
}
Rows are `{name, repo, from, to}`; Slackware rows are `{name, from, to}`,
`{name, version}` and `{name, date}`. `repo` is the label nvtable shows
(`personal`, `my-sbo`, `pentesting`, `SBo`, `AppImage`, `flatpak`).
**Version order** is a small `vercmp`: split on non-alphanumerics, compare
numeric chunks as numbers and alphabetic chunks as strings, numbers before
letters; when one runs out, the longer is newer unless its next chunk is
alphabetic (a pre-release). It replaces nvtable's normalised equality. Its
rule that an installed version extending upstream at a component boundary (a
kernel suffix, a git hash) counts as equal needs no special case: the longer
version orders as newer, which is never behind.
**NFS reads** (`PACKAGES.TXT` of the repo and of the mirror, the mirror's
`ChangeLog.txt`) go through `subprocess.run(["cat", path], timeout=5)`. The
mount is `hard`, so a read during a NAS outage blocks; the timeout kills the
child, the script carries on, and that source is reported in `errors` while
the sections that do not need it still fill.
**`--refresh`** runs `nvchecker -c ~/.config/nvchecker/nvchecker.toml`
synchronously first, then prints as above. That config already names the
GitHub keyfile. nvtake is not run: this model never reads `old_ver.json`.
## Module
`desktop/modules/updates/UpdatesModule.qml`, name `updates`.
- **Icon**: ``, `linux-slackware`, present in Inconsolata Nerd Font.
- **Tile line**: `3 to install · 2 to build`, counting Slackware (all three
groups) plus Upgrade here as "to install", and Awaiting build as "to build".
`up to date` when both are zero. `checking…` before the first result.
- **Active** (accent) when there is anything to install.
- **Freshness**: when the tile is created, which is when the drawer opens, the
module runs `updatesctl`. If `checked` is more than 30 minutes old it then
runs `updatesctl --refresh` and the page shows `checking…` until it
returns. Nothing runs while the drawer is closed, the same gating as KDE
Connect.
- **Page**: the five sections in order, each with a heading and a count, each
hidden when empty. Rows read `name repo from → to`. A footer reads
`checked 12 min ago` and holds a refresh button that runs `--refresh`.
An entry in `errors` shows as one dim line under the section it empties,
e.g. `mirror unreachable`. Read-only: no install or build buttons.
## Retiring conky's card
Once the user trusts the tile, `bin/updates-sample.sh` and
`widgets/updates.lua` are deleted from `conky-theme-udt`, with the card's
slot, as a separate commit in that repo. `nvtable` stays in
`danix-nvchecker` for the shell; this repo does not depend on it.
## Testing
`desktop/modules/updates/test_updatesctl.py`, run with `/usr/bin/python3`:
- `vercmp`: 1.14.10 > 1.14.9, 2.1.278 > 2.1.267, 2026_10_02 > 2026_09_12,
a kernel suffix or git hash never behind its base.
- Section assignment on fixture directories built in a temp dir, one row per
case: built and newer goes to Upgrade here, bumped and unbuilt to Awaiting
build, unbumped to Upstream newer, an SBo recipe behind upstream to
Upstream newer, an installed version ahead of SBo to nothing, an AppImage
behind to App updates.
- Slackware: a mirror with one changed build, one `Added.` package and one
`Removed.` package, plus a blacklisted `_SBo` build that must not appear.
- An NFS path that times out: a fifo with no writer, read with a short
timeout, must report `unreachable` without hanging the test.
The tests must be shown to fail on a broken input before they are trusted.
## Not in scope
Installing, building, or bumping from the page. Showing upstream lag of the
NFS mirror itself. Reading slackrepo hint files from the build VM.
|