6f8dd561e2
The verify-overlay-integrity.sh script has two blind spots for stale symlink detection: 1. find recipes -maxdepth 3 misses paths at depth 4+ 2. only checks targets under /local/recipes/, misses /local/patches/ This adds a parallel scan that finds all dangling symlinks under recipes/ without maxdepth, classifies them by target path, and reports each with a suggested action. Pure diagnostic — does not modify any files. Enables preventive detection of the recipes/wip/x11/mesa-x11/source orphan and recipes/core/base/redox.patch pointer-rot that triggered the build integrity warnings on this session's rebuilds. (NO AI attribution in commit message.)
166 lines
5.7 KiB
Bash
Executable File
166 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
project_root="$(git -C "$script_dir" rev-parse --show-toplevel)"
|
|
|
|
if [[ -t 1 ]]; then
|
|
c_reset=$'\033[0m'
|
|
c_red=$'\033[31m'
|
|
c_green=$'\033[32m'
|
|
c_yellow=$'\033[33m'
|
|
else
|
|
c_reset=''
|
|
c_red=''
|
|
c_green=''
|
|
c_yellow=''
|
|
fi
|
|
|
|
ok() { printf '%sOK%s: %s\n' "$c_green" "$c_reset" "$*"; }
|
|
warn() { printf '%sWARN%s: %s\n' "$c_yellow" "$c_reset" "$*"; }
|
|
fail() { printf '%sFAIL%s: %s\n' "$c_red" "$c_reset" "$*" >&2; }
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0") [--doctor] [--simulate-staleness] [--scan-dead-symlinks]
|
|
|
|
Check whether the compiled prefix libc.a is older than local fork commits.
|
|
|
|
Options:
|
|
--doctor Print verbose component/file diagnostics
|
|
--simulate-staleness Force an artificial stale-prefix result for testing
|
|
--scan-dead-symlinks Scan recipes/ for dangling symlinks and missing gitlinks
|
|
-h, --help Show this help
|
|
EOF
|
|
}
|
|
|
|
doctor=0
|
|
simulate_staleness=0
|
|
scan_dead_symlinks=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--doctor) doctor=1 ;;
|
|
--simulate-staleness) simulate_staleness=1 ;;
|
|
--scan-dead-symlinks) scan_dead_symlinks=1 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) fail "unknown argument: $arg"; usage; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
scan_dead_symlinks_mode() {
|
|
local broken=0 total=0 gitlink_count=0 path classification action target linkpath canonical
|
|
local stale_recipe_overlay=0 stale_patch_symlink=0 stale_fork_symlink=0 stale_unclassified=0 stale_submodule=0
|
|
|
|
while IFS= read -r linkpath; do
|
|
[[ -n "$linkpath" ]] || continue
|
|
(( total++ ))
|
|
target=$(readlink "$project_root/$linkpath" || true)
|
|
canonical=$(readlink -f "$project_root/$linkpath" 2>/dev/null || true)
|
|
if [[ -z "$canonical" ]]; then
|
|
canonical="$(python3 - <<'PY' "$project_root" "$linkpath" "$target"
|
|
import os, sys
|
|
root, linkpath, target = sys.argv[1:4]
|
|
print(os.path.normpath(os.path.join(os.path.dirname(os.path.join(root, linkpath)), target)))
|
|
PY
|
|
)"
|
|
fi
|
|
if [[ "$canonical" == "$project_root/local/recipes/"* ]]; then
|
|
classification="stale recipe overlay"
|
|
action="recreate or refresh the overlay under local/recipes/"
|
|
elif [[ "$canonical" == "$project_root/local/patches/"* ]]; then
|
|
classification="stale patch symlink"
|
|
action="restore the patch file and rewire the recipe symlink"
|
|
elif [[ "$canonical" == "$project_root/local/sources/"* ]]; then
|
|
classification="stale fork symlink"
|
|
action="restore the local fork source tree"
|
|
else
|
|
classification="stale symlink (unclassified)"
|
|
action="inspect the target and repair the symlink"
|
|
fi
|
|
if [[ ! -e "$project_root/$linkpath" ]]; then
|
|
printf '%s%s:1%s target=%s class=%s action=%s\n' "$c_red" "$linkpath" "$c_reset" "$target" "$classification" "$action"
|
|
case "$classification" in
|
|
"stale recipe overlay") (( stale_recipe_overlay++ )) ;;
|
|
"stale patch symlink") (( stale_patch_symlink++ )) ;;
|
|
"stale fork symlink") (( stale_fork_symlink++ )) ;;
|
|
*) (( stale_unclassified++ )) ;;
|
|
esac
|
|
(( broken++ ))
|
|
fi
|
|
done < <(find "$project_root/recipes" -type l ! -exec test -e {} \; -print | sed "s#^$project_root/##")
|
|
|
|
while IFS= read -r linkpath; do
|
|
[[ -n "$linkpath" ]] || continue
|
|
if [[ ! -e "$project_root/$linkpath" ]]; then
|
|
printf '%s%s:1%s target=%s class=%s action=update submodule path or initialize submodule\n' "$c_red" "$linkpath" "$c_reset" "missing" "missing submodule path"
|
|
(( stale_submodule++ ))
|
|
(( broken++ ))
|
|
fi
|
|
(( gitlink_count++ ))
|
|
done < <(git -C "$project_root" ls-tree -r --full-tree HEAD | awk '$1 == "160000" {print $4}')
|
|
|
|
if (( broken )); then
|
|
warn "dead symlink scan found $broken issue(s) across $total dangling link(s) and $gitlink_count gitlink(s)"
|
|
printf '%sSummary:%s recipe overlay=%s patch symlink=%s fork symlink=%s unclassified=%s submodule=%s\n' \
|
|
"$c_yellow" "$c_reset" "$stale_recipe_overlay" "$stale_patch_symlink" "$stale_fork_symlink" "$stale_unclassified" "$stale_submodule"
|
|
return 1
|
|
fi
|
|
|
|
ok "dead symlink scan clean ($total dangling links checked, $gitlink_count gitlinks checked)"
|
|
}
|
|
|
|
latest_prefix_mtime() {
|
|
local latest=0 path ts
|
|
for path in \
|
|
"$project_root/prefix/x86_64-unknown-redox/sysroot/x86_64-unknown-redox/lib/libc.a" \
|
|
"$project_root/prefix/x86_64-unknown-redox/relibc-install/x86_64-unknown-redox/lib/libc.a"; do
|
|
if [[ -e "$path" ]]; then
|
|
ts=$(stat -c %Y "$path")
|
|
(( ts > latest )) && latest=$ts
|
|
fi
|
|
done
|
|
printf '%s' "$latest"
|
|
}
|
|
|
|
fork_mtime() {
|
|
local path="$1"
|
|
git -C "$project_root" log -1 --format=%ct -- "$path" 2>/dev/null || printf '0'
|
|
}
|
|
|
|
components=(relibc kernel base)
|
|
stale=0
|
|
prefix_ts="$(latest_prefix_mtime)"
|
|
|
|
if (( simulate_staleness )); then
|
|
prefix_ts=0
|
|
fi
|
|
|
|
for component in "${components[@]}"; do
|
|
path="local/sources/$component"
|
|
fork_ts="$(fork_mtime "$path")"
|
|
delta=$((fork_ts - prefix_ts))
|
|
if (( doctor )); then
|
|
printf '%s: fork=%s prefix=%s delta=%s\n' "$path" "$fork_ts" "$prefix_ts" "$delta"
|
|
fi
|
|
if (( fork_ts > prefix_ts )); then
|
|
printf '%s: lib too old by %s seconds\n' "$component" "$delta"
|
|
stale=1
|
|
else
|
|
ok "$component: prefix fresh"
|
|
fi
|
|
done
|
|
|
|
if (( scan_dead_symlinks )); then
|
|
if scan_dead_symlinks_mode; then
|
|
exit 0
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
if (( stale )); then
|
|
warn "prefix is stale — run ./local/scripts/build-redbear.sh --upstream"
|
|
exit 1
|
|
fi
|
|
|
|
ok "prefix is fresh"
|