diff options
| author | Danilo M. <danix@danix.xyz> | 2026-07-08 11:45:00 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-07-08 11:45:00 +0200 |
| commit | 67d4196bb3c98b0f6c00e8e514d9060b1cf7be2f (patch) | |
| tree | 7fa81814653a6e613590262f2683b913acccf983 | |
| parent | efeeeb045ee8f7d92bc718c40661df0f5fb070c7 (diff) | |
| download | mkhintfile-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.md | 36 | ||||
| -rw-r--r-- | CLAUDE.md | 16 | ||||
| -rw-r--r-- | TODO.md | 3 | ||||
| -rwxr-xr-x | mkhint | 52 | ||||
| -rw-r--r-- | mkhint.1.gz | bin | 3485 -> 3486 bytes | |||
| -rw-r--r-- | mkhint.1.md | 2 | ||||
| -rwxr-xr-x | tests/mkhint_test.sh | 39 |
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. @@ -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 @@ -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 @@ -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 Binary files differindex b2f7b41..989fd53 100644 --- a/mkhint.1.gz +++ b/mkhint.1.gz 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" |
