Serve from /srv/tarballz on CT148 via a 'location /tarballz/' alias, NOT from under /var/www/asger: the asger-web deploy swaps that whole directory atomically, so tarballs kept inside it would be deleted on the next site deploy. CT148's rootfs was 3G with 2.7G free - one tarball would have filled it - so it is grown to 15G; speedy's thin pool has room even though vgs reports the VG nearly full. Publishing uploads to a .part name and renames on arrival so a download can never see a truncated file, verifies sha256 on the host, then fetches the public URL and checks it against the sha256 baked into the PKGBUILD. Both checks run before the AUR push, so the package cannot go out pointing at a missing file. Old tarballs are pruned to the newest three. GH_TOKEN is kept but demoted to an optional GITHUB_PAT for R module downloads; it no longer has anything to do with publishing.
101 lines
3.4 KiB
Python
Executable File
101 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Turn build-info.json into a ready-to-publish PKGBUILD.
|
|
|
|
pkgrel is derived from what is currently on the AUR: same pkgver means this is a
|
|
rebuild (against a new R/Qt6), so pkgrel increments; a new pkgver resets it to 1.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
import sys
|
|
import urllib.request
|
|
|
|
AUR_RPC = "https://aur.archlinux.org/rpc/v5/info?arg[]={}"
|
|
|
|
|
|
def next_minor(version: str) -> str:
|
|
"""4.6 -> 4.7, 6.11 -> 6.12 — the upper bound of the compatible range."""
|
|
major, minor = version.split(".")[:2]
|
|
return f"{major}.{int(minor) + 1}"
|
|
|
|
|
|
def current_aur_version(pkgname: str) -> tuple[str, int] | None:
|
|
"""(pkgver, pkgrel) currently published on the AUR, or None if absent."""
|
|
try:
|
|
with urllib.request.urlopen(AUR_RPC.format(pkgname), timeout=30) as r:
|
|
results = json.load(r).get("results", [])
|
|
except Exception as exc: # network trouble must not silently reset pkgrel
|
|
print(f"warning: could not query AUR: {exc}", file=sys.stderr)
|
|
return None
|
|
if not results:
|
|
return None
|
|
full = results[0]["Version"] # e.g. "0.98.1-2"
|
|
ver, _, rel = full.rpartition("-")
|
|
return ver, int(rel) if rel.isdigit() else 1
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--build-info", required=True)
|
|
ap.add_argument("--template", required=True)
|
|
ap.add_argument("--out", required=True)
|
|
ap.add_argument("--base-url", required=True,
|
|
help="public directory the tarball is served from")
|
|
ap.add_argument("--maintainer", required=True)
|
|
ap.add_argument("--pkgname", default="jasp-desktop-bin")
|
|
args = ap.parse_args()
|
|
|
|
info = json.loads(open(args.build_info).read())
|
|
jasp_version = info["jasp_version"]
|
|
|
|
published = current_aur_version(args.pkgname)
|
|
if published and published[0] == jasp_version:
|
|
pkgrel = published[1] + 1
|
|
print(f"rebuild of {jasp_version}: pkgrel {published[1]} -> {pkgrel}")
|
|
else:
|
|
pkgrel = 1
|
|
print(f"new version {jasp_version}: pkgrel 1")
|
|
|
|
tag = f"v{jasp_version}-{pkgrel}"
|
|
download_url = f"{args.base_url.rstrip('/')}/{info['tarball']}"
|
|
|
|
qt_minor = info["qt6_minor"]
|
|
|
|
substitutions = {
|
|
"@MAINTAINER@": args.maintainer,
|
|
"@JASP_VERSION@": jasp_version,
|
|
"@JASP_TAG@": info["jasp_tag"],
|
|
"@JASP_COMMIT@": info["jasp_commit"],
|
|
"@PKGREL@": str(pkgrel),
|
|
"@BUNDLED_R@": info["bundled_r_version"],
|
|
"@QT_MINOR@": qt_minor,
|
|
"@DOWNLOAD_URL@": download_url,
|
|
"@SHA256@": info["sha256"],
|
|
}
|
|
|
|
text = open(args.template).read()
|
|
for key, value in substitutions.items():
|
|
text = text.replace(key, value)
|
|
|
|
leftover = re.findall(r"@[A-Z0-9_]+@", text)
|
|
if leftover:
|
|
print(f"error: unsubstituted placeholders: {sorted(set(leftover))}", file=sys.stderr)
|
|
return 1
|
|
|
|
with open(args.out, "w") as fh:
|
|
fh.write(text)
|
|
|
|
# Consumed by the release + AUR-push steps of the workflow.
|
|
with open("release-meta.json", "w") as fh:
|
|
json.dump({"tag": tag, "pkgrel": pkgrel, "download_url": download_url, **info}, fh, indent=2)
|
|
|
|
print(f"wrote {args.out} ({args.pkgname} {jasp_version}-{pkgrel})")
|
|
print(f" R bundled at {info['bundled_r_version']}; built against Qt {qt_minor}")
|
|
print(" depends are unpinned - everything volatile is bundled")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|