Files
RedBear-OS/local/scripts/verify-external-source-versions.sh
T
vasilito 8413b69334 build system: harden + regression-test the versioning machinery
Edge-case suite (local/scripts/test-versioning-machinery.sh, 27 cases, zero
network via file:// tarballs) covering the validator and the sync engine.
It found and fixed three silent-failure bugs — the exact class the user flagged:
 - sync engine used 'rsync -a --delete' (size+mtime quick-check): a changed file
   of identical size with a coincidental mtime was skipped, leaving stale content
   in source/. Now uses --checksum (content comparison).
 - apply_patch relied on patch's default fuzz: a patch whose context no longer
   matched the new upstream was force-fitted instead of rejected. Now --fuzz=0
   (exact context; line offsets still allowed).
 - decorrupt collapsed ANY run of identical lines, mangling legitimate paired
   lines; now only collapses the corruption pattern (runs >=4).
Also: unknown-version recipes are skipped (never clobber a ported tree like
mesa), and grep patterns use [[:space:]] for portability.
2026-07-31 20:33:10 +03:00

98 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# verify-external-source-versions.sh — detect recipe-vs-source VERSION divergence
# for tar-based (external upstream) recipes.
#
# Why this exists
# ---------------
# Several recipes under local/recipes/ vendor their upstream `source/` tree in
# git (the fork model) while ALSO declaring a `[source] tar = <url>` + `blake3`.
# A version bump that only rewrites `tar=`/`blake3=` (e.g. via
# bump-graphics-recipes.sh, or a manual edit) does NOT propagate into the
# committed source/ tree, nor does cookbook re-extract an existing source/ or
# re-verify an existing source.tar. The build then silently compiles the STALE
# version — exactly the Qt 6.11.0-vs-6.11.1 divergence that broke the desktop
# build (qtshadertools required 6.11.1 but qtbase was cooked from a 6.11.0 tree).
#
# This is the tar-recipe analogue of verify-fork-functions.sh (which guards the
# local/sources/ forks). It FAILS LOUDLY rather than letting a stale tree build.
#
# Checks per tar recipe (only when the relevant artifact is present):
# 1. source.tar blake3 == recipe blake3 (stale downloaded tarball)
# 2. source.tar top-dir version == recipe URL version (URL bumped, tar not)
# 3. vendored source/ version marker == recipe URL version
# (recipe bumped, committed tree not — the Qt class). Marker files:
# - .cmake.conf : QT_REPO_MODULE_VERSION "X.Y.Z" (Qt modules)
# - .redbear-src-version : plain "X.Y.Z" (generic stamp)
#
# Exit 0 = all consistent (or nothing to check). Exit 1 = divergence found.
# Gate: REDBEAR_SKIP_EXTERNAL_SOURCE_CHECK=1 bypasses (handled by caller).
set -u
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
QUIET=0
for a in "$@"; do case "$a" in --quiet) QUIET=1 ;; esac; done
have_b3() { command -v b3sum >/dev/null 2>&1; }
# Extract a dotted version (X.Y or X.Y.Z...) from a string; prints the LAST one,
# which for "qtbase-everywhere-src-6.11.1.tar.xz" is the upstream version.
ver_of() { grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)*' <<<"$1" | tail -1; }
FAIL=0
CHECKED=0
declare -a PROBLEMS=()
while IFS= read -r recipe; do
dir="$(dirname "$recipe")"
# recipe-declared tar URL + blake3 (first [source] tar= wins)
url="$(grep -m1 -E '^[[:space:]]*tar[[:space:]]*=' "$recipe" 2>/dev/null | sed -E 's/^[^"]*"([^"]+)".*/\1/')"
[ -n "$url" ] || continue
rblake="$(grep -m1 -E '^[[:space:]]*blake3[[:space:]]*=' "$recipe" 2>/dev/null | grep -oE '[0-9a-f]{64}')"
rver="$(ver_of "$(basename "$url")")"
[ -n "$rver" ] || continue
name="$(basename "$dir")"
CHECKED=$((CHECKED + 1))
# 1) cached source.tar blake3 must match recipe blake3
if [ -f "$dir/source.tar" ] && [ -n "$rblake" ] && have_b3; then
dblake="$(b3sum "$dir/source.tar" 2>/dev/null | awk '{print $1}')"
if [ -n "$dblake" ] && [ "$dblake" != "$rblake" ]; then
PROBLEMS+=("$name: cached source.tar blake3 ($dblake) != recipe blake3 ($rblake) — stale downloaded tarball; rm '$dir/source.tar' to re-fetch")
FAIL=1
fi
fi
# 2) source.tar top-dir version must match recipe URL version
if [ -f "$dir/source.tar" ]; then
tver="$(ver_of "$(tar tf "$dir/source.tar" 2>/dev/null | head -1)")"
if [ -n "$tver" ] && [ "$tver" != "$rver" ]; then
PROBLEMS+=("$name: source.tar is v$tver but recipe tar= is v$rver — URL bumped, tarball not; rm '$dir/source.tar' to re-fetch")
FAIL=1
fi
fi
# 3) vendored source/ version marker must match recipe URL version
if [ -d "$dir/source" ]; then
sver=""
if [ -f "$dir/source/.redbear-src-version" ]; then
sver="$(ver_of "$(cat "$dir/source/.redbear-src-version" 2>/dev/null)")"
elif [ -f "$dir/source/.cmake.conf" ]; then
sver="$(ver_of "$(grep -m1 QT_REPO_MODULE_VERSION "$dir/source/.cmake.conf" 2>/dev/null)")"
fi
if [ -n "$sver" ] && [ "$sver" != "$rver" ]; then
PROBLEMS+=("$name: vendored source/ is v$sver but recipe declares v$rver — the committed tree was never bumped; rebase source/ onto v$rver (see qt bump commits for the pattern)")
FAIL=1
fi
fi
done < <(find "$ROOT/local/recipes" -name recipe.toml -not -path '*/wip/*' 2>/dev/null)
if [ "$FAIL" != "0" ]; then
echo "FAIL: external source version divergence ($CHECKED tar recipes checked):" >&2
for p in "${PROBLEMS[@]}"; do echo " - $p" >&2; done
exit 1
fi
[ "$QUIET" = "1" ] || echo ">>> Preflight: external tar-recipe source versions consistent ($CHECKED checked)."
exit 0