From 981cb1582ece95dfad9d6c53d34a601f6b25391f Mon Sep 17 00:00:00 2001 From: Vladislav Doster Date: Thu, 2 Jul 2026 06:45:42 -0500 Subject: [PATCH 1/2] fix(install): treat non-archive single file gracefully in ziextract. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change `ziextract` when no extractor case matches and no explicit type was passed (-z $ext), file is treated as plain single file with info message `'' is not an archive — keeping it as a plain file.` plus chmod a+x. The existing exec-bit collection then picks it up, sets REPLY for --move, prints normal success. Error message retained for explicit bogus types (ziextract file bogus-type). One iteration mid-verify: dropped -- from chmod — BSD/macOS chmod rejects it (chmod: --: No such file or directory). Why it broke: commit 1334994f (PR #771) made +x detection archive-exec-bit-only. Bare gh-r binaries arrive over HTTP with 644 and no extension => no extractor, no exec bit → error branch. Pre-#771, file(1) detection covered this case. Tests (tests/ices.zunit): two new — plain-file success path (asserts no error, message present, file executable) and bogus-explicit-type error retention. Suite 16/16, including #771's ziextract-permissions. Regression-validated: plain-file test fails 15/16 with fix stashed. Signed-off-by: Vladislav Doster --- tests/ices.zunit | 21 +++++++++++++++++++++ zinit-install.zsh | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/tests/ices.zunit b/tests/ices.zunit index 4d8c9ba6..258594bf 100755 --- a/tests/ices.zunit +++ b/tests/ices.zunit @@ -82,6 +82,27 @@ assert $output contains 'ERROR' assert $output contains "doesn't exist" } +@test 'ziextract plain single file (not an archive)' { + # A bare gh-r-style release binary: no "unrecognized archive" error, + # the file is kept as-is and marked executable. + local workdir=$(mktemp -d) + printf '#!/bin/sh\necho jq\n' > "$workdir/jq-macos-arm64" + _zi_extract_plain() { cd "$workdir" && ziextract jq-macos-arm64 } + run _zi_extract_plain + assert $state equals 0 + assert $output does_not_contain "didn't recognize archive type" + assert $output contains 'not an archive' + assert "$workdir/jq-macos-arm64" is_executable + rm -rf "$workdir" +} +@test 'ziextract still errors on unrecognized explicit type' { + local workdir=$(mktemp -d) + printf 'plain text\n' > "$workdir/somefile" + _zi_extract_bogus() { cd "$workdir" && ziextract somefile bogus-type } + run _zi_extract_bogus + assert $output contains "didn't recognize archive type" + rm -rf "$workdir" +} @test 'ziextract plain (no flattening)' { # extract'' → ziextract with no flags: directory structure is preserved local workdir=$(mktemp -d) diff --git a/zinit-install.zsh b/zinit-install.zsh index 5299a2f8..2796b47d 100644 --- a/zinit-install.zsh +++ b/zinit-install.zsh @@ -1754,6 +1754,17 @@ ziextract() { unfunction -- →zinit-extract →zinit-check } else { integer warning=1 + # Not an archive and no explicit type claimed — treat as a plain single + # file (e.g. a bare gh-r release binary). HTTP downloads carry no exec + # bit, so mark the file executable and let the execs collection below + # pick it up and report success. + if [[ -z $ext ]] { + warning=0 + (( !OPTS[opt_-q,--quiet] )) && \ + +zi-log "{info}[{pre}ziextract{info}]{rst}" \ + "\`{file}${file}{rst}' is not an archive — keeping it as a plain file." + command chmod a+x "$file" + } } unfunction -- .zinit-extract-wrapper From aabc3808815204c9e9399a528d894d4d8ff4d681 Mon Sep 17 00:00:00 2001 From: Vladislav Doster Date: Thu, 27 Aug 2026 22:20:25 -0500 Subject: [PATCH 2/2] test(ices): cover gh-r appimage bpick+mv recipe End-to-end test for the ziextract non-archive fallback using pkgforge-dev/ghostty-appimage: the downloaded AppImage is not an archive, so it must be kept as a plain file, marked executable, and renamed by the mv ice. Asserts on files only; the Linux-only binary is never executed since CI also runs on macOS. Closes: https://github.com/zdharma-continuum/zinit/issues/775 Signed-off-by: Vladislav Doster --- tests/ices.zunit | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/ices.zunit b/tests/ices.zunit index 258594bf..50878541 100755 --- a/tests/ices.zunit +++ b/tests/ices.zunit @@ -95,6 +95,18 @@ assert "$workdir/jq-macos-arm64" is_executable rm -rf "$workdir" } +@test 'gh-r appimage: bpick + mv on non-archive asset' { + # Real-world recipe for the ziextract non-archive fallback: the AppImage is not + # an archive, must be kept, marked executable, and renamed by the mv ice. + run zinit as"program" from"gh-r" bpick"*AppImage" mv"gh* -> ghostty" id-as"test/ghostty" for pkgforge-dev/ghostty-appimage + assert $state equals 0 + assert $output does_not_contain 'ERROR' + assert $output does_not_contain "didn't recognize archive type" + assert "$ZPLUGINS/test---ghostty/ghostty" is_file + assert "$ZPLUGINS/test---ghostty/ghostty" is_executable + local -a leftovers=( "$ZPLUGINS"/test---ghostty/*.appimage(N) ) + assert $#leftovers equals 0 +} @test 'ziextract still errors on unrecognized explicit type' { local workdir=$(mktemp -d) printf 'plain text\n' > "$workdir/somefile"