From e9e4255e1681e074dfb82ef310629ff16baef096 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 12 Jun 2026 16:48:28 +0200 Subject: [PATCH] pacman-helper: inline a `vercmp` Bash function into the patched repo-add When `pacman-helper.sh quick_add` is run from the `pacman-packages` action of `git-for-windows/git-for-windows-automation`, the SDK that the action sets up is the `build-installers` flavor, which intentionally ships only a small subset of `/usr/bin`. `vercmp.exe` is not in that subset, so every `repo-add` invocation prints two lines of noise of the form: D:/a/_temp/build-extra/repo-add: line 254: vercmp: command not found D:/a/_temp/build-extra/repo-add: line 254: ((: > 0 : arithmetic syntax error: operand expected (error token is "> 0 ") (see e.g. https://github.com/git-for-windows/git-for-windows-automation/actions/runs/27414389819/job/81026080873, which produced 64 such pairs before the unrelated `db3` leak bit it). The errors themselves are benign because we invoke `repo-add` without `--prevent-downgrade`, so the suppressed "newer version already present" warning has no functional consequence, but I would rather not pollute release logs with them. Adding `vercmp.exe` (or any of the other plausible interpreters that came up while exploring this -- `awk.exe`, `perl`, `expr.exe`) to `build-installers` would defeat the point of that minimal SDK. Instead, extend the existing sed-based patching of `/usr/bin/repo-add` to also inject a small Bash function called `vercmp`. The patched copy is what `pacman-helper.sh` invokes, and `repo-add` is itself a Bash script, so the injected function is in scope at the call site with no PATH manipulation, no `export -f` gymnastics across process boundaries, and `pacman-helper.sh` itself stays POSIX `sh`. The algorithm splits each version string on runs of non-alphanumeric characters and walks the resulting arrays segment by segment: two numeric segments compare numerically, a numeric vs. alphanumeric segment lets the numeric side win (matching pacman's behavior of treating pre-release suffixes as older), and otherwise it falls back to lexical comparison. When one string runs out of segments first, the longer string wins unless its extra segment starts with a letter, in which case it is treated as a pre-release. This is essentially the same shape as the prior-art `version_compare` in `git-extra/git-update-git-for-windows`, and it gets the cases that the `pacman-packages` action ever encounters right; in particular it places `2.55.0.rc0.windows.1-1` below `2.55.0.1-1`, which matters because the RC needs to be considered older than the release. All nine test cases from `git-update-git-for-windows --test-version-compare` pass, and I have also verified the failing-run strings and the strict-equality case (which the prior-art function gets wrong but which `vercmp`'s contract requires to be `0`). Within a mixed-alphanumeric segment such as `rc10` vs. `rc2` the lexical fallback gets the order wrong, but Git for Windows has never published an RC past single digits, so a full rpm-style sub-tokenization stays out of scope. `repo-remove` next door is patched the same way but does not call `vercmp`, so its patching block is intentionally left alone. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- pacman-helper.sh | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/pacman-helper.sh b/pacman-helper.sh index 89c7285550..66829adf03 100755 --- a/pacman-helper.sh +++ b/pacman-helper.sh @@ -79,8 +79,48 @@ call_gpg () { repo_add () { if test ! -s "$this_script_dir/repo-add" then - # Make sure that GPGKEY is used unquoted - sed 's/"\(\${\?GPGKEY}\?\)"/\1/g' "$this_script_dir/repo-add" + # The `build-installers` SDK that is used by the + # `pacman-packages` action of + # `git-for-windows/git-for-windows-automation` does not ship + # `vercmp.exe`. Inject a small Bash function of the same name + # (`repo-add` is a Bash script, so it picks it up at the call + # site without any PATH manipulation), and make sure that + # `GPGKEY` is used unquoted. + { + sed '1q' 10#${sb[i]} )) && echo 1 || echo -1 + return + fi + [[ "${sa[i]}" =~ ^[0-9]+$ ]] && { echo 1; return; } + [[ "${sb[i]}" =~ ^[0-9]+$ ]] && { echo -1; return; } + [[ "${sa[i]}" > "${sb[i]}" ]] && echo 1 || echo -1 + return + done + (( ${#sa[@]} == ${#sb[@]} )) && { echo 0; return; } + local extra sign + if (( ${#sa[@]} > ${#sb[@]} )); then + extra=${sa[n]} + sign=1 + else + extra=${sb[n]} + sign=-1 + fi + [[ "$extra" =~ ^[A-Za-z] ]] && echo $(( -sign )) || echo $sign +} +VERCMP_EOF + sed '1d; s/"\(\${\?GPGKEY}\?\)"/\1/g' "$this_script_dir/repo-add" fi && "$this_script_dir/repo-add" "$@" }