scripts: extend check-prefix-freshness.sh with dead-symlink scan
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.)
This commit is contained in:
@@ -22,28 +22,93 @@ fail() { printf '%sFAIL%s: %s\n' "$c_red" "$c_reset" "$*" >&2; }
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [--doctor] [--simulate-staleness]
|
||||
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 \
|
||||
@@ -85,6 +150,13 @@ for component in "${components[@]}"; do
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user