From a89e6799a4473ff2d182e1d3268222a9f54cea58 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 9 Jul 2026 20:17:02 +0200 Subject: feat: submodule inventory roster (Job B, set-drift) Co-Authored-By: Claude Opus 4.8 --- mkhint | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/mkhint_test.sh | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/mkhint b/mkhint index 815a30b..7921501 100755 --- a/mkhint +++ b/mkhint @@ -715,6 +715,69 @@ _fetch_submodule_sha() { printf '%s\t%s\n' "$sha" "$sr" } +# _fetch_gitmodules_paths — echo each submodule "path" line from the +# .gitmodules at ref (one per line). Non-zero on fetch fail. +_fetch_gitmodules_paths() { + local repo="${1#github:}" ref="$2" + local url="https://raw.githubusercontent.com/${repo}/${ref}/.gitmodules" + [[ -d "$TMP_DIR" ]] || mkdir -p "$TMP_DIR" + local out="${TMP_DIR}/gitmodules_${ref}" + rm -f "$out" + wget -O "$out" "$url" >&2 || return 1 + [[ -s "$out" ]] || return 1 + grep -E '^[[:space:]]*path[[:space:]]*=' "$out" | sed 's/.*=[[:space:]]*//' +} + +# detect_set_drift — print the full submodule inventory +# roster. Diffs .gitmodules@old vs @new; tags each submodule bundled/(ignored), +# with +/- change glyphs and ACTION (bundled removed) / review (new unbundled). +# FYI only, never edits. Skips with a notice if a fetch fails. +detect_set_drift() { + local pkg="$1" oldv="$2" newv="$3" + local rest="${BUNDLE_REST[$pkg]}" + local repo; read -r repo _ rest <<< "$rest" + local -A bundled=() + local pair + for pair in $rest; do bundled["${pair#*=}"]=1; done + + local -a new_paths old_paths + local gm_new gm_old + gm_new=$(_fetch_gitmodules_paths "$repo" "$newv") || { + echo " $pkg: .gitmodules@$newv unavailable — inventory skipped"; return 0; } + mapfile -t new_paths <<< "$gm_new" + if [[ "$oldv" == "$newv" ]]; then + old_paths=("${new_paths[@]}") + else + gm_old=$(_fetch_gitmodules_paths "$repo" "$oldv") || { + echo " $pkg: .gitmodules@$oldv unavailable — inventory skipped"; return 0; } + mapfile -t old_paths <<< "$gm_old" + fi + local -A in_old=() in_new=() + local p; for p in "${old_paths[@]}"; do in_old["$p"]=1; done + for p in "${new_paths[@]}"; do in_new["$p"]=1; done + + echo "" + echo "$pkg submodule inventory $oldv -> $newv:" + local glyph tag + for p in "${new_paths[@]}"; do + glyph=" "; [[ -z "${in_old[$p]:-}" ]] && glyph="+" + if [[ -n "${bundled[$p]:-}" ]]; then + tag="bundled" + else + tag="(ignored)"; [[ "$glyph" == "+" ]] && tag="review (new, not bundled)" + fi + printf ' %s %-46s %s\n' "$glyph" "$p" "$tag" + done + for p in "${old_paths[@]}"; do + [[ -n "${in_new[$p]:-}" ]] && continue + if [[ -n "${bundled[$p]:-}" ]]; then + printf ' %s %-46s %s\n' "-" "$p" "ACTION (bundled, removed upstream)" + else + printf ' %s %-46s %s\n' "-" "$p" "(ignored, removed upstream)" + fi + done +} + # reconcile_bundle_deps_url # mode = report (print only) | apply (rewrite matched changed lines + md5). # Reconciles the DOWNLOAD line's extra URLs (index >= 1) against the manifest. diff --git a/tests/mkhint_test.sh b/tests/mkhint_test.sh index 2df225a..4dc2e8c 100755 --- a/tests/mkhint_test.sh +++ b/tests/mkhint_test.sh @@ -299,6 +299,17 @@ run_sha_reconcile() { ' _ "$@" } +# run_set_drift — source the patched mkhint, load the +# bundle manifests (so BUNDLE_REST is populated), then call detect_set_drift. +run_set_drift() { + patch_mkhint + MKHINT_NOMAIN=1 bash -c ' + source "'"$PATCHED_MKHINT"'" + load_bundle_manifests + detect_set_drift "$@" + ' _ "$@" +} + # Mock wget — writes fake content, md5 will be deterministic. URLs containing # deps.txt instead serve a manifest fixture ($MOCK_BASE/manifest_fixture) if # present, so bundled-dep manifest tests can control fetch_manifest's input. @@ -331,6 +342,13 @@ elif [[ "\$url" == *api.github.com*contents* ]]; then else exit 1 fi +elif [[ "\$url" == *.gitmodules* ]]; then + ref="\${url%%/.gitmodules*}"; ref="\${ref##*/}" + if [[ -f "$MOCK_BASE/gitmodules_\$ref" ]]; then + cat "$MOCK_BASE/gitmodules_\$ref" > "\$out" + else + exit 1 + fi else echo "FAKE_CONTENT_FOR_\${url}" > "\$out" fi @@ -2404,6 +2422,55 @@ assert_contains "report foo no matching line" <(echo "$out") "foo: no matching D rm -f "$MOCK_BASE/api_foo.json" "$MOCK_HINT/openvino.hint" # T-SHA4 (--new prints reconcile report) deferred: needs --new wiring (later task). +# ── T-SET1..6: submodule inventory roster (Job B, detect_set_drift) ───────────── +echo "" +echo "T-SET1..4: submodule inventory roster — added/removed/bundled/ignored tags" +cat > "$MOCK_BASE/gitmodules_2024.4.1" << 'EOF' +[submodule "onnx"] + path = thirdparty/onnx/onnx + url = https://github.com/onnx/onnx.git +[submodule "mlas"] + path = src/plugins/intel_cpu/thirdparty/mlas + url = https://github.com/openvinotoolkit/mlas.git +[submodule "gtest"] + path = thirdparty/gtest/gtest + url = https://github.com/openvinotoolkit/googletest.git +EOF +cat > "$MOCK_BASE/gitmodules_2024.5.0" << 'EOF' +[submodule "newdep"] + path = src/plugins/foo/thirdparty/newdep + url = https://github.com/foo/newdep.git +[submodule "mlas"] + path = src/plugins/intel_cpu/thirdparty/mlas + url = https://github.com/openvinotoolkit/mlas.git +[submodule "gtest"] + path = thirdparty/gtest/gtest + url = https://github.com/openvinotoolkit/googletest.git +EOF +cat > "$MOCK_BASE/bundle-manifests" << 'EOF' +openvino sha github:openvinotoolkit/openvino {VERSION} mlas=src/plugins/intel_cpu/thirdparty/mlas onnx=thirdparty/onnx/onnx +EOF +out=$(run_set_drift openvino 2024.4.1 2024.5.0) +assert_contains "onnx removed shown" <(echo "$out") "thirdparty/onnx/onnx" +assert_contains "onnx ACTION" <(echo "$out") "ACTION (bundled, removed upstream)" +assert_contains "newdep added review" <(echo "$out") "review (new, not bundled)" +assert_contains "mlas bundled" <(echo "$out") "bundled" +assert_contains "gtest ignored" <(echo "$out") "(ignored)" + +# ── T-SET5: fetch fail at old ref (no fixture) — inventory skipped notice ─────── +echo "" +echo "T-SET5: fetch failure at old ref — inventory skipped" +out=$(run_set_drift openvino 1999.0.0 2024.5.0) +assert_contains "fetch-fail skip notice" <(echo "$out") "inventory skipped" + +# ── T-SET6: force no-bump old==new — roster prints, no + glyph ────────────────── +echo "" +echo "T-SET6: old==new (force) — roster prints, no + glyph" +out=$(run_set_drift openvino 2024.5.0 2024.5.0) +assert_contains "roster on force" <(echo "$out") "submodule inventory 2024.5.0 -> 2024.5.0" +assert_not_contains "no + glyph" <(echo "$out") "+ src/plugins/foo" +rm -f "$MOCK_BASE/gitmodules_2024.4.1" "$MOCK_BASE/gitmodules_2024.5.0" + # ─── SUMMARY ────────────────────────────────────────────────────────────────── teardown -- cgit v1.2.3