Created
April 20, 2026 18:43
-
-
Save bogorad/a3cd65c36d7030bd2c114b0520e71b8e to your computer and use it in GitHub Desktop.
git-run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -u | |
| if [ $# -lt 1 ]; then | |
| printf "Usage: %s <user/repo> [args...]\n" "$0" >&2 | |
| printf "Example: %s openai/codex --help\n" "$0" >&2 | |
| exit 1 | |
| fi | |
| REPO="$1" | |
| shift | |
| if [[ "$REPO" != */* ]]; then | |
| printf "Error: repository must be in user/repo format (e.g. asheshgoplani/agent-deck)\n" >&2 | |
| exit 1 | |
| fi | |
| APP_NAME="${REPO#*/}" | |
| BIN_DIR="/tmp/git-run/$REPO" | |
| BIN_PATH="$BIN_DIR/$APP_NAME" | |
| VERSION_FILE="$BIN_DIR/.version" | |
| TMP_DIR="" | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then | |
| ARCH_REGEX="(amd64|x86_64|x64)" | |
| elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then | |
| ARCH_REGEX="(arm64|aarch64)" | |
| else | |
| printf "Error: unsupported architecture %s\n" "$ARCH" >&2 | |
| exit 1 | |
| fi | |
| cleanup() { | |
| if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then | |
| rm -rf "$TMP_DIR" | |
| fi | |
| } | |
| trap cleanup EXIT INT TERM | |
| check_deps() { | |
| local missing=0 | |
| local cmd | |
| for cmd in gh tar unzip mktemp chmod mv rm ldd file grep cut head; do | |
| if ! command -v "$cmd" >/dev/null 2>&1; then | |
| printf "Error: missing required command: %s\n" "$cmd" >&2 | |
| missing=1 | |
| fi | |
| done | |
| if [ "$missing" -ne 0 ]; then | |
| exit 1 | |
| fi | |
| } | |
| find_binary() { | |
| local dir="$1" | |
| local app="$2" | |
| local c | |
| # 1. Exact match | |
| c=$(find "$dir" -type f -name "$app" | head -n 1) | |
| if [ -n "$c" ]; then | |
| echo "$c" | |
| return | |
| fi | |
| # 2. ELF executable containing app name | |
| c=$(find "$dir" -type f -exec file {} + 2>/dev/null | grep "ELF" | grep "executable" | cut -d: -f1 | grep -i "$app" | head -n 1) | |
| if [ -n "$c" ]; then | |
| echo "$c" | |
| return | |
| fi | |
| # 3. Any ELF executable | |
| c=$(find "$dir" -type f -exec file {} + 2>/dev/null | grep "ELF" | grep "executable" | cut -d: -f1 | head -n 1) | |
| if [ -n "$c" ]; then | |
| echo "$c" | |
| return | |
| fi | |
| # 4. Just any file matching app case-insensitively | |
| c=$(find "$dir" -type f -iname "$app*" | grep -vE "\.(txt|md|json)$" | head -n 1) | |
| if [ -n "$c" ]; then | |
| echo "$c" | |
| return | |
| fi | |
| } | |
| main() { | |
| check_deps | |
| local local_version="" | |
| if [ -x "$BIN_PATH" ] && [ -f "$VERSION_FILE" ]; then | |
| local_version=$(cat "$VERSION_FILE" 2>/dev/null) | |
| fi | |
| local latest_tag | |
| latest_tag=$(gh release view -R "$REPO" --json tagName -q '.tagName' 2>/dev/null) | |
| local status=$? | |
| if [ "$status" -ne 0 ] || [ -z "$latest_tag" ]; then | |
| printf "Error: failed to fetch latest release metadata for %s\n" "$REPO" >&2 | |
| exit 1 | |
| fi | |
| local needs_update=0 | |
| if [ ! -x "$BIN_PATH" ] || [ -z "$local_version" ] || [ "$local_version" != "$latest_tag" ]; then | |
| needs_update=1 | |
| fi | |
| if [ "$needs_update" -eq 1 ]; then | |
| printf "Updating %s to %s...\n" "$APP_NAME" "$latest_tag" >&2 | |
| TMP_DIR=$(mktemp -d "/tmp/git-run-update.XXXXXX") | |
| status=$? | |
| if [ "$status" -ne 0 ] || [ -z "$TMP_DIR" ]; then | |
| printf "Error: failed to create temporary directory\n" >&2 | |
| exit 1 | |
| fi | |
| local assets | |
| assets=$(gh release view -R "$REPO" --json assets -q '.assets[].name' 2>/dev/null) | |
| local filtered | |
| filtered=$(echo "$assets" | grep -i "linux" | grep -iE "$ARCH_REGEX" | grep -vE "\.(sigstore|zst|sbom|pem|sha256|txt|md|rpm|deb|apk|msi)$") | |
| if [ -z "$filtered" ]; then | |
| filtered=$(echo "$assets" | grep -iE "$ARCH_REGEX" | grep -vE "(windows|darwin|mac|apple)" | grep -vE "\.(sigstore|zst|sbom|pem|sha256|txt|md|rpm|deb|apk|msi)$") | |
| fi | |
| if [ -z "$filtered" ]; then | |
| printf "Error: could not find suitable Linux asset for %s in release %s\n" "$REPO" "$latest_tag" >&2 | |
| exit 1 | |
| fi | |
| # Try to isolate the main app binary from sidecars (e.g. codex vs codex-responses-api-proxy) | |
| local strict_filtered | |
| strict_filtered=$(echo "$filtered" | grep -iE "^${APP_NAME}([-_]v?[0-9.]+)?[-_](linux|ubuntu|alpine|mac|darwin|windows|x86_64|amd64|x64|aarch64|arm64)") | |
| if [ -n "$strict_filtered" ]; then | |
| filtered="$strict_filtered" | |
| fi | |
| local best_asset="" | |
| best_asset=$(echo "$filtered" | grep -i "musl" | head -n 1) | |
| if [ -z "$best_asset" ]; then | |
| best_asset=$(echo "$filtered" | head -n 1) | |
| fi | |
| gh release download "$latest_tag" -R "$REPO" -p "$best_asset" -D "$TMP_DIR" --clobber >/dev/null 2>&1 | |
| status=$? | |
| if [ "$status" -ne 0 ]; then | |
| printf "Error: failed to download asset %s\n" "$best_asset" >&2 | |
| exit 1 | |
| fi | |
| local archive="$TMP_DIR/$best_asset" | |
| if [ ! -f "$archive" ]; then | |
| printf "Error: downloaded asset not found\n" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$archive" == *.tar.gz ]] || [[ "$archive" == *.tgz ]]; then | |
| tar -xzf "$archive" -C "$TMP_DIR" | |
| elif [[ "$archive" == *.zip ]]; then | |
| unzip -q "$archive" -d "$TMP_DIR" | |
| fi | |
| local new_bin | |
| new_bin=$(find_binary "$TMP_DIR" "$APP_NAME") | |
| if [ -z "$new_bin" ] || [ ! -f "$new_bin" ]; then | |
| printf "Error: binary not found in downloaded asset\n" >&2 | |
| exit 1 | |
| fi | |
| chmod +x "$new_bin" | |
| if file "$new_bin" | grep -q "ELF" && ! ldd "$new_bin" 2>&1 | grep -q "not a dynamic executable"; then | |
| local dynamic_linker="" | |
| if command -v nr >/dev/null 2>&1; then | |
| dynamic_linker=$(nr patchelf --print-interpreter "$(which ls)" 2>/dev/null || true) | |
| if [ -n "$dynamic_linker" ]; then | |
| nr patchelf --set-interpreter "$dynamic_linker" "$new_bin" 2>/dev/null || true | |
| fi | |
| elif command -v patchelf >/dev/null 2>&1; then | |
| dynamic_linker=$(patchelf --print-interpreter "$(which ls)" 2>/dev/null || true) | |
| if [ -n "$dynamic_linker" ]; then | |
| patchelf --set-interpreter "$dynamic_linker" "$new_bin" 2>/dev/null || true | |
| fi | |
| elif command -v nix >/dev/null 2>&1; then | |
| dynamic_linker=$(nix run nixpkgs#patchelf -- --print-interpreter "$(which ls)" 2>/dev/null || true) | |
| if [ -n "$dynamic_linker" ]; then | |
| nix run nixpkgs#patchelf -- --set-interpreter "$dynamic_linker" "$new_bin" 2>/dev/null || true | |
| fi | |
| fi | |
| fi | |
| mkdir -p "$BIN_DIR" | |
| mv "$new_bin" "$BIN_PATH" | |
| echo "$latest_tag" >"$VERSION_FILE" | |
| fi | |
| if [ ! -x "$BIN_PATH" ]; then | |
| printf "Error: binary is not executable at %s\n" "$BIN_PATH" >&2 | |
| exit 1 | |
| fi | |
| exec "$BIN_PATH" "$@" | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment