media-updates/release.py
2026-08-30 03:53:55 +02:00

69 lines
2.1 KiB
Python
Executable file

#!/usr/bin/env python3
"""Publish an APK: copy it in, write the manifest, commit.
Reads the version and build number out of amber-adult's pubspec so the two
cannot drift — a manifest advertising a build number the APK does not carry is
an update the device installs and is then offered again on every launch.
"""
import hashlib
import json
import pathlib
import re
import shutil
import subprocess
import sys
HERE = pathlib.Path(__file__).resolve().parent
PUBSPEC = HERE.parent / "amber-adult" / "pubspec.yaml"
BASE_URL = "https://media-updates.petruzalekr.cz"
def pubspec_version() -> tuple[str, int]:
m = re.search(r"^version:\s*([0-9.]+)\+([0-9]+)\s*$",
PUBSPEC.read_text(encoding="utf-8"), re.M)
if not m:
sys.exit(f"no version line in {PUBSPEC}")
return m.group(1), int(m.group(2))
def main() -> None:
if len(sys.argv) < 2:
sys.exit("usage: release.py <apk> [notes]")
apk = pathlib.Path(sys.argv[1]).resolve()
notes = sys.argv[2] if len(sys.argv) > 2 else ""
if not apk.is_file():
sys.exit(f"no such APK: {apk}")
version, build = pubspec_version()
public = HERE / "public"
public.mkdir(exist_ok=True)
name = f"media-{build}.apk"
dest = public / name
shutil.copy2(apk, dest)
digest = hashlib.sha256(dest.read_bytes()).hexdigest()
manifest = {
"version": version,
"buildNumber": build,
"notes": notes,
"sha256": digest,
"size": dest.stat().st_size,
"url": f"{BASE_URL}/{name}",
}
# ensure_ascii=False: the notes are Czech and get read by a person as
# often as by the app.
(public / "manifest.json").write_text(
json.dumps(manifest, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8")
subprocess.run(["git", "add", "-A"], cwd=HERE, check=True)
subprocess.run(
["git", "commit", "-m", f"Release {version}+{build}"],
cwd=HERE, check=True)
print(f"staged {name} ({dest.stat().st_size // 1024 // 1024} MB), "
f"version {version}+{build}")
print("push to deploy")
if __name__ == "__main__":
main()