#!/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 [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()