fe03fed004
Jumpboxes may lack jq; requiring it made the documented manual path fail closed for the wrong reason. Keep python3 as the rewrite tool and the feed parser fallback, and fail loudly when neither parser nor curl/sha256sum is present. Reject tiny/non-deb downloads so a failed fetch cannot look like a successful bump.
176 lines
5.5 KiB
Bash
Executable File
176 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Bump PKGBUILD/.SRCINFO when Cursor publishes a newer linux-x64 Grok Bot.
|
|
# Requires curl, sha256sum, python3. jq is optional (python3 parses the feed).
|
|
# Fail loudly; do not leave a half-applied bump that looks like "up to date".
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
need_cmd() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
missing=()
|
|
need_cmd curl || missing+=(curl)
|
|
need_cmd sha256sum || missing+=(sha256sum)
|
|
need_cmd python3 || missing+=(python3)
|
|
if ((${#missing[@]})); then
|
|
echo "error: missing required tools: ${missing[*]}" >&2
|
|
exit 1
|
|
fi
|
|
if ! need_cmd jq; then
|
|
echo "note: jq not found; parsing update feed with python3" >&2
|
|
fi
|
|
|
|
FEED='https://api2.cursor.sh/updates/api/update/linux-x64/sand/0.0.0/00000000-0000-0000-0000-000000000000/stable'
|
|
echo "Fetching update feed..."
|
|
if ! resp=$(curl -fsSL --retry 3 --retry-delay 2 "$FEED"); then
|
|
echo "error: failed to fetch update feed: $FEED" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$resp" ]]; then
|
|
echo "error: empty update feed from $FEED" >&2
|
|
exit 1
|
|
fi
|
|
|
|
feed_field() {
|
|
local field="$1"
|
|
if need_cmd jq; then
|
|
jq -er --arg f "$field" '.[$f] | select(. != null and . != "")' <<<"$resp"
|
|
else
|
|
python3 -c '
|
|
import json, sys
|
|
d = json.loads(sys.stdin.read())
|
|
v = d.get(sys.argv[1])
|
|
if not isinstance(v, (str, int, float)) or v == "":
|
|
raise SystemExit(1)
|
|
print(v)
|
|
' "$field" <<<"$resp"
|
|
fi
|
|
}
|
|
|
|
if ! version=$(feed_field version); then
|
|
echo "error: could not parse .version from update feed: $resp" >&2
|
|
exit 1
|
|
fi
|
|
if ! url=$(feed_field url); then
|
|
echo "error: could not parse .url from update feed: $resp" >&2
|
|
exit 1
|
|
fi
|
|
|
|
commit=$(sed -E 's#.*/stable/([^/]+)/.*#\1#' <<<"$url")
|
|
current=$(sed -n 's/^pkgver=//p' PKGBUILD | head -1)
|
|
|
|
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*$ ]]; then
|
|
echo "error: feed version looks wrong: $version" >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! "$commit" =~ ^[0-9a-f]{40}$ ]]; then
|
|
echo "error: could not parse 40-char commit from feed url: $url" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$current" ]]; then
|
|
echo "error: could not read pkgver from PKGBUILD" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "$version" == "$current" ]]; then
|
|
echo "Up to date at $version"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Bump $current -> $version (commit $commit)"
|
|
deb_url="https://downloads.cursor.com/grokbot/stable/${commit}/linux/x64/grok-bot_${version}_amd64.deb"
|
|
tmp=$(mktemp)
|
|
trap 'rm -f "$tmp"' EXIT
|
|
echo "Downloading $deb_url"
|
|
if ! curl -fL --retry 3 --retry-delay 2 -o "$tmp" "$deb_url"; then
|
|
echo "error: failed to download deb: $deb_url" >&2
|
|
exit 1
|
|
fi
|
|
sz=$(wc -c <"$tmp")
|
|
if ((sz < 1000000)); then
|
|
echo "error: downloaded deb too small (${sz} bytes): $deb_url" >&2
|
|
exit 1
|
|
fi
|
|
magic=$(head -c 8 "$tmp" | tr -d '\0')
|
|
if [[ "$magic" != '!<arch>'* ]]; then
|
|
echo "error: download is not a .deb (missing ar magic): $deb_url" >&2
|
|
exit 1
|
|
fi
|
|
|
|
deb_sha=$(sha256sum "$tmp" | cut -d' ' -f1)
|
|
shim_sha=$(sha256sum grok-bot-launch.sh | cut -d' ' -f1)
|
|
if [[ ! "$deb_sha" =~ ^[0-9a-f]{64}$ || ! "$shim_sha" =~ ^[0-9a-f]{64}$ ]]; then
|
|
echo "error: sha256sum failed (deb=$deb_sha shim=$shim_sha)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Reset pkgrel on upstream version bumps.
|
|
sed -i \
|
|
-e "s/^pkgver=.*/pkgver=${version}/" \
|
|
-e "s/^_commit=.*/_commit=${commit}/" \
|
|
-e "s/^pkgrel=.*/pkgrel=1/" \
|
|
PKGBUILD
|
|
|
|
newver=$(sed -n 's/^pkgver=//p' PKGBUILD | head -1)
|
|
newcommit=$(sed -n 's/^_commit=//p' PKGBUILD | head -1)
|
|
newrel=$(sed -n 's/^pkgrel=//p' PKGBUILD | head -1)
|
|
if [[ "$newver" != "$version" || "$newcommit" != "$commit" || "$newrel" != "1" ]]; then
|
|
echo "error: PKGBUILD rewrite did not stick (pkgver=$newver _commit=$newcommit pkgrel=$newrel)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
python3 - "$deb_sha" "$shim_sha" <<'PY'
|
|
import pathlib, re, sys
|
|
deb_sha, shim_sha = sys.argv[1], sys.argv[2]
|
|
p = pathlib.Path("PKGBUILD")
|
|
text = p.read_text()
|
|
block = f"sha256sums=(\n '{deb_sha}'\n '{shim_sha}'\n)"
|
|
text2, n = re.subn(r"sha256sums=\([^\)]*\)", block, text, count=1, flags=re.S)
|
|
if n != 1:
|
|
raise SystemExit(f"sha256sums replace failed (n={n})")
|
|
p.write_text(text2)
|
|
PY
|
|
|
|
python3 - "$version" "$commit" "$deb_sha" "$shim_sha" <<'PY'
|
|
import pathlib, sys
|
|
version, commit, deb_sha, shim_sha = sys.argv[1:5]
|
|
p = pathlib.Path(".SRCINFO")
|
|
if not p.is_file():
|
|
raise SystemExit(".SRCINFO missing")
|
|
lines = []
|
|
saw_sha = False
|
|
saw_pkgver = saw_pkgrel = saw_source = saw_noextract = False
|
|
for line in p.read_text().splitlines(True):
|
|
if line.startswith("\tpkgver ="):
|
|
lines.append(f"\tpkgver = {version}\n"); saw_pkgver = True; continue
|
|
if line.startswith("\tpkgrel ="):
|
|
lines.append("\tpkgrel = 1\n"); saw_pkgrel = True; continue
|
|
if line.startswith("\tsource = https://downloads.cursor.com/grokbot/stable/"):
|
|
lines.append(
|
|
f"\tsource = https://downloads.cursor.com/grokbot/stable/{commit}/linux/x64/grok-bot_{version}_amd64.deb\n"
|
|
)
|
|
saw_source = True
|
|
continue
|
|
if line.startswith("\tnoextract = grok-bot_"):
|
|
lines.append(f"\tnoextract = grok-bot_{version}_amd64.deb\n")
|
|
saw_noextract = True
|
|
continue
|
|
if line.startswith("\tsha256sums ="):
|
|
if not saw_sha:
|
|
lines.append(f"\tsha256sums = {deb_sha}\n")
|
|
lines.append(f"\tsha256sums = {shim_sha}\n")
|
|
saw_sha = True
|
|
continue
|
|
lines.append(line)
|
|
missing = [n for n, ok in (
|
|
("pkgver", saw_pkgver),
|
|
("pkgrel", saw_pkgrel),
|
|
("source", saw_source),
|
|
("noextract", saw_noextract),
|
|
("sha256sums", saw_sha),
|
|
) if not ok]
|
|
if missing:
|
|
raise SystemExit(f".SRCINFO rewrite missed fields: {', '.join(missing)}")
|
|
p.write_text("".join(lines))
|
|
PY
|
|
|
|
echo "Updated PKGBUILD and .SRCINFO to ${version} deb_sha=${deb_sha} shim_sha=${shim_sha}"
|