From 3acd48aad8be07754581650ee6400de88073290c Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 11 Jul 2026 11:01:12 +0200 Subject: Add collect_shadows dup detection + self-check Finds upstream SBo packages shadowed by a personal-tree twin, read-only, no removal. Personal package = subdir with matching .SlackBuild; prune array excludes every SBO_PERSONAL_TREES path from the search so a personal package never lists itself. Co-Authored-By: Claude Opus 4.8 --- sbo-batch-test | 26 ++++++++++++++++++++++++++ test-logic.sh | 22 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/sbo-batch-test b/sbo-batch-test index f2b9c14..c028df1 100755 --- a/sbo-batch-test +++ b/sbo-batch-test @@ -343,6 +343,32 @@ rsync_tree() { "$SBO_RSYNC_URL/" "$root/" } +# Echo (one per line) the -relative dirs of upstream packages that +# duplicate a package in a personal subtree. Reads only, never removes. A +# personal package is a subdir with a matching .SlackBuild; an upstream +# dup is a same-named depth-2 dir anywhere under outside the personal +# trees. +collect_shadows() { + local root="$1" + local -a personal_dirs=() prune=() + local dir + for dir in "${!SBO_PERSONAL_TREES[@]}"; do + [[ -d "$root/$dir" ]] || continue + personal_dirs+=("$root/$dir") + prune+=(! -path "$root/$dir/*") + done + [[ ${#personal_dirs[@]} -eq 0 ]] && return + local pkgdir pkg match + while IFS= read -r pkgdir; do + pkg=$(basename "$pkgdir") + [[ -f "$pkgdir/$pkg.SlackBuild" ]] || continue + while IFS= read -r match; do + echo "${match#"$root"/}" + done < <(find "$root" -mindepth 2 -maxdepth 2 -type d \ + -name "$pkg" "${prune[@]}") + done < <(find "${personal_dirs[@]}" -mindepth 1 -maxdepth 1 -type d) +} + # ============================================================================= # Package cache. Persistent, on-disk store of built packages so unchanged deps # are installed from cache instead of rebuilt. Layout mirrors the SBo tree: diff --git a/test-logic.sh b/test-logic.sh index 423d2b5..cbdef9d 100755 --- a/test-logic.sh +++ b/test-logic.sh @@ -152,6 +152,28 @@ echo "$ex" | grep -qx -- "--exclude=/pentesting/" && ok "rsync_excludes pentesti declare -A SBO_PERSONAL_TREES=() [[ -z "$(rsync_excludes)" ]] && ok "rsync_excludes empty for no trees" || bad "rsync_excludes should be empty, got [$(rsync_excludes)]" +# --- collect_shadows: upstream dups of personal packages ------------------- +S=$(mktemp -d) +mkslb() { mkdir -p "$S/$1/$2"; : > "$S/$1/$2/$2.SlackBuild"; } +# upstream copies +mkslb academic foo +mkslb network bar +# personal copies (win) +mkslb personal foo +mkslb pentesting bar +# decoy: personal pkg with no upstream twin +mkslb personal nomatch +# decoy: personal subdir without a .SlackBuild (ignored) +mkdir -p "$S/personal/noslb" +declare -A SBO_PERSONAL_TREES=([personal]=u1 [pentesting]=u2) + +got="$(collect_shadows "$S" | sort)" +want="$(printf 'academic/foo\nnetwork/bar\n' | sort)" +[[ "$got" == "$want" ]] && ok "collect_shadows finds upstream dups only" || bad "collect_shadows wrong; got [$got] want [$want]" +echo "$got" | grep -q "personal/" && bad "collect_shadows returned a personal path" || ok "collect_shadows excludes personal trees" +echo "$got" | grep -q "nomatch" && bad "collect_shadows invented a match for nomatch" || ok "collect_shadows ignores no-twin pkg" +rm -rf "$S" + # --- result ----------------------------------------------------------------- echo echo "$pass passed, $fail failed" -- cgit v1.2.3