aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-07-09 17:22:55 +0200
committerDanilo M. <danix@danix.xyz>2026-07-09 17:22:55 +0200
commite94e3fe6e1d30a856913992aafb35bc7dfa2912d (patch)
treefc39d885612d6941e7f4d261ec088840c95367fe
parentd74e9388d7d0581758d7aebe699e65c45f7bafb0 (diff)
downloadmkhintfile-e94e3fe6e1d30a856913992aafb35bc7dfa2912d.tar.gz
mkhintfile-e94e3fe6e1d30a856913992aafb35bc7dfa2912d.zip
feat: --info version-compare row; fix -i completion; release v1.2.6v1.2.6
--info/-i now prints a version-compare row between the header and the README: SBo .info version vs the hint's, greening the higher side (< / >), yellow on equal (=), '(no hint)' when no hint carries a version, skipped when the .info has no version. Header stays pinned, version row scrolls with the README. Completion: -i now completes package names (was flag-only); package-name completion for -n/-i drops the broken -maxdepth 2 .info scan for a param-expansion sweep of REPO_DIR/*/*/ dirs, ~7s -> ~60ms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-rw-r--r--CHANGELOG.md18
-rw-r--r--CLAUDE.md2
-rw-r--r--TODO.md3
-rwxr-xr-xmkhint46
-rw-r--r--mkhint.1.gzbin3837 -> 3958 bytes
-rw-r--r--mkhint.1.md16
-rw-r--r--mkhint.bash-completion13
-rwxr-xr-xtests/mkhint_test.sh57
8 files changed, 136 insertions, 19 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26b4cbf..382f247 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,24 @@ 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.6] - 2026-07-09
+
+### Added
+- `--info` / `-i <pkg>`: adds a version-compare row between the header and the
+ README, comparing the SBo `.info` VERSION against the hint's VERSION. Shows
+ `SBo: x < Hint: y` (or `>`) greening the higher side, `SBo: x = Hint: y` in
+ yellow when equal, or `SBo: x (no hint)` when no hint carries a version.
+ Skipped when the `.info` has no VERSION. Header stays pinned; the version row
+ scrolls with the README.
+
+### Fixed
+- Bash completion: `--info`/`-i` now completes package names from the repo
+ (previously fell through to flag completion). Package-name completion for
+ `--new`/`-n` and `-i` no longer relies on a `-maxdepth 2` `.info` scan that
+ matched nothing on the real `category/pkg/pkg.info` layout; it enumerates the
+ `REPO_DIR/*/*/` package dirs with pure param-expansion (no per-dir `basename`
+ fork), cutting completion time from ~7s to ~60ms on a full repo.
+
## [1.2.5] - 2026-07-09
### Added
diff --git a/CLAUDE.md b/CLAUDE.md
index f41a7bf..e83f633 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -176,7 +176,7 @@ When adding new features, add a corresponding test case to `tests/mkhint_test.sh
`fetch_manifest`, `parse_manifest`, `match_dep_url`, `_url_version`,
`reconcile_bundle_deps`.
- `--delete` / `-d`: removes hint file and `.bak` if present. Accepts multiple package names. Exits 2 on first missing file.
-- `--info` / `-i <pkg>`: globs `REPO_DIR/*/pkg/` for the category, prints the green `category/program` header then the README, paged with sticky header (`less --header=1`) only when the README is taller than the terminal (inline when it fits or when piped), missing package exits 2, missing README prints `(no README)` and exits 0. Mutually exclusive with `-V`/`-f`/`-n`. Handler `show_info`.
+- `--info` / `-i <pkg>`: globs `REPO_DIR/*/pkg/` for the category, prints the green `category/program` header, then a version-compare row, then the README, paged with sticky header (`less --header=1`) only when the README is taller than the terminal (inline when it fits or when piped), missing package exits 2, missing README prints `(no README)` and exits 0. Mutually exclusive with `-V`/`-f`/`-n`. Handler `show_info`. The version row compares the SBo `.info` VERSION against the hint's (both via `grep "^VERSION" | cut -d '"' -f2` from `<dir>/<pkg>.info` and `HINT_DIR/<pkg>.hint`), normalized with `_normalize_version`: equal → whole row yellow with `=`; differ → `sort -V` greens the higher side with `<`/`>` pointing at it; hint absent/versionless → `SBo: x (no hint)`; `.info` without VERSION → row skipped. Header stays pinned (`--header=1`); the version row is body line 1 and scrolls with the README.
- Downloads go to `/tmp/mkhint/download` (single shared temp file, deleted after md5 calculation).
- Multiline `DOWNLOAD`/`DOWNLOAD_x86_64`: parsed via `parse_multiline_var` (awk). First URL always re-downloaded. Continuation URLs (2+) prompt user interactively — changed URLs re-downloaded, unchanged URLs keep existing md5. Written back via `perl -i` with `\` continuation format preserved. Shared logic in `update_checksums` → `_process_download_var`.
diff --git a/TODO.md b/TODO.md
index 75c1284..16c0e37 100644
--- a/TODO.md
+++ b/TODO.md
@@ -12,4 +12,5 @@
- [ ] cache the manifest per run: `reconcile_bundle_deps` currently fetches it twice (report + apply); fetch once and reuse
- [ ] verify md5 against the manifest `SHA256`: cross-check the downloaded file's sha256 against the manifest entry before writing MD5SUM (integrity check)
- [ ] config validation command (e.g. `--check-config`): sanity-check nvchecker.toml sections, bundle-manifests URLs, phantom-deps file, and that configured paths exist
- - [ ] batch `--check` summary report at the end: counts of updated / bundled-deps bumped / skipped, instead of only per-package interleaved output \ No newline at end of file
+ - [ ] batch `--check` summary report at the end: counts of updated / bundled-deps bumped / skipped, instead of only per-package interleaved output
+ - [ ] check if package ships an nvchecker stanza and use that instead in case our functions would simply print the stub when adding the .hint file. \ No newline at end of file
diff --git a/mkhint b/mkhint
index 1d7c86d..ab952e8 100755
--- a/mkhint
+++ b/mkhint
@@ -45,7 +45,7 @@ if [[ ! -d $TMP_DIR ]]; then
mkdir $TMP_DIR
fi
-readonly MKHINT_VERSION="1.2.5"
+readonly MKHINT_VERSION="1.2.6"
# Variables
VERSION=""
@@ -825,20 +825,52 @@ show_info() {
local dir="${matches[0]%/}"
local category; category=$(basename "$(dirname "$dir")")
- # Green header on a TTY (same gate as --list).
- local g_on="" g_off=""
+ # Green header on a TTY (same gate as --list). Yellow for the equal case.
+ local g_on="" g_off="" y_on="" y_off=""
if [[ -n "$MKHINT_FORCE_COLOR" || -t 1 ]]; then
if command -v tput &>/dev/null && tput setaf 2 &>/dev/null; then
g_on=$(tput setaf 2); g_off=$(tput sgr0)
+ y_on=$(tput setaf 3); y_off=$(tput sgr0)
else
g_on=$'\033[32m'; g_off=$'\033[0m'
+ y_on=$'\033[33m'; y_off=$'\033[0m'
fi
fi
local header="${g_on}${category}/${pkg}${g_off}"
+ # Version-compare row (body line 1, scrolls with README). Skip if the
+ # .info has no VERSION. Reuses _normalize_version + sort -V like --list.
+ local vrow=""
+ local sbo_ver=""
+ [[ -f "${dir}/${pkg}.info" ]] && \
+ sbo_ver=$(grep "^VERSION" "${dir}/${pkg}.info" | cut -d '"' -f2)
+ if [[ -n "$sbo_ver" ]]; then
+ local hint_ver=""
+ [[ -f "${HINT_DIR%/}/${pkg}.hint" ]] && \
+ hint_ver=$(grep "^VERSION" "${HINT_DIR%/}/${pkg}.hint" | cut -d '"' -f2)
+ if [[ -z "$hint_ver" ]]; then
+ vrow="SBo: ${sbo_ver} (no hint)"
+ else
+ local sn hn
+ sn=$(_normalize_version "$sbo_ver")
+ hn=$(_normalize_version "$hint_ver")
+ if [[ "$sn" == "$hn" ]]; then
+ vrow="${y_on}SBo: ${sbo_ver} = Hint: ${hint_ver}${y_off}"
+ else
+ local newer; newer=$(printf '%s\n%s\n' "$sn" "$hn" | sort -V | tail -1)
+ if [[ "$newer" == "$hn" ]]; then
+ vrow="SBo: ${sbo_ver} < Hint: ${g_on}${hint_ver}${g_off}"
+ else
+ vrow="SBo: ${g_on}${sbo_ver}${g_off} > Hint: ${hint_ver}"
+ fi
+ fi
+ fi
+ fi
+
local readme="${dir}/README"
if [[ ! -f "$readme" ]]; then
printf '%s\n' "$header"
+ [[ -n "$vrow" ]] && printf '%s\n' "$vrow"
echo "(no README)"
exit 0
fi
@@ -851,16 +883,18 @@ show_info() {
if [[ ! -t 1 || "$lines" -le "$rows" ]]; then
printf '%s\n' "$header"
+ [[ -n "$vrow" ]] && printf '%s\n' "$vrow"
cat "$readme"
exit 0
fi
- # Page: header as line 1 so it survives; pin it if pager is less.
+ # Page: header as line 1 so it survives; pin it if pager is less. The
+ # version row is body line 1 so it scrolls with the README.
local pager="${PAGER:-less}"
if [[ "$(basename "$pager")" == "less" ]]; then
- { printf '%s\n' "$header"; cat "$readme"; } | less -R --header=1
+ { printf '%s\n' "$header"; [[ -n "$vrow" ]] && printf '%s\n' "$vrow"; cat "$readme"; } | less -R --header=1
else
- { printf '%s\n' "$header"; cat "$readme"; } | $pager
+ { printf '%s\n' "$header"; [[ -n "$vrow" ]] && printf '%s\n' "$vrow"; cat "$readme"; } | $pager
fi
exit 0
}
diff --git a/mkhint.1.gz b/mkhint.1.gz
index 8933bb3..0b228e8 100644
--- a/mkhint.1.gz
+++ b/mkhint.1.gz
Binary files differ
diff --git a/mkhint.1.md b/mkhint.1.md
index 593bfb3..aa458a7 100644
--- a/mkhint.1.md
+++ b/mkhint.1.md
@@ -1,4 +1,4 @@
-% MKHINT(1) mkhint 1.2.5 | User Commands
+% MKHINT(1) mkhint 1.2.6 | User Commands
% Danilo M.
% July 2026
@@ -87,11 +87,15 @@ show a diff and prompt **[K]eep / [D]elete / [S]kip**.
: Delete a hint file and its `.bak`. Accepts multiple names.
**\--info**, **-i** *FILE*
-: Show a package's `category/program` path (green on a TTY), then its
-`README`. Paged with a sticky header (`less --header=1`) only when the
-`README` is taller than the terminal; printed inline when it fits or when
-piped. Missing package exits 2; missing `README` prints `(no README)` and
-exits 0. Mutually exclusive with **-V**, **-f**, **-n**.
+: Show a package's `category/program` path (green on a TTY), then a
+version-compare row, then its `README`. The row compares the SBo `.info`
+version against the hint's: `SBo: x < Hint: y` (or `>`) with the higher side
+green, `SBo: x = Hint: y` in yellow when equal, or `SBo: x (no hint)` when no
+hint carries a version. Omitted when the `.info` has no version. Paged with a
+sticky header (`less --header=1`) only when the `README` is taller than the
+terminal; printed inline when it fits or when piped. Missing package exits 2;
+missing `README` prints `(no README)` and exits 0. Mutually exclusive with
+**-V**, **-f**, **-n**.
**\--clean**, **-c**
: Remove all `.bak` files from the hint directory.
diff --git a/mkhint.bash-completion b/mkhint.bash-completion
index b24992b..031a707 100644
--- a/mkhint.bash-completion
+++ b/mkhint.bash-completion
@@ -31,11 +31,14 @@ _mkhintfile_completions() {
fi
case "$prev" in
- --new|-n)
- local -a words=()
- while IFS= read -r f; do
- words+=("$(basename "${f%.info}")")
- done < <(find "$repo_dir" -mindepth 2 -maxdepth 2 -name "*.info" 2>/dev/null)
+ --new|-n|--info|-i)
+ # Packages live at REPO_DIR/<category>/<pkg>/; complete the pkg dir
+ # names. Strip the trailing slash and category prefix with param
+ # expansion (no per-dir basename fork — the repo has thousands).
+ local -a words=() d
+ for d in "$repo_dir"/*/*/; do
+ d="${d%/}"; words+=("${d##*/}")
+ done
COMPREPLY=($(compgen -W "${words[*]}" -- "$cur"))
;;
--hintfile|-f|--delete|-d|--check|-C)
diff --git a/tests/mkhint_test.sh b/tests/mkhint_test.sh
index 8a8bd08..a7d1537 100755
--- a/tests/mkhint_test.sh
+++ b/tests/mkhint_test.sh
@@ -2153,6 +2153,63 @@ info4_rc=$?
set -e
assert_exit_code "info4 exit 1" 1 "$info4_rc"
+# ── T-INFO5: --info version row, hint higher than SBo → '<', hint side green ──
+echo ""
+echo "T-INFO5: --info version row differ, hint newer green"
+printf 'VERSION="9.0.0"\n' > "$MOCK_HINT/curl.hint"
+out=$(MKHINT_FORCE_COLOR=1 run_mkhint -i curl 2>&1)
+echo "$out" > "$MOCK_BASE/info5.out"
+assert_contains "info5 SBo ver" "$MOCK_BASE/info5.out" 'SBo: 8.5.0'
+assert_contains "info5 hint label" "$MOCK_BASE/info5.out" 'Hint:'
+assert_contains "info5 hint ver" "$MOCK_BASE/info5.out" '9.0.0'
+assert_contains "info5 lt glyph" "$MOCK_BASE/info5.out" '<'
+# hint (9.0.0) is higher → green escape precedes 9.0.0
+echo "$out" | grep -qE $'\033\[[0-9;]*m9\.0\.0' \
+ && { echo " PASS: info5 hint side greened"; (( PASS++ )); } \
+ || { echo " FAIL: info5 hint side not greened"; (( FAIL++ )) || true; ERRORS+=("T-INFO5 green"); }
+rm -f "$MOCK_HINT/curl.hint"
+
+# ── T-INFO6: --info version row equal → whole row yellow, '=' glyph ────────────
+echo ""
+echo "T-INFO6: --info version row equal, yellow"
+printf 'VERSION="8.5.0"\n' > "$MOCK_HINT/curl.hint"
+out=$(MKHINT_FORCE_COLOR=1 run_mkhint -i curl 2>&1)
+echo "$out" > "$MOCK_BASE/info6.out"
+assert_contains "info6 eq glyph" "$MOCK_BASE/info6.out" '='
+# yellow (tput setaf 3 / \033[33m) wraps the row
+echo "$out" | grep -qE $'\033\[(33|[0-9;]*3)m' \
+ && { echo " PASS: info6 row yellow"; (( PASS++ )); } \
+ || { echo " FAIL: info6 row not yellow"; (( FAIL++ )) || true; ERRORS+=("T-INFO6 yellow"); }
+rm -f "$MOCK_HINT/curl.hint"
+
+# ── T-INFO7: --info no hint file → '(no hint)' row ────────────────────────────
+echo ""
+echo "T-INFO7: --info no hint, (no hint) row"
+rm -f "$MOCK_HINT/curl.hint"
+run_mkhint -i curl > "$MOCK_BASE/info7.out" 2>&1
+assert_contains "info7 SBo ver" "$MOCK_BASE/info7.out" 'SBo: 8.5.0'
+assert_contains "info7 no hint" "$MOCK_BASE/info7.out" 'no hint'
+
+# ── T-INFO8: --info .info has no VERSION → no version row emitted ──────────────
+echo ""
+echo "T-INFO8: --info no .info VERSION, row skipped"
+# strip curl's VERSION so the .info carries none; header prints, no SBo: row
+printf 'PRGNAM="curl"\n' > "$MOCK_REPO/network/curl/curl.info"
+run_mkhint -i curl > "$MOCK_BASE/info8.out" 2>&1
+assert_not_contains "info8 no SBo row" "$MOCK_BASE/info8.out" 'SBo:'
+# restore for T-INFO9
+printf 'PRGNAM="curl"\nVERSION="8.5.0"\n' > "$MOCK_REPO/network/curl/curl.info"
+
+# ── T-INFO9: --info dashed SBo vs underscore hint, same version → equal yellow ─
+echo ""
+echo "T-INFO9: --info dashed vs underscore treated equal"
+printf 'VERSION="2026-06-02"\n' > "$MOCK_REPO/network/curl/curl.info"
+printf 'VERSION="2026_06_02"\n' > "$MOCK_HINT/curl.hint"
+out=$(MKHINT_FORCE_COLOR=1 run_mkhint -i curl 2>&1)
+echo "$out" > "$MOCK_BASE/info9.out"
+assert_contains "info9 eq glyph" "$MOCK_BASE/info9.out" '='
+rm -f "$MOCK_HINT/curl.hint"
+
# ─── SUMMARY ──────────────────────────────────────────────────────────────────
teardown