Upstream JASP ships no Linux binary, so the existing AUR package builds everything from source including several hundred R packages. This builds that once in CI and publishes the result as jasp-desktop-bin. JASP links against the system R and Qt6 rather than bundling them, so a rebuild is triggered by an Arch r/qt6-base bump as well as by a new JASP release, and the generated PKGBUILD pins depends to the versions actually built against.
105 lines
3.4 KiB
Python
Executable File
105 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("--gh-owner", required=True)
|
|
ap.add_argument("--gh-repo", default="jasp-desktop-bin")
|
|
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"https://github.com/{args.gh_owner}/{args.gh_repo}"
|
|
f"/releases/download/{tag}/{info['tarball']}"
|
|
)
|
|
|
|
r_minor = info["r_minor"]
|
|
qt_minor = info["qt6_minor"]
|
|
|
|
substitutions = {
|
|
"@MAINTAINER@": args.maintainer,
|
|
"@JASP_VERSION@": jasp_version,
|
|
"@PKGREL@": str(pkgrel),
|
|
"@R_MINOR@": r_minor,
|
|
"@R_NEXT_MINOR@": next_minor(r_minor),
|
|
"@QT_MINOR@": qt_minor,
|
|
"@QT_NEXT_MINOR@": next_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 pinned to >={r_minor} <{next_minor(r_minor)}")
|
|
print(f" Qt pinned to >={qt_minor} <{next_minor(qt_minor)}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|