464a9558df
update.sh only rewrote deb+launch shim checksums, truncating pkexec-pacman-u and polkit policy after version bumps. Cover all four sources in PKGBUILD/.SRCINFO and future update.sh runs.
194 lines
6.2 KiB
Bash
Executable File
194 lines
6.2 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)
|
|
pkexec_sha=$(sha256sum pkexec-pacman-u | cut -d' ' -f1)
|
|
policy_sha=$(sha256sum com.s1d3sw1ped.grok-bot-bin.policy | cut -d' ' -f1)
|
|
for label in deb_sha:$deb_sha shim_sha:$shim_sha pkexec_sha:$pkexec_sha policy_sha:$policy_sha; do
|
|
name=${label%%:*}
|
|
val=${label#*:}
|
|
if [[ ! "$val" =~ ^[0-9a-f]{64}$ ]]; then
|
|
echo "error: sha256sum failed ($name=$val)" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# 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" "$pkexec_sha" "$policy_sha" <<'PY2'
|
|
import pathlib, re, sys
|
|
deb_sha, shim_sha, pkexec_sha, policy_sha = sys.argv[1:5]
|
|
p = pathlib.Path("PKGBUILD")
|
|
text = p.read_text()
|
|
block = (
|
|
"sha256sums=(\n"
|
|
f" '{deb_sha}'\n"
|
|
f" '{shim_sha}'\n"
|
|
f" '{pkexec_sha}'\n"
|
|
f" '{policy_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)
|
|
PY2
|
|
|
|
python3 - "$version" "$commit" "$deb_sha" "$shim_sha" "$pkexec_sha" "$policy_sha" <<'PY2'
|
|
import pathlib, sys
|
|
version, commit, deb_sha, shim_sha, pkexec_sha, policy_sha = sys.argv[1:7]
|
|
p = pathlib.Path(".SRCINFO")
|
|
if not p.is_file():
|
|
raise SystemExit(".SRCINFO missing")
|
|
shas = [deb_sha, shim_sha, pkexec_sha, policy_sha]
|
|
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:
|
|
for s in shas:
|
|
lines.append(f"\tsha256sums = {s}\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)}")
|
|
# Ensure four sha lines present
|
|
sha_lines = [l for l in lines if l.startswith("\tsha256sums =")]
|
|
if len(sha_lines) != 4:
|
|
raise SystemExit(f".SRCINFO expected 4 sha256sums lines, got {len(sha_lines)}")
|
|
p.write_text("".join(lines))
|
|
PY2
|
|
|
|
echo "Updated PKGBUILD and .SRCINFO to ${version} deb_sha=${deb_sha} shim_sha=${shim_sha} pkexec_sha=${pkexec_sha} policy_sha=${policy_sha}"
|