aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-07-07 18:23:03 +0200
committerDanilo M. <danix@danix.xyz>2026-07-07 18:23:03 +0200
commit375b2b74e3ff11a7029ec8de7ca8cb8167b2f6a1 (patch)
treef1341bb7029ef9c7ac12c75d50737c4621384e6e
parent6b7ca94be115b7678074b3880b8f127d17c5267e (diff)
downloadmkhintfile-375b2b74e3ff11a7029ec8de7ca8cb8167b2f6a1.tar.gz
mkhintfile-375b2b74e3ff11a7029ec8de7ca8cb8167b2f6a1.zip
feat: match_dep_url maps a hint download line to a manifest URL
Repo-path match first, exact basename-stem fallback for blob hosts. Blob host repo (owner/deps) is excluded from repo-path matching so it resolves by stem. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-rwxr-xr-xmkhint49
-rwxr-xr-xtests/mkhint_test.sh38
2 files changed, 87 insertions, 0 deletions
diff --git a/mkhint b/mkhint
index 50e2412..7c593b8 100755
--- a/mkhint
+++ b/mkhint
@@ -436,6 +436,55 @@ parse_manifest() {
[[ -f "$file" ]] || return 0
awk '/_URL[[:space:]]/ { print $2 }' "$file"
}
+
+# _url_stem <url> — reduce a download URL's basename to a comparison stem:
+# drop a trailing archive extension, then a trailing -<version> or the version
+# is the whole tail after the name. Version = [vV]?[0-9]... or a 7+ hex sha.
+_url_stem() {
+ local base="${1##*/}"
+ base="${base%.tar.gz}"; base="${base%.tar.xz}"; base="${base%.tar.bz2}"
+ base="${base%.zip}"; base="${base%.tgz}"
+ # strip a trailing -<version> (version starts with optional v then a digit,
+ # or is a 7+ char hex sha)
+ if [[ "$base" =~ ^(.+)-[vV]?[0-9].*$ ]]; then
+ base="${BASH_REMATCH[1]}"
+ elif [[ "$base" =~ ^(.+)-[0-9a-f]{7,}$ ]]; then
+ base="${BASH_REMATCH[1]}"
+ fi
+ printf '%s\n' "$base"
+}
+
+# _url_repo <url> — echo owner/repo for a github URL, empty otherwise.
+_url_repo() {
+ [[ "$1" =~ github\.com/([^/]+)/([^/]+) ]] && printf '%s/%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]%.git}"
+}
+
+# match_dep_url <hint_url> <manifest_url_list> — echo the manifest URL that
+# corresponds to hint_url, or nothing. Repo-path match first, then exact
+# basename-stem fallback (for blob hosts where the repo path is ambiguous).
+match_dep_url() {
+ local hint_url="$1" list="$2"
+ local hrepo; hrepo=$(_url_repo "$hint_url")
+ local m mrepo
+ # pass 1: repo-path (skip the shared-blob-host repo neovim/deps so a blob
+ # URL never wins on repo path; it must match on stem instead)
+ if [[ -n "$hrepo" && "$hrepo" != */deps ]]; then
+ while IFS= read -r m; do
+ [[ -z "$m" ]] && continue
+ mrepo=$(_url_repo "$m")
+ if [[ -n "$mrepo" && "$mrepo" != */deps && "$mrepo" == "$hrepo" ]]; then
+ printf '%s\n' "$m"; return 0
+ fi
+ done <<< "$list"
+ fi
+ # pass 2: exact stem
+ local hstem; hstem=$(_url_stem "$hint_url")
+ while IFS= read -r m; do
+ [[ -z "$m" ]] && continue
+ [[ "$(_url_stem "$m")" == "$hstem" ]] && { printf '%s\n' "$m"; return 0; }
+ done <<< "$list"
+ return 1
+}
# ── end bundled-dep manifest handling ─────────────────────────────────────────
# Create new hint file
diff --git a/tests/mkhint_test.sh b/tests/mkhint_test.sh
index 9830f3b..908b738 100755
--- a/tests/mkhint_test.sh
+++ b/tests/mkhint_test.sh
@@ -1473,6 +1473,44 @@ echo "$bm_out" | grep -qx 'https://github.com/libuv/libuv/archive/v1.52.1.tar.gz
&& { echo " PASS: parse_manifest URLs only"; (( PASS++ )); } \
|| { echo " FAIL: parse_manifest: $bm_out"; (( FAIL++ )); ERRORS+=("T-BM1"); }
+# ── T-BM2: match_dep_url repo-path hit ───────────────────────────────────────
+echo ""
+echo "T-BM2: match_dep_url matches by owner/repo path"
+BM_SRC='source <(sed -n "/# ── bundled-dep manifest handling/,/# ── end bundled-dep/p" '"$SCRIPT"')'
+manifest_urls='https://github.com/tree-sitter/tree-sitter/archive/v0.26.8.tar.gz
+https://github.com/luvit/luv/archive/1.53.0-0.tar.gz'
+r=$(bash -c "$BM_SRC; match_dep_url 'https://github.com/tree-sitter/tree-sitter/archive/v0.26.7/tree-sitter-0.26.7.tar.gz' \"\$1\"" _ "$manifest_urls")
+[[ "$r" == 'https://github.com/tree-sitter/tree-sitter/archive/v0.26.8.tar.gz' ]] \
+ && { echo " PASS: repo-path match"; (( PASS++ )); } \
+ || { echo " FAIL: repo-path match got '$r'"; (( FAIL++ )); ERRORS+=("T-BM2"); }
+
+# ── T-BM3: match_dep_url stem fallback for blob host ─────────────────────────
+echo ""
+echo "T-BM3: match_dep_url stem fallback (neovim/deps/raw blob → lpeg)"
+manifest_urls='https://github.com/neovim/deps/raw/deadbeef1234567/opt/lpeg-1.1.0.tar.gz'
+r=$(bash -c "$BM_SRC; match_dep_url 'https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.1.0.tar.gz' \"\$1\"" _ "$manifest_urls")
+[[ "$r" == 'https://github.com/neovim/deps/raw/deadbeef1234567/opt/lpeg-1.1.0.tar.gz' ]] \
+ && { echo " PASS: stem fallback match"; (( PASS++ )); } \
+ || { echo " FAIL: stem fallback got '$r'"; (( FAIL++ )); ERRORS+=("T-BM3"); }
+
+# ── T-BM4: match_dep_url no false prefix match ───────────────────────────────
+echo ""
+echo "T-BM4: match_dep_url does not match tree-sitter to tree-sitter-c"
+manifest_urls='https://github.com/tree-sitter/tree-sitter-c/archive/v0.24.1.tar.gz'
+r=$(bash -c "$BM_SRC; match_dep_url 'https://example.com/foo/tree-sitter-0.26.7.tar.gz' \"\$1\"" _ "$manifest_urls") || true
+[[ -z "$r" ]] \
+ && { echo " PASS: no false prefix match"; (( PASS++ )); } \
+ || { echo " FAIL: false match got '$r'"; (( FAIL++ )); ERRORS+=("T-BM4"); }
+
+# ── T-BM5: match_dep_url no match → empty ────────────────────────────────────
+echo ""
+echo "T-BM5: match_dep_url returns empty on no match"
+manifest_urls='https://github.com/foo/bar/archive/v1.0.tar.gz'
+r=$(bash -c "$BM_SRC; match_dep_url 'https://github.com/baz/qux/archive/v2.0.tar.gz' \"\$1\"" _ "$manifest_urls") || true
+[[ -z "$r" ]] \
+ && { echo " PASS: empty on no match"; (( PASS++ )); } \
+ || { echo " FAIL: expected empty got '$r'"; (( FAIL++ )); ERRORS+=("T-BM5"); }
+
# ─── SUMMARY ──────────────────────────────────────────────────────────────────
teardown