From 18af4de0c000e028b74046dffea8d87ad0e5b360 Mon Sep 17 00:00:00 2001 From: Jeremy McClure Date: Wed, 29 Jul 2026 12:11:31 -0400 Subject: [PATCH] zsh: add github binary fallbacks for bat/zoxide/delta (fixes RHEL/Alma without EPEL/cargo) On RHEL-family distros without EPEL enabled and without cargo, the PM loop fails for bat/zoxide/git-delta and there was no fallback, so they ended up skipped/FAIL. Now, after the PM/cargo attempts fail, download the latest static release tarball from GitHub instead, matching the existing pattern for eza/fastfetch/starship/lazydocker. - Add _gh_latest_tag(): resolve latest release tag from the /releases/latest redirect (no GitHub API, no rate limits) - Add _gh_install_bin(): build the asset URL from a versioned template, download, extract, and cp the named binary into ~/.local/bin - Handle per-repo tag conventions: bat/zoxide tags are 'v0.x' while delta tags are bare '0.x'; keep the raw tag for the download path and strip the optional 'v' only for asset-filename substitution - Add target_musl/target_gnu per-arch (x86_64/aarch64/armv7l) - bat/zoxide use static musl builds (no glibc deps); delta ships gnu-only - Verbose 'gh installing ( from )' / FAIL lines - Bump ZSHRC_BOOTSTRAP_VERSION 3 -> 4 so existing boxes re-run the bootstrap and pick up the new fallbacks Verified end-to-end: bat 0.26.1, zoxide 0.10.0, delta 0.19.2 all download, extract, install, and run from a temp HOME. --- zsh/README.md | 2 +- zsh/zshrc | 2 +- zsh/zshrc-bootstrap.zsh | 69 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/zsh/README.md b/zsh/README.md index ca55dc4..db693f2 100644 --- a/zsh/README.md +++ b/zsh/README.md @@ -112,7 +112,7 @@ All downloads use `--fail` so a 502/HTML error page is never written over a work | Variable | Default | Purpose | |----------|---------|---------| | `ZSHRC_GIT` | `.../scripts/raw/branch/master/zsh/` | Base URL for all remote config files | -| `ZSHRC_BOOTSTRAP_VERSION` | `3` | Bump to force a re-bootstrap on all machines | +| `ZSHRC_BOOTSTRAP_VERSION` | `4` | Bump to force a re-bootstrap on all machines | | `FFENABLED` | (unset → enabled) | Set to `false` to disable the fastfetch system info on shell start | | `BAT_THEME` | `Monokai Extended` | Override before the bat block to use a different bat theme | | `GIT_PAGER` | `delta` (when installed) | Override to use a different git pager | diff --git a/zsh/zshrc b/zsh/zshrc index 8ec46a3..3ccb9d7 100644 --- a/zsh/zshrc +++ b/zsh/zshrc @@ -6,7 +6,7 @@ export ZSHRC_GIT="https://git.jeremymcclure.com/jeremy/scripts/raw/branch/master export ZSHRC_URL="$ZSHRC_GIT/zshrc" export ZSHRC_BOOTSTRAP_URL="$ZSHRC_GIT/zshrc-bootstrap.zsh" -export ZSHRC_BOOTSTRAP_VERSION="3" +export ZSHRC_BOOTSTRAP_VERSION="4" export ZSHRC_BOOTSTRAP="$ZSH_CONFIG/.bootstrapped" [[ -d "$HOME/Scripts" ]] && path+=("$HOME/Scripts") diff --git a/zsh/zshrc-bootstrap.zsh b/zsh/zshrc-bootstrap.zsh index b7ae900..21caf4d 100644 --- a/zsh/zshrc-bootstrap.zsh +++ b/zsh/zshrc-bootstrap.zsh @@ -36,6 +36,49 @@ EOF _bootstrap_banner unfunction _bootstrap_banner +# GitHub-release binary fallback. Used for tools not packaged in a distro's +# repos (e.g. bat/zoxide/git-delta on RHEL-family without EPEL, or no cargo). +# Resolves the latest release tag via the /releases/latest redirect (no API, +# no rate limits), builds the asset URL from a template, extracts, and copies +# the named binary into ~/.local/bin. Args: +# $1 owner/repo $2 asset template (%v = version, no leading v) +# $3 binary name $4 arch suffix to substitute into %a in the template +_gh_latest_tag() { + local repo="$1" + curl -fsIL --connect-timeout 5 --max-time 20 "https://github.com/$repo/releases/latest" 2>/dev/null \ + | grep -i '^location:' | tail -1 \ + | sed -E 's#.*tag/([^[:space:]"/]+).*#\1#' +} + +_gh_install_bin() { + local repo="$1" tmpl="$2" bin="$3" + local rawtag ver asset ext tmp found + rawtag=$(_gh_latest_tag "$repo") + if [[ -z "$rawtag" ]]; then + echo " FAIL could not resolve latest tag for $repo"; return 1 + fi + ver="${rawtag#v}" # strip optional leading v for asset-filename substitution + asset="${tmpl//\%v/$ver}" + ext="${asset##*.}" + echo " gh installing $bin ($rawtag from $repo)" + tmp=$(mktemp -d) + if curl -fsSL --connect-timeout 5 --max-time 60 -o "$tmp/pkg.$ext" \ + "https://github.com/$repo/releases/download/$rawtag/$asset" \ + && { case "$ext" in + gz) tar -xzf "$tmp/pkg.$ext" -C "$tmp" 2>/dev/null ;; + *) return 1 ;; + esac; }; then + found=$(find "$tmp" -type f -name "$bin" ! -name "*.*" | head -1) + if [[ -n "$found" ]]; then + cp "$found" "$HOME/.local/bin/$bin" + chmod +x "$HOME/.local/bin/$bin" + rm -rf "$tmp"; return 0 + fi + fi + rm -rf "$tmp" + echo " FAIL could not download/extract $bin from $repo"; return 1 +} + touch ~/.hushlogin mkdir -p "$HOME/.local/bin" mkdir -p "$ZSH_CONFIG" @@ -123,10 +166,14 @@ if ! command -v delta >/dev/null; then fi arch=$(uname -m) +target_musl=""; target_gnu="" case "$arch" in - x86_64) target_fast="linux-amd64" && target_eza="x86_64-unknown-linux-gnu" ;; - aarch64|arm64) target_fast="linux-aarch64" && target_eza="aarch64-unknown-linux-gnu" ;; - armv7l) target_fast="linux-armv7l" && target_eza="armv7-unknown-linux-gnueabihf" ;; + x86_64) target_fast="linux-amd64" && target_eza="x86_64-unknown-linux-gnu" \ + && target_musl="x86_64-unknown-linux-musl" && target_gnu="x86_64-unknown-linux-gnu" ;; + aarch64|arm64) target_fast="linux-aarch64" && target_eza="aarch64-unknown-linux-gnu" \ + && target_musl="aarch64-unknown-linux-musl" && target_gnu="aarch64-unknown-linux-gnu" ;; + armv7l) target_fast="linux-armv7l" && target_eza="armv7-unknown-linux-gnueabihf" \ + && target_musl="armv7-unknown-linux-musleabihf" && target_gnu="armv7-unknown-linux-gnueabihf" ;; esac if [[ -n $target_fast && -n $target_eza ]]; then @@ -163,6 +210,22 @@ if [[ -n $target_fast && -n $target_eza ]]; then fi fi +# GitHub-release binary fallbacks for tools often missing from distro repos +# (e.g. bat/zoxide/git-delta on RHEL/Alma without EPEL, or boxes with no cargo). +# Tried after the PM/cargo loop above already failed for these. Static musl +# builds preferred so there are no glibc dependencies; delta ships gnu-only. +if ! command -v bat >/dev/null && [[ -n "$target_musl" ]]; then + _gh_install_bin "sharkdp/bat" "bat-v%v-$target_musl.tar.gz" "bat" +fi + +if ! command -v zoxide >/dev/null && [[ -n "$target_musl" ]]; then + _gh_install_bin "ajeetdsouza/zoxide" "zoxide-%v-$target_musl.tar.gz" "zoxide" +fi + +if ! command -v delta >/dev/null && [[ -n "$target_gnu" ]]; then + _gh_install_bin "dandavison/delta" "delta-%v-$target_gnu.tar.gz" "delta" +fi + mkdir -p "$HOME/.config/zsh" if [ ! -d "$OHMYZSH" ]; then