From 9ec00ca793472048f46b5619098290b736fe7d55 Mon Sep 17 00:00:00 2001 From: vasilito Date: Fri, 31 Jul 2026 22:28:52 +0300 Subject: [PATCH] build system: engine preserves ALL RedBear-added files across a rebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Data-loss bug: rsync --delete during a rebase dropped RedBear-added files that carry no __redox__ token (a Redox Wayland-crash wrapper .sh, a utmp compat header, a generated D-Bus interface) because the capture was grep-on-marker only. The engine now, for EVERY vendored rebase, fetches pristine(Vold) and carries forward every committed file absent from Vold (content-agnostic, matched by path) — so RedBear additions survive. If Vold cannot be fetched it rejects (manual) rather than produce a lossy tree. New tests E20 (non-marker added file preserved) + Vold fixtures for the rebase cases. 41 tests green. --- local/scripts/sync-recipe-source.sh | 76 ++++++++++++---------- local/scripts/test-versioning-machinery.sh | 18 ++++- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/local/scripts/sync-recipe-source.sh b/local/scripts/sync-recipe-source.sh index 83a305fb7b..a00b678241 100755 --- a/local/scripts/sync-recipe-source.sh +++ b/local/scripts/sync-recipe-source.sh @@ -171,47 +171,57 @@ for dir in "${RECIPES[@]}"; do lv=$(apply_patch "$base/source" "$pf"); [ "$lv" = FAIL ] && preject=1 done - # --- capture + reapply baked delta (changes beyond patches) --- + # --- preserve RedBear additions + reapply baked Redox deltas --- + # This runs for EVERY vendored rebase (not only marker-bearing ones): a + # RedBear-added file (e.g. a Redox Wayland-crash wrapper .sh, a utmp compat + # header) has no __redox__ token, so a grep-only capture misses it and + # rsync --delete drops it. We compare against pristine(Vold) by PATH to keep + # every RedBear addition, content-agnostic. breject=0 - if [ "$baked" -gt 0 ] && [ "$vold" != unknown ]; then - # Derive the old-version URL: replace the full version, then the - # major.minor directory component (KDE mirrors nest tarballs under a - # major.minor dir, e.g. .../frameworks/6.28/foo-6.28.0.tar.xz -> 6.10/foo-6.10.0). + if [ "$vold" != unknown ]; then + # Old-version URL: replace the full version, then the major.minor dir + # component (KDE mirrors nest under .../6.28/foo-6.28.0 -> 6.10/foo-6.10.0). oldurl="${url//$vnew/$vold}" vnm="${vnew%.*}"; vom="${vold%.*}" [ "$vnm" != "$vnew" ] && [ "$vnm" != "$vom" ] && oldurl="${oldurl//$vnm/$vom}" if download "$oldurl" "$WORK/$name-old.tar"; then op="$WORK/$name-old"; rm -rf "$op"; mkdir -p "$op"; tar xf "$WORK/$name-old.tar" -C "$op" 2>/dev/null otop="$(tar tf "$WORK/$name-old.tar" 2>/dev/null | head -1 | cut -d/ -f1)"; mv "$op/$otop" "$op/source" 2>/dev/null - # For each Redox-marker file uncovered by patches, port its delta onto base. - # A shim must NEVER be silently dropped: any failure -> breject (manual). - relroot="${dir#$ROOT/}" # repo-relative recipe dir (git show needs this) - while IFS= read -r line; do - rel="${line#*/source/}" - gitf="$WORK/gitf" - if ! git -C "$ROOT" show "HEAD:$relroot/source/$rel" > "$gitf" 2>/dev/null || [ ! -s "$gitf" ]; then - breject=1; continue # cannot read the Redox-modified file from HEAD - fi + relroot="${dir#$ROOT/}" # repo-relative recipe dir (git needs this) + gitf="$WORK/gitf" + + # (A) Carry forward every committed file absent from pristine(Vold): these + # are RedBear additions upstream never had. Skip the stamp and files + # the new pristine/patches already provide. + while IFS= read -r rel; do + [ "$rel" = ".redbear-src-version" ] && continue + [ -e "$op/source/$rel" ] && continue # exists upstream -> not a RedBear addition + [ -e "$base/source/$rel" ] && continue # already provided by pristine(Vnew) or a patch + if ! git -C "$ROOT" show "HEAD:$relroot/source/$rel" > "$gitf" 2>/dev/null; then breject=1; continue; fi decorrupt "$gitf" > "$gitf.clean" - if [ ! -f "$op/source/$rel" ]; then - # Redox-ADDED file (absent from old upstream): carry it into the new tree verbatim. - mkdir -p "$base/source/$(dirname "$rel")"; cp "$gitf.clean" "$base/source/$rel"; continue - fi - if [ ! -f "$base/source/$rel" ]; then - breject=1; continue # file existed in old upstream+HEAD but gone in new -> manual - fi - if diff -q "$op/source/$rel" "$gitf.clean" >/dev/null 2>&1; then - continue # marker is upstream's own (no Redox delta) -> nothing to port - fi - # Capture the delta to a file — do NOT pipe diff|patch. `diff` exits 1 - # whenever the files differ (always, here), and under `set -o pipefail` - # that makes the pipeline look failed even when patch succeeded, which - # would false-reject EVERY shim. Check patch's own exit status instead. - diff -u "$op/source/$rel" "$gitf.clean" > "$WORK/delta.patch" 2>/dev/null - if ! patch --fuzz=0 -s "$base/source/$rel" < "$WORK/delta.patch" >/dev/null 2>&1; then - breject=1 # Redox delta will not apply cleanly at new upstream -> manual - fi - done < <(git -C "$ROOT" grep -lI "__redox__\|Q_OS_REDOX\|defined(__redox" HEAD -- "$dir/source" 2>/dev/null) + mkdir -p "$base/source/$(dirname "$rel")"; cp "$gitf.clean" "$base/source/$rel" + done < <(git -C "$ROOT" ls-tree -r --name-only HEAD -- "$relroot/source" | while IFS= read -r p; do printf '%s\n' "${p#"$relroot"/source/}"; done) + + # (B) For marker-bearing files that ALSO exist in Vold (modified upstream + # files), port the Redox delta. Added marker files were handled by (A). + if [ "$baked" -gt 0 ]; then + while IFS= read -r line; do + rel="${line#*/source/}" + [ -f "$op/source/$rel" ] || continue # added file -> already carried by (A) + if ! git -C "$ROOT" show "HEAD:$relroot/source/$rel" > "$gitf" 2>/dev/null || [ ! -s "$gitf" ]; then + breject=1; continue + fi + decorrupt "$gitf" > "$gitf.clean" + if [ ! -f "$base/source/$rel" ]; then breject=1; continue; fi # gone in new upstream -> manual + diff -q "$op/source/$rel" "$gitf.clean" >/dev/null 2>&1 && continue # marker is upstream's own + # Capture delta to a file (never pipe diff|patch: diff exits 1 on any + # difference and pipefail would false-reject every shim). + diff -u "$op/source/$rel" "$gitf.clean" > "$WORK/delta.patch" 2>/dev/null + if ! patch --fuzz=0 -s "$base/source/$rel" < "$WORK/delta.patch" >/dev/null 2>&1; then + breject=1 + fi + done < <(git -C "$ROOT" grep -lI "__redox__\|Q_OS_REDOX\|defined(__redox" HEAD -- "$dir/source" 2>/dev/null) + fi else breject=1; fi fi diff --git a/local/scripts/test-versioning-machinery.sh b/local/scripts/test-versioning-machinery.sh index 36e8724be3..1ef64832a7 100755 --- a/local/scripts/test-versioning-machinery.sh +++ b/local/scripts/test-versioning-machinery.sh @@ -110,6 +110,7 @@ assert_eq "E2 source/ untouched" "$(cat "$d/source/f.c")" "code"; rm -rf "$d" echo "=== engine: real rebase via file:// tarball ===" # E4 auto-ready divergent (0 patches, 0 baked): source/ 1.0.0 -> pristine 2.0.0 +mk_tar "$FIX/tarballs/e4-1.0.0.tar" "app-1.0.0" "main.c:v1\n" "old_only.c:gone\n" newtar="$FIX/tarballs/e4-2.0.0.tar"; mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "main.c:v2\n" "new_only.c:added\n" d="$(mk_recipe eng_ready "file://$newtar" "$(b3 "$newtar")")" mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'v1\n' >"$d/source/main.c"; printf 'gone\n' >"$d/source/old_only.c" @@ -122,7 +123,8 @@ assert_eq "E4 stamp updated to 2.0.0" "$(cat "$d/source/.redbear-src-version")" out="$($SYNC --check eng_ready 2>&1)"; assert_contains "E9 second run consistent" "$out" "consistent"; rm -rf "$d" # E5/E6 patch apply vs reject -newtar="$FIX/tarballs/e5-2.0.0.tar"; mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "f.c:line1\nline2\nline3\n" +newtar="$FIX/tarballs/e5-2.0.0.tar"; mk_tar "$FIX/tarballs/e5-1.0.0.tar" "app-1.0.0" "f.c:line1\nline2\nline3\n" +mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "f.c:line1\nline2\nline3\n" d="$(mk_recipe eng_patch "file://$newtar" "$(b3 "$newtar")"); " d="$FIX/local/recipes/eng_patch" printf 'tar = "file://%s"\nblake3 = "%s"\npatches = [ "add.patch" ]\n' "$newtar" "$(b3 "$newtar")" >>"$d/recipe.toml" 2>/dev/null @@ -159,6 +161,7 @@ assert_eq "E12 source/ untouched on DL-FAIL" "$(cat "$d/source/f.c")" "keep"; rm echo "=== blake3 reconcile ===" STALE=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef # E13 rebase reconciles recipe blake3 to the fetched source.tar +mk_tar "$FIX/tarballs/e13-1.0.0.tar" "app-1.0.0" "m.c:v1\n" newtar="$FIX/tarballs/e13-2.0.0.tar"; mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "m.c:v2\n" d="$(mk_recipe eng_b3 "file://$newtar" "$STALE")" mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'v1\n' >"$d/source/m.c" @@ -223,6 +226,19 @@ $SYNC eng_shim3 >/dev/null 2>&1 [ -f "$d/source/redoxonly.c" ] && grep -q "__redox__" "$d/source/redoxonly.c" && ok "E19 Redox-added file carried into new tree" || no "E19 added file carried" "redoxonly.c lost" rm -rf "$d"; gc rm +echo "=== E20 RedBear-ADDED file WITHOUT a __redox__ marker is preserved across rebase ===" +mk_tar "$FIX/tarballs/w-1.0.0.tar" "app-1.0.0" "foo.c:x\n" +mk_tar "$FIX/tarballs/w-2.0.0.tar" "app-2.0.0" "foo.c:x2\n" ".redbear-src-version:2.0.0\n" +d="$(mk_recipe eng_add "file://$FIX/tarballs/w-2.0.0.tar" "$(b3 "$FIX/tarballs/w-2.0.0.tar")")" +mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'x\n' >"$d/source/foo.c" +# a RedBear launcher wrapper — NOT in upstream, and it contains NO __redox__ token +printf '#!/bin/sh\n# RedBear launcher wrapper\nexec /usr/bin/app.real "$@"\n' >"$d/source/app-wrapper.sh" +gc eng_add +$SYNC eng_add >/dev/null 2>&1 +[ -f "$d/source/app-wrapper.sh" ] && grep -q "RedBear launcher" "$d/source/app-wrapper.sh" && ok "E20 non-marker RedBear-added file preserved" || no "E20 added file preserved" "app-wrapper.sh dropped by rebase" +assert_eq "E20 upstream file updated to v2" "$(cat "$d/source/foo.c")" "x2" +rm -rf "$d"; gc rm + echo "" echo "================ RESULT ================" echo " PASS: $PASS FAIL: $FAIL"