scripts: Parse update feed with python3 if jq is missing #9
@@ -33,4 +33,10 @@ jobs:
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m "pkgbuild: Bump grok-bot-bin to ${after}"
|
||||
git tag "v${after}"
|
||||
git push origin "HEAD:${GITHUB_REF_NAME}" "v${after}"
|
||||
# Proven on this forge: run 1190 pushed master + tag v0.35.0.
|
||||
# Still fail the job if push is denied rather than reporting a landed bump.
|
||||
if ! git push origin "HEAD:${GITHUB_REF_NAME}" "v${after}"; then
|
||||
echo "error: could not push commit/tag to ${GITHUB_REF_NAME} (v${after})." >&2
|
||||
echo "error: Manual path: ./scripts/update.sh, commit, PR/merge, then tag v${after} and push the tag so build.yml can attach the release asset." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -68,14 +68,16 @@ The tag triggers `.gitea/workflows/build.yml`, which builds the Arch package and
|
||||
|
||||
Actions **can** push and tag on this forge. [Run 1190](https://git.s1d3sw1ped.com/s1d3sw1ped/grok-bot-bin/actions/runs/1190) (schedule on `master`) bumped 0.30.0 → 0.35.0 and pushed `master` plus tag `v0.35.0`.
|
||||
|
||||
If the script cannot parse the feed, or `curl` / `jq` / `python3` is missing, the job fails. A no-op is only “already at this `pkgver`”.
|
||||
If the script cannot parse the feed, the `.deb` download fails, or `curl` / `python3` / `sha256sum` is missing, the job fails (it is not a silent “up to date”). `jq` is optional; without it the script parses the feed with `python3`. The workflow still `apt-get install`s `jq` for the run. A no-op is only “already at this `pkgver`”.
|
||||
|
||||
Scheduled jobs run on the default branch (`master`). Product PRs land on `develop`; promote or run the manual path below if `develop` is ahead of `master`.
|
||||
|
||||
### Manual force path
|
||||
|
||||
When you do not want to wait for cron, or you are landing a bump on `develop`:
|
||||
|
||||
```bash
|
||||
# requires curl, jq, python3
|
||||
# requires curl, python3, sha256sum; jq optional
|
||||
./scripts/update.sh
|
||||
```
|
||||
|
||||
|
||||
+106
-18
@@ -1,20 +1,69 @@
|
||||
#!/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")/.."
|
||||
|
||||
for cmd in curl jq python3 sha256sum; do
|
||||
command -v "$cmd" >/dev/null || { echo "error: missing required command: $cmd" >&2; exit 1; }
|
||||
done
|
||||
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'
|
||||
resp=$(curl -fsSL "$FEED")
|
||||
version=$(jq -r .version <<<"$resp")
|
||||
commit=$(jq -r .url <<<"$resp" | sed -E 's#.*/stable/([^/]+)/.*#\1#')
|
||||
current=$(sed -n 's/^pkgver=//p' PKGBUILD)
|
||||
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
|
||||
|
||||
if [[ -z "$version" || "$version" == "null" || ! "$commit" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "error: could not parse update feed: $resp" >&2
|
||||
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
|
||||
@@ -30,9 +79,28 @@ 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
|
||||
curl -fsSL --retry 3 "$deb_url" -o "$tmp"
|
||||
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 \
|
||||
@@ -41,9 +109,11 @@ sed -i \
|
||||
-e "s/^pkgrel=.*/pkgrel=1/" \
|
||||
PKGBUILD
|
||||
|
||||
newver=$(sed -n 's/^pkgver=//p' PKGBUILD)
|
||||
if [[ "$newver" != "$version" ]]; then
|
||||
echo "error: PKGBUILD pkgver rewrite failed (got ${newver@Q}, expected ${version@Q})" >&2
|
||||
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
|
||||
|
||||
@@ -60,20 +130,29 @@ p.write_text(text2)
|
||||
PY
|
||||
|
||||
python3 - "$version" "$commit" "$deb_sha" "$shim_sha" <<'PY'
|
||||
import pathlib, re, sys
|
||||
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"); continue
|
||||
lines.append(f"\tpkgver = {version}\n"); saw_pkgver = True; continue
|
||||
if line.startswith("\tpkgrel ="):
|
||||
lines.append("\tpkgrel = 1\n"); continue
|
||||
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"); continue
|
||||
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"); continue
|
||||
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")
|
||||
@@ -81,6 +160,15 @@ for line in p.read_text().splitlines(True):
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user