diff --git a/scripts/webui/data/generators/updater/webui_updater_scan.sh b/scripts/webui/data/generators/updater/webui_updater_scan.sh index 50de7aa..9e1878e 100644 --- a/scripts/webui/data/generators/updater/webui_updater_scan.sh +++ b/scripts/webui/data/generators/updater/webui_updater_scan.sh @@ -187,9 +187,9 @@ updaterTagGreater() { return 1 # identical -> not newer } -# The newest tag for $2 (repo) that shares $1's (current tag) shape and is -# numerically greater. Empty when there is nothing newer — the common case. -updaterNewerVersionTag() { +# The newest same-shape, numerically-greater tag found by ENUMERATING the newest +# 100 tags. One cheap call, and right whenever the release we want is recent. +updaterNewerVersionByList() { local cur="$1" repo="$2" local shape; shape="$(updaterTagShape "$cur")" local best="" t @@ -202,6 +202,82 @@ updaterNewerVersionTag() { printf '%s' "$best" } +# Bump the Nth (0-based) numeric component of a tag by one and zero every +# component after it, so a bump means what a version bump means: +# "v1.158.2", 1 -> "v1.159.0" "31-fpm-alpine", 0 -> "32-fpm-alpine" +# Shape is preserved by construction (only the digits change), which is what +# lets the caller compare shapes to reject nonsense candidates. +updaterTagBumpAt() { + printf '%s' "$1" | awk -v idx="$2" '{ + out=""; n=0; s=$0 + while (match(s, /[0-9]+/)) { + pre = substr(s, 1, RSTART-1) + num = substr(s, RSTART, RLENGTH) + 0 + s = substr(s, RSTART+RLENGTH) + if (n == idx) num = num + 1; else if (n > idx) num = 0 + out = out pre num + n++ + } + print out s + }' +} + +# The newest tag reachable from $1 by PROBING for exact tags, most-significant +# component first, climbing each as far as it goes. +# +# This exists because enumeration has a blind spot that gets worse the more +# actively a project publishes. The listing returns the newest 100 tags, and +# repos that push a tag per commit drown their own releases in them — +# matrixdotorg/synapse's newest 100 hold just 5 version tags, roughly ten days +# of history. Once the release we need is older than that window it is simply +# absent, updaterNewerVersionByList returns nothing, and the app reports "up to +# date" forever. The failure is silent and it lands exactly on the apps that are +# furthest behind, which are the ones that most need to be told. +# +# Probing has no window: an exact tag lookup either exists or it does not. This +# is the same reasoning (and the same endpoint) as the version ladder, which +# refuses to build a rung list from a listing for precisely this reason — see +# cli_updater_ladder.sh. Bounded at 40 lookups so a strange tag scheme cannot +# turn one app's scan into a crawl. +updaterNewerVersionByProbe() { + local cur="$1" repo="$2" + declare -F updaterTagExists >/dev/null 2>&1 || return 0 # ladder unavailable + local shape; shape="$(updaterTagShape "$cur")" + local ncomp; ncomp="$(printf '%s' "$cur" | grep -oE '[0-9]+' | wc -l | tr -d ' ')" + [ "${ncomp:-0}" -gt 0 ] 2>/dev/null || return 0 + + local best="$cur" probes=0 i cand + for ((i=0; i/dev/null)" + [ "$_seen" = "null" ] && _seen="" + [ -z "$_seen" ] && app_registry=1 # never answered (new app, or first scan) + fi + # available (registry) digest for the anchor's channel local avail_dig="" - if [ "$do_registry" = "1" ]; then + if [ "$app_registry" = "1" ]; then avail_dig="$(updaterRegistryDigest "$(updaterRepoTag "$anchor")")" fi # reuse the prior value when we didn't (or couldn't) reach the registry @@ -287,7 +383,7 @@ webuiUpdaterScan() { # rest of the registry work: look it up live inside the window, otherwise # carry the previous answer forward so the field never blinks off. local img_updated="" - if [ "$do_registry" = "1" ]; then + if [ "$app_registry" = "1" ]; then img_updated="$(updaterTagLastUpdated "$(updaterRepoTag "$anchor")" "$channel")" fi if [ -z "$img_updated" ] && [ "$have_jq" = "1" ] && [ -f "$prev_json" ]; then @@ -301,7 +397,7 @@ webuiUpdaterScan() { # field does not flicker off on a throttled scan. local newer_ver="" if [ "$vtype" = "versioned" ]; then - if [ "$do_registry" = "1" ]; then + if [ "$app_registry" = "1" ]; then newer_ver="$(updaterNewerVersionTag "$channel" "$(updaterRepoTag "$anchor")")" newer_ver="${newer_ver%%:*}" elif [ "$have_jq" = "1" ] && [ -f "$prev_json" ]; then