summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-07-08 11:45:00 +0200
committerDanilo M. <danix@danix.xyz>2026-07-08 11:45:00 +0200
commit67d4196bb3c98b0f6c00e8e514d9060b1cf7be2f (patch)
tree7fa81814653a6e613590262f2683b913acccf983
parentefeeeb045ee8f7d92bc718c40661df0f5fb070c7 (diff)
downloadmkhintfile-67d4196bb3c98b0f6c00e8e514d9060b1cf7be2f.tar.gz
mkhintfile-67d4196bb3c98b0f6c00e8e514d9060b1cf7be2f.zip
fix: complete version-aware reconcile against real URL shapes; release v1.2.2v1.2.2
1.2.1 made the bundled-dep reconcile version-aware but _url_version mis-parsed several real-world URL shapes, so 1.2.1 was never correct in the field (found by running mkhint -C --force neovim against the live 0.12.4 hint). _url_version now derives the version by stripping the URL's own github repo name from the basename: - dep names containing digits/dashes (lua-compat-5.3) parse correctly instead of splitting the name as a version - a bare-tag basename with no name prefix is taken as the whole version, fixing package-rev suffixes (luv 1.52.1-0 was truncated to 0) - non-github and the shared neovim/deps blob host fall back to the trailing-version/sha heuristic _url_repo is lowercased so JuliaStrings/utf8proc matches juliastrings/utf8proc (github repos are case-insensitive); utf8proc had reported no-match and appeared in the manifest-only FYI. Verified against all 13 live neovim 0.12.4 bundled deps: all match and report current, no false change, a real bump still detected. Adds T-BM22 (one case per URL-shape class) and T-BM23 (case-insensitive repo match); T-BM17 unchanged. 182 passed. Bump MKHINT_VERSION and man title to 1.2.2, rebuild mkhint.1.gz. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-rw-r--r--CHANGELOG.md36
-rw-r--r--CLAUDE.md16
-rw-r--r--TODO.md3
-rwxr-xr-xmkhint52
-rw-r--r--mkhint.1.gzbin3485 -> 3486 bytes
-rw-r--r--mkhint.1.md2
-rwxr-xr-xtests/mkhint_test.sh39
7 files changed, 117 insertions, 31 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 32fe3a9..2a501e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,17 +4,37 @@ All notable changes to this project are documented here. The format is based on
[Keep a Changelog](https://keepachangelog.com/), and this project adheres to
[Semantic Versioning](https://semver.org/).
+## [1.2.2] - 2026-07-08
+
+### Fixed
+- Completes the 1.2.1 version-aware reconcile against real-world URL shapes.
+ Verified against all 13 bundled deps of the live neovim 0.12.4 hint; 1.2.1's
+ `_url_version` mis-parsed several of them and 1.2.1 was never correct in the
+ field.
+- `_url_version` now derives the version by stripping the URL's own github repo
+ name from the basename, so dep names that themselves contain digits/dashes
+ (e.g. `lua-compat-5.3`) parse correctly instead of splitting the name as a
+ version. A bare-tag basename (no name prefix) is taken as the whole version,
+ which fixes package-rev suffixes like `luv` `1.52.1-0` being truncated to `0`.
+ Non-github hosts and the shared `neovim/deps` blob host fall back to the
+ trailing-version/sha heuristic.
+- `_url_repo` is now lowercased, so a dep that appears as `JuliaStrings/utf8proc`
+ in the hint and `juliastrings/utf8proc` in the manifest matches (github
+ owners/repos are case-insensitive) instead of being reported as unmatched and
+ duplicated in the manifest-only FYI.
+
## [1.2.1] - 2026-07-08
### Fixed
-- Bundled-dep reconcile now detects change by upstream version, not raw URL
- string. Manifests serve bare-tag archive URLs
- (`.../archive/v0.26.7.tar.gz`) while hints use the SBo-fetched tree shape
- (`.../archive/v0.26.7/tree-sitter-0.26.7.tar.gz`); these are the same
- version in different path shapes, so the old string comparison flagged every
- dep as changed at a version that had not moved. Reconcile now extracts the
- version from each URL (`_url_version`) and only rewrites a line when the
- version actually differs.
+- Bundled-dep reconcile detects change by upstream version, not raw URL string.
+ Manifests serve bare-tag archive URLs (`.../archive/v0.26.7.tar.gz`) while
+ hints use the SBo-fetched tree shape
+ (`.../archive/v0.26.7/tree-sitter-0.26.7.tar.gz`); these are the same version
+ in different path shapes, so the old string comparison flagged every dep as
+ changed at a version that had not moved. Reconcile now extracts the version
+ from each URL (`_url_version`) and only rewrites a line when the version
+ actually differs. (URL-shape parsing was incomplete in this release; see
+ 1.2.2.)
- The changed-deps report now shows `name old-ver -> new-ver` from the parsed
identity and version, instead of version-stripped URL basenames.
diff --git a/CLAUDE.md b/CLAUDE.md
index 77af699..16876c3 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -155,12 +155,18 @@ When adding new features, add a corresponding test case to `tests/mkhint_test.sh
the upstream deps manifest (`NAME_URL`/`NAME_SHA256` pairs, e.g. neovim's
`cmake.deps/deps.txt`), matches each extra `DOWNLOAD` line via
`match_dep_url` (repo-path first, exact basename-stem fallback for blob
- hosts). A matched line is rewritten only when its upstream *version* differs
- (`_url_version` parses the version from each URL basename and normalizes it),
- not when only the URL path shape differs, so a manifest's bare-tag
- `archive/v0.26.7.tar.gz` and the hint's SBo-fetched
+ hosts; `_url_repo` is lowercased so a `JuliaStrings/utf8proc` hint matches a
+ `juliastrings/utf8proc` manifest — github repos are case-insensitive). A
+ matched line is rewritten only when its upstream *version* differs
+ (`_url_version`), not when only the URL path shape differs, so a manifest's
+ bare-tag `archive/v0.26.7.tar.gz` and the hint's SBo-fetched
`archive/v0.26.7/tree-sitter-0.26.7.tar.gz` at the same version are treated as
- current. Changed lines get their md5 recomputed; the report shows
+ current. `_url_version` derives the version by stripping the URL's own github
+ repo name from the basename (so digit/dash-containing dep names like
+ `lua-compat-5.3` parse), treats a bare-tag basename as the whole version
+ (package-rev suffixes like `1.52.1-0`), and falls back to a
+ trailing-version/sha heuristic for non-github and the shared `neovim/deps`
+ blob host. Changed lines get their md5 recomputed; the report shows
`name old-ver -> new-ver`. Runs automatically when the primary changed this
run, otherwise only with `--force` (check-only flag). `--new` on a listed
package prints the reconcile report without changing the hint. Manifest deps
diff --git a/TODO.md b/TODO.md
index 0d0d5bf..7ba7907 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,7 +1,6 @@
## Post-1.2.0 (bundled-dep feature followups)
- - [x] **v1.2.1 (bug): reconcile change-detection is now version-aware.** `reconcile_bundle_deps` detects change via `_url_version` (version parsed from each URL basename, normalized), not raw URL string. Report shows `name old-ver -> new-ver`. Regression test T-BM17. Compares version strings only, not `NAME_SHA256`; add sha compare if a same-version-different-content case ever appears.
- - [ ] verify on the VM that utf8proc (previously reported no-match AND in the FYI) now reconciles correctly with the version-aware fix; if it still no-matches, it is a `match_dep_url` stem issue, not change-detection.
+ - [x] **v1.2.1/1.2.2 (bug): reconcile change-detection is version-aware.** 1.2.1 switched `reconcile_bundle_deps` to detect change via `_url_version` (parsed version, not raw URL string) but mis-parsed several real URL shapes; 1.2.2 completes it. `_url_version` strips the URL's own github repo name from the basename (handles digit/dash dep names like `lua-compat-5.3`, bare-tag package-rev suffixes like `1.52.1-0`, sha pins), and `_url_repo` is lowercased (fixes the `JuliaStrings/utf8proc` vs `juliastrings/utf8proc` case mismatch that had utf8proc reporting no-match + in the FYI). Report shows `name old-ver -> new-ver`. Verified against all 13 live neovim 0.12.4 deps: all match + current, no false change, real bump still detected. Tests T-BM17/22/23. Compares version strings only, not `NAME_SHA256`; add sha compare if a same-version-different-content case ever appears.
- [ ] add a `--special` flag to add a package to the bundled list, asking for a link to it's upstream deps list file
- [ ] consider splitting `mkhint` into multiple files for easier maintenance
- [ ] add a noDL column to `--list` similar to what we do with DelReq
diff --git a/mkhint b/mkhint
index f3ff50a..2a95cf2 100755
--- a/mkhint
+++ b/mkhint
@@ -45,7 +45,7 @@ if [[ ! -d $TMP_DIR ]]; then
mkdir $TMP_DIR
fi
-readonly MKHINT_VERSION="1.2.1"
+readonly MKHINT_VERSION="1.2.2"
# Variables
VERSION=""
@@ -458,31 +458,53 @@ _url_stem() {
}
# _url_version <url> — extract the version token from a download URL's basename.
-# Same archive stripping as _url_stem, then take the trailing version: a
-# leading-v-or-digit tail after a "-" separator, else the whole basename if it
-# is itself a version (e.g. "v0.26.7"). Used to detect real version drift
-# independent of URL path shape. Empty if no version found.
+# Dep names can themselves contain digits/dashes (lua-compat-5.3, win32yank-x64),
+# so no fixed regex can split name from version. When the URL is a github one we
+# know the repo name: strip a leading "<repo>-"/"<repo>_" prefix (case-insensitive,
+# since github is case-insensitive: LuaJIT vs luajit) and the rest is the version.
+# Otherwise fall back to a trailing-version / trailing-sha heuristic, then drop a
+# leading "v". Both sides of a matched pair reduce to "the part that isn't the
+# name", so equal versions in different URL shapes compare equal.
+# ponytail: name comes from the github repo. A non-github host whose basename is
+# "<digit-containing-name>-<version>" can't derive the name and may misparse; add
+# a manifest name hint if such a dep ever appears.
_url_version() {
- local base="${1##*/}"
+ local url="$1"
+ local base="${url##*/}"
base="${base%.tar.gz}"; base="${base%.tar.xz}"; base="${base%.tar.bz2}"
base="${base%.zip}"; base="${base%.tgz}"
- local ver=""
- if [[ "$base" =~ -([vV]?[0-9][^/]*)$ ]]; then
- ver="${BASH_REMATCH[1]}"
+ local ver="$base"
+ local rslug; rslug=$(_url_repo "$url")
+ local repo="${rslug#*/}" # bare repo name, lowercased
+ # A shared blob repo (neovim/deps/raw/.../opt/<name>-<ver>) names the host,
+ # not the dep, so its repo name is useless — fall through to the heuristic,
+ # same exclusion match_dep_url makes.
+ [[ "$rslug" == */deps ]] && repo=""
+ local base_lc="${base,,}"
+ if [[ -n "$repo" ]]; then
+ # github: name is known. Strip a "<repo>[-_]" prefix if present; else the
+ # whole basename is the version (bare-tag shape, e.g. "1.52.1-0", "v0.13").
+ if [[ "$base_lc" == "$repo-"* || "$base_lc" == "${repo}_"* ]]; then
+ ver="${base:${#repo}+1}"
+ else
+ ver="$base"
+ fi
+ elif [[ "$base" =~ -([vV]?[0-9][^/]*)$ ]]; then
+ ver="${BASH_REMATCH[1]}" # non-github: trailing version
elif [[ "$base" =~ -([0-9a-f]{7,})$ ]]; then
- ver="${BASH_REMATCH[1]}"
- elif [[ "$base" =~ ^([vV]?[0-9][^/]*)$ ]]; then
- ver="${BASH_REMATCH[1]}"
- elif [[ "$base" =~ ^([0-9a-f]{7,})$ ]]; then
- ver="${BASH_REMATCH[1]}"
+ ver="${BASH_REMATCH[1]}" # non-github: trailing sha
fi
ver="${ver#[vV]}"
printf '%s\n' "$(_normalize_version "$ver")"
}
# _url_repo <url> — echo owner/repo for a github URL, empty otherwise.
+# Lowercased: github owners/repos are case-insensitive, and the same dep can
+# appear as JuliaStrings/utf8proc in one URL and juliastrings/utf8proc in another.
_url_repo() {
- [[ "$1" =~ github\.com/([^/]+)/([^/]+) ]] && printf '%s/%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]%.git}"
+ [[ "$1" =~ github\.com/([^/]+)/([^/]+) ]] || return 0
+ local r; printf -v r '%s/%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]%.git}"
+ printf '%s\n' "${r,,}"
}
# match_dep_url <hint_url> <manifest_url_list> — echo the manifest URL that
diff --git a/mkhint.1.gz b/mkhint.1.gz
index b2f7b41..989fd53 100644
--- a/mkhint.1.gz
+++ b/mkhint.1.gz
Binary files differ
diff --git a/mkhint.1.md b/mkhint.1.md
index f4f43e0..2c910a1 100644
--- a/mkhint.1.md
+++ b/mkhint.1.md
@@ -1,4 +1,4 @@
-% MKHINT(1) mkhint 1.2.1 | User Commands
+% MKHINT(1) mkhint 1.2.2 | User Commands
% Danilo M.
% July 2026
diff --git a/tests/mkhint_test.sh b/tests/mkhint_test.sh
index 316d9b7..eac0fd2 100755
--- a/tests/mkhint_test.sh
+++ b/tests/mkhint_test.sh
@@ -1642,6 +1642,45 @@ echo "$rep17" | grep -q 'all current' \
|| { echo " FAIL: T-BM17 falsely flagged change. out=$rep17"; (( FAIL++ )); ERRORS+=("T-BM17"); }
rm -f "$MOCK_BASE/manifest_fixture" "$MOCK_HINT/nvim17.hint" "$MOCK_BASE/nvim17.before"
+# ── T-BM22: _url_version yields equal versions across URL-shape classes ───────
+# One case per shape class, not per dep: name-carrying vs bare-tag; name with an
+# embedded digit-dot (lua-compat-5.3); package-rev suffix (luv 1.52.1-0); sha
+# pin (luajit); mixed-case repo (utf8proc); shared /deps blob (lpeg). Each pair
+# is the same upstream version in two shapes → _url_version must match.
+echo ""
+echo "T-BM22: _url_version equal across shape classes (name/bare, digit-name, pkgrev, sha, case, /deps)"
+declare -a UV_PAIRS=(
+ # hint_url|manifest_url|label
+ "https://github.com/tree-sitter/tree-sitter/archive/v0.26.7/tree-sitter-0.26.7.tar.gz|https://github.com/tree-sitter/tree-sitter/archive/v0.26.7.tar.gz|name-vs-bare"
+ "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13/lua-compat-5.3-0.13.tar.gz|https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.tar.gz|digit-in-name"
+ "https://github.com/luvit/luv/releases/download/1.52.1-0/luv-1.52.1-0.tar.gz|https://github.com/luvit/luv/archive/1.52.1-0.tar.gz|pkgrev-suffix"
+ "https://github.com/luajit/luajit/archive/fbb36bb/LuaJIT-fbb36bb6bfa88716a47c58bcf9ce9f2ef752abac.tar.gz|https://github.com/luajit/luajit/archive/fbb36bb6bfa88716a47c58bcf9ce9f2ef752abac.tar.gz|sha-pin-mixedcase"
+ "https://github.com/JuliaStrings/utf8proc/archive/v2.11.3/utf8proc-2.11.3.tar.gz|https://github.com/juliastrings/utf8proc/archive/v2.11.3.tar.gz|mixed-case-repo"
+ "https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.1.0.tar.gz|https://github.com/neovim/deps/raw/deadbeef1234567/opt/lpeg-1.1.0.tar.gz|deps-blob"
+)
+uv_fail=""
+for pair in "${UV_PAIRS[@]}"; do
+ IFS='|' read -r huv muv lbl <<< "$pair"
+ hv=$(bash -c "source '$SCRIPT' 2>/dev/null; _url_version '$huv'")
+ mv=$(bash -c "source '$SCRIPT' 2>/dev/null; _url_version '$muv'")
+ [[ -n "$hv" && "$hv" == "$mv" ]] || uv_fail+=" $lbl($hv≠$mv)"
+done
+# and a real bump MUST differ
+bump_h=$(bash -c "source '$SCRIPT' 2>/dev/null; _url_version 'https://github.com/tree-sitter/tree-sitter/archive/v0.26.7/tree-sitter-0.26.7.tar.gz'")
+bump_m=$(bash -c "source '$SCRIPT' 2>/dev/null; _url_version 'https://github.com/tree-sitter/tree-sitter/archive/v0.26.8.tar.gz'")
+[[ "$bump_h" != "$bump_m" ]] || uv_fail+=" real-bump-not-detected"
+[[ -z "$uv_fail" ]] \
+ && { echo " PASS: all shape classes equal, real bump differs"; (( PASS++ )); } \
+ || { echo " FAIL: T-BM22:$uv_fail"; (( FAIL++ )); ERRORS+=("T-BM22"); }
+
+# ── T-BM23: match_dep_url is case-insensitive on the repo slug ────────────────
+echo ""
+echo "T-BM23: match_dep_url matches JuliaStrings/utf8proc to juliastrings/utf8proc"
+r=$(bash -c "$BM_SRC; match_dep_url 'https://github.com/JuliaStrings/utf8proc/archive/v2.11.3/utf8proc-2.11.3.tar.gz' \"\$1\"" _ 'https://github.com/juliastrings/utf8proc/archive/v2.11.3.tar.gz')
+[[ "$r" == 'https://github.com/juliastrings/utf8proc/archive/v2.11.3.tar.gz' ]] \
+ && { echo " PASS: case-insensitive repo match"; (( PASS++ )); } \
+ || { echo " FAIL: case match got '$r'"; (( FAIL++ )); ERRORS+=("T-BM23"); }
+
# ── T-BM10: --new listed pkg prints reconcile report, does NOT rewrite ───────
echo ""
echo "T-BM10: --new listed pkg → manifest report, hint not rewritten by manifest"