#!/bin/bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")" MANIFEST="$REPO_ROOT/Bins/versions.json" ensure_deps() { local missing=() for cmd in jq curl python3; do if ! command -v "$cmd" >/dev/null 2>&1; then missing+=("$cmd") fi done if [ "${#missing[@]}" -gt 0 ]; then printf 'Missing required commands: %s\n' "${missing[*]}" >&2 exit 1 fi } github_api() { local path="$1" local auth_args=() if [ -n "${GITHUB_TOKEN:-}" ]; then auth_args=(-H "Authorization: Bearer $GITHUB_TOKEN") fi curl -fsSL \ -H "Accept: application/vnd.github+json" \ "${auth_args[@]}" \ "https://api.github.com${path}" } list_versions() { local tool="$1" owner repo if ! jq -e --arg tool "$tool" '.[$tool]' "$MANIFEST" >/dev/null; then printf 'Unsupported tool: %s\n' "$tool" >&2 exit 1 fi owner="$(jq -r --arg tool "$tool" '.[$tool].owner' "$MANIFEST")" repo="$(jq -r --arg tool "$tool" '.[$tool].repo' "$MANIFEST")" github_api "/repos/$owner/$repo/releases?per_page=100" | jq -r '.[].tag_name' } select_version() { local tool="$1" local versions versions="$(list_versions "$tool")" if [ -z "$versions" ]; then printf 'No releases found for %s\n' "$tool" >&2 exit 1 fi if command -v fzf >/dev/null 2>&1; then printf '%s\n' "$versions" | fzf --prompt="Select ${tool} version > " --height=20 --reverse else printf '%s\n' "$versions" | sed -n '1,20p' >&2 printf 'fzf is not installed, so pass a version explicitly.\n' >&2 exit 1 fi } update_version() { local tool="$1" version="$2" local tmp_file if [ -z "$version" ]; then printf 'No version selected for %s\n' "$tool" >&2 exit 1 fi tmp_file="$(mktemp)" python3 - "$MANIFEST" "$tool" "$version" "$tmp_file" <<'PY' import json import pathlib import sys manifest_path = pathlib.Path(sys.argv[1]) tool = sys.argv[2] version = sys.argv[3] tmp_path = pathlib.Path(sys.argv[4]) data = json.loads(manifest_path.read_text()) if tool not in data: raise SystemExit(f"Unsupported tool: {tool}") data[tool]["version"] = version tmp_path.write_text(json.dumps(data, indent=2) + "\n") PY mv "$tmp_file" "$MANIFEST" printf 'Pinned %s to %s\n' "$tool" "$version" } main() { local mode="update" tool version ensure_deps if [ "${1:-}" = "--list" ]; then mode="list" shift fi tool="${1:-}" version="${2:-}" if [ -z "$tool" ]; then printf 'Usage: %s [--list] tool [version]\n' "$0" >&2 exit 1 fi case "$mode" in list) list_versions "$tool" ;; update) if [ -z "$version" ]; then version="$(select_version "$tool")" fi update_version "$tool" "$version" ;; esac } main "$@"