diff options
| author | Danilo M. <danix@danix.xyz> | 2026-07-09 17:22:55 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-07-09 17:22:55 +0200 |
| commit | e94e3fe6e1d30a856913992aafb35bc7dfa2912d (patch) | |
| tree | fc39d885612d6941e7f4d261ec088840c95367fe | |
| parent | d74e9388d7d0581758d7aebe699e65c45f7bafb0 (diff) | |
| download | mkhintfile-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.md | 18 | ||||
| -rw-r--r-- | CLAUDE.md | 2 | ||||
| -rw-r--r-- | TODO.md | 3 | ||||
| -rwxr-xr-x | mkhint | 46 | ||||
| -rw-r--r-- | mkhint.1.gz | bin | 3837 -> 3958 bytes | |||
| -rw-r--r-- | mkhint.1.md | 16 | ||||
| -rw-r--r-- | mkhint.bash-completion | 13 | ||||
| -rwxr-xr-x | tests/mkhint_test.sh | 57 |
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 @@ -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`. @@ -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 @@ -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 Binary files differindex 8933bb3..0b228e8 100644 --- a/mkhint.1.gz +++ b/mkhint.1.gz 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 |
