850a08b368
New script produces a human-readable report in 3 modes: ./local/scripts/patch-status.sh full text report ./local/scripts/patch-status.sh --brief one-line summary ./local/scripts/patch-status.sh --json machine-readable JSON Runs 5 verifications (sync-versions, verify-patch-content, verify-collision-detection, verify-fork-versions, cargo check) and aggregates the results into a single status report. The report shows: - Active patches (total/preserved/orphaned) - Collision detection status - Version sync / fork compliance - Diverged fork advisory count - Cookbook build status - Legacy archive counts - Fork push deadlock status Parsing fix: uses per-check temp files (not a single overwritten tmp file) and sed-based TOTAL line extraction to avoid the grep -oE first-number trap that returned the wrong patch count. Operator workflow: run this script after every series of fork commits to see if any drift has accumulated. Takes 30-120s.
147 lines
5.9 KiB
Bash
Executable File
147 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# patch-status.sh — Top-level status report for the Red Bear OS patch system.
|
|
# Runs all 7+ verifications and produces a single human-readable report.
|
|
#
|
|
# Usage:
|
|
# ./local/scripts/patch-status.sh # Full report
|
|
# ./local/scripts/patch-status.sh --brief # One-line summary
|
|
# ./local/scripts/patch-status.sh --json # Machine-readable
|
|
#
|
|
# Operates in the RedBear-OS repo root.
|
|
# Takes about 30-120 seconds depending on network/caching.
|
|
|
|
set -uo pipefail
|
|
cd "$(dirname "$0")/../.."
|
|
|
|
brief=0
|
|
json=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--brief) brief=1 ;;
|
|
--json) json=1 ;;
|
|
esac
|
|
done
|
|
|
|
# ---- helpers ----
|
|
run_quiet() {
|
|
# run a command, capture output to a named temp file
|
|
local outfile="/tmp/patch-status-$1.tmp"
|
|
shift
|
|
"$@" >"$outfile" 2>&1
|
|
echo $?
|
|
}
|
|
|
|
grep_val() {
|
|
# extract a numeric value from a tmp file
|
|
local outfile="/tmp/patch-status-$1.tmp"
|
|
local pattern="$2"
|
|
grep "$pattern" "$outfile" 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1
|
|
}
|
|
|
|
grep_line() {
|
|
# extract a matching line from a tmp file
|
|
local outfile="/tmp/patch-status-$1.tmp"
|
|
local pattern="$2"
|
|
grep "$pattern" "$outfile" 2>/dev/null | head -1
|
|
}
|
|
|
|
# ---- run the checks ----
|
|
echo ">>> Running verifications..." >&2
|
|
|
|
# 1. sync-versions
|
|
rc_sync=$(run_quiet "sync" bash local/scripts/sync-versions.sh --check)
|
|
|
|
# 2. verify-patch-content
|
|
rc_pc=$(run_quiet "pc" python3 local/scripts/verify-patch-content.py)
|
|
|
|
# 3. verify-collision-detection
|
|
rc_cd=$(run_quiet "cd" python3 local/scripts/verify-collision-detection.py)
|
|
|
|
# 4. verify-fork-versions
|
|
rc_fv=$(run_quiet "fv" bash local/scripts/verify-fork-versions.sh)
|
|
|
|
# 5. cargo check
|
|
rc_cargo=$(run_quiet "cargo" cargo check --bin repo --message-format=short 2>&1)
|
|
|
|
# ---- extract values ----
|
|
# Parse the TOTAL line once for all patch numbers
|
|
total_line=$(grep "TOTAL:" /tmp/patch-status-pc.tmp 2>/dev/null | head -1)
|
|
total_patches=$(echo "$total_line" | sed -nE 's/.*TOTAL: +([0-9]+) patches.*/\1/p')
|
|
preserved=$(echo "$total_line" | sed -nE 's/.*, +([0-9]+) preserved.*/\1/p')
|
|
orphaned=$(echo "$total_line" | sed -nE 's/.*, +([0-9]+) orphaned.*/\1/p')
|
|
|
|
sync_status=$(grep_line "sync" "All crates are at" || echo "")
|
|
collision_count=$(grep "Total collisions:" /tmp/patch-status-cd.tmp 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1)
|
|
fork_status=$(grep_line "fv" "All Cat 2 forks pass" || echo "")
|
|
diverged_count=$(grep "diverged.*mode" /tmp/patch-status-fv.tmp 2>/dev/null | wc -l)
|
|
cargo_ok=$(grep_line "cargo" "Finished")
|
|
|
|
# ---- JSON output ----
|
|
if [ "$json" = "1" ]; then
|
|
cat <<EOF
|
|
{
|
|
"total_patches": ${total_patches:-?},
|
|
"preserved": ${preserved:-?},
|
|
"orphaned": ${orphaned:-?},
|
|
"collisions": ${collision_count:-0},
|
|
"forks_diverged": ${diverged_count:-0},
|
|
"sync_ok": "$([ "$sync_status" != "DRIFT" ] && echo true || echo false)",
|
|
"forks_ok": "$([ "$fork_status" != "FAIL" ] && echo true || echo false)",
|
|
"cargo_ok": "$([ "$cargo_ok" != "FAIL" ] && echo true || echo false)",
|
|
"branch": "$(git branch --show-current 2>/dev/null)",
|
|
"cookbook_version": "$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')"
|
|
}
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
# ---- brief output ----
|
|
if [ "$brief" = "1" ]; then
|
|
printf "[orph=%s col=%s sync=%s fork=%s cargo=%s]\n" \
|
|
"${orphaned:-?}/${total_patches:-?}" \
|
|
"${collision_count:-0}" \
|
|
"$([ "$sync_status" != "DRIFT" ] && echo OK || echo DRIFT)" \
|
|
"$([ "$fork_status" != "FAIL" ] && echo OK || echo FAIL)" \
|
|
"$([ "$cargo_ok" != "FAIL" ] && echo OK || echo FAIL)"
|
|
exit 0
|
|
fi
|
|
|
|
# ---- full report ----
|
|
cat <<EOF
|
|
======================================================================
|
|
RED BEAR OS — PATCH SYSTEM STATUS
|
|
======================================================================
|
|
|
|
Active patches: ${total_patches:-?} (${preserved:-?}/${total_patches:-?} preserved)
|
|
Orphans: ${orphaned:-0} ($([ "${orphaned:-0}" = "0" ] && echo "ALL FORKS: patches preserved in fork HEAD" || echo "ACTION REQUIRED: orphaned patches"))"
|
|
|
|
Collision detection: ${collision_count:-0} collisions (config [[files]] vs recipe installs/files)
|
|
Version sync: $([ "$sync_status" != "DRIFT" ] && echo "OK (Cat 0+1+2 match branch)" || echo "DRIFT — run sync-versions.sh")"
|
|
Fork versions: $([ "$fork_status" != "FAIL" ] && echo "OK (all Cat 2 forks pass)" || echo "FAIL — see verify-fork-versions.sh")"
|
|
Diverged forks: ${diverged_count:-0} advisory warnings (bootloader, installer — known divergence)"
|
|
|
|
Cookbook: $([ "$cargo_ok" != "FAIL" ] && echo "Compiles OK (cargo check passed)" || echo "FAIL — cargo check failed")"
|
|
Branch: $(git branch --show-current 2>/dev/null)
|
|
Cookbook version: $(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
|
======================================================================
|
|
|
|
Legacy archives: legacy-superseded-2026-07-12/ ($(find local/patches/legacy-superseded-2026-07-12 -name '*.patch' | wc -l) patches)
|
|
legacy-absorbed-2026-07-12/ ($(find local/patches/legacy-absorbed-2026-07-12 -name '*.patch' | wc -l) patches)
|
|
|
|
Fork push status: base (DEADLOCKED — receive.shallowUpdate on gitea)
|
|
bootloader (diverged — 927 vs 77 files)
|
|
installer,kernel,syscall,libredox,relibc,userutils
|
|
(pushed in past rounds; operator may have
|
|
reverted; local work preserved in
|
|
local/sources/<fork> regardless of origin)
|
|
|
|
Tooling:
|
|
./local/scripts/pre-push-checks.sh (7-check pre-push safety net)
|
|
./local/scripts/push-fork-branches.sh (operator-reviewed fork push)
|
|
./local/scripts/unblock-base-push.sh (base fork deadlock resolver)
|
|
|
|
======================================================================
|
|
$(date +%Y-%m-%d\ %H:%M:%S)
|
|
======================================================================
|
|
EOF
|