diff options
| -rwxr-xr-x | .extras/test-build | 96 | ||||
| -rw-r--r-- | .extras/test-logic.sh | 26 |
2 files changed, 122 insertions, 0 deletions
diff --git a/.extras/test-build b/.extras/test-build index 4d3f158..fa24fa6 100755 --- a/.extras/test-build +++ b/.extras/test-build @@ -132,10 +132,106 @@ EOF fi } +# ============================================================================= +# SBo tree lookup +# ============================================================================= +# In this tool there is one active tree per run, but the resolver reads an array +# named SBO_TREE_ROOTS so the ported logic and its self-check match sbo-batch-test. +# main() sets SBO_TREE_ROOTS=("$ACTIVE_TREE") after require_config. +declare -a SBO_TREE_ROOTS=() + +find_slackbuild_dir() { + local prog="$1" root d + for root in "${SBO_TREE_ROOTS[@]}"; do + [[ -d "$root" ]] || continue + for d in "$root"/*/"$prog"; do + if [[ -d "$d" && -f "$d/$prog.info" ]]; then + echo "$d"; return 0 + fi + done + done + return 1 +} + +category_of() { basename "$(dirname "$1")"; } +pkg_key() { echo "$(category_of "$1")/$(basename "$1")"; } + +read_requires() { + local info="$1" + # shellcheck disable=SC1090 + ( set +u; source "$info"; echo "${REQUIRES:-}" ) +} + +version_of() { + local dir="$1" + local info="$dir/$(basename "$dir").info" + [[ -f "$info" ]] || return + local v; v="$(grep -m1 '^VERSION=' "$info" | cut -d'"' -f2)" + echo "$v" +} + +# ============================================================================= +# DEPENDENCY RESOLUTION (topo sort + cycle detection, LOCAL tree only) +# ============================================================================= +declare -a RESOLVED_ORDER=() +declare -A UNMET=() +declare -a CYCLES=() +declare -A HAS_README=() +declare -A _vstate=() + +# Is a prog already present in the container base? Overridden at build time to +# consult the image; in resolution we treat "in base" as a callback so the pure +# topo logic stays testable. Default: not in base (self-check has no base db). +installed_in_base() { return 1; } + +_resolve_visit() { + local dir="$1" parent="$2" + local key; key="$(basename "$dir")" + + if [[ "${_vstate[$dir]:-}" == "1" ]]; then return 0; fi + if [[ "${_vstate[$dir]:-}" == "0" ]]; then + CYCLES+=("cycle involving $key (pulled in via $parent)") + return 1 + fi + _vstate["$dir"]=0 + + local info="$dir/$(basename "$dir").info" + local req tok depdir rc=0 + req="$(read_requires "$info")" + for tok in $req; do + if [[ "$tok" == "%README%" ]]; then + HAS_README["$dir"]=1 + continue + fi + if depdir="$(find_slackbuild_dir "$tok")"; then + _resolve_visit "$depdir" "$key" || rc=1 + elif installed_in_base "$tok"; then + : + else + UNMET["$tok"]="needed by $key" + rc=1 + fi + done + + _vstate["$dir"]=1 + RESOLVED_ORDER+=("$dir") + return $rc +} + +resolve_target() { + local dir="$1" + RESOLVED_ORDER=() + CYCLES=() + UNMET=() + _vstate=() + _resolve_visit "$dir" "(top)" +} + main() { parse_args "$@" init_color require_config + SBO_TREE_ROOTS=("$ACTIVE_TREE") } main "$@" diff --git a/.extras/test-logic.sh b/.extras/test-logic.sh index 81a0841..027fdb9 100644 --- a/.extras/test-logic.sh +++ b/.extras/test-logic.sh @@ -44,6 +44,32 @@ VERSION_ID="15.0"; select_version_paths [[ "$ACTIVE_TREE" == "/trees/stable" ]] && ok "15.0 -> stable tree" || bad "stable tree wrong: [$ACTIVE_TREE]" [[ "$ACTIVE_IMAGE" == "sbo-testbuild:15.0" ]] && ok "15.0 -> stable image" || bad "stable image wrong: [$ACTIVE_IMAGE]" +# --- resolution ------------------------------------------------------------- +# Fake SBo tree under one category. mk <prog> "<REQUIRES>". +mk() { mkdir -p "$T/cat/$1"; echo "REQUIRES=\"$2\"" > "$T/cat/$1/$1.info"; } +mk c "" +mk b "c" +mk a "b %README%" +mk d "nonexistentpkg" +mk e "f" +mk f "e" +mk g "b" + +SBO_TREE_ROOTS=("$T") # resolver reads this global (set by select in real runs) + +resolve_target "$T/cat/a" +order=""; for x in "${RESOLVED_ORDER[@]}"; do order+="$(basename "$x") "; done +order="${order% }" +[[ "$order" == "c b a" ]] && ok "topo order c b a" || bad "topo order, got: [$order]" +[[ "${HAS_README[$T/cat/a]:-}" == "1" ]] && ok "%README% recorded" || bad "%README% not recorded" +[[ ${#UNMET[@]} -eq 0 ]] && ok "no false unmet" || bad "unexpected unmet" + +resolve_target "$T/cat/d" +[[ ${#UNMET[@]} -eq 1 ]] && ok "unmet-dep caught" || bad "unmet-dep missed" + +resolve_target "$T/cat/e" +[[ ${#CYCLES[@]} -ge 1 ]] && ok "cycle caught" || bad "cycle missed" + echo echo "$pass passed, $fail failed" [[ $fail -eq 0 ]] || exit 1 |
