#!/usr/bin/env python3 """GX Hub Studio packager — build the submission zip in the hub's expected shape. Runs the Studio validator first and REFUSES to package if validation fails. The zip puts the game folder's contents at the zip root (index.html at the top, which is what the hub's checkEntries wants), and enforces the hub's 25 MB zip cap (LIMITS.maxZipBytes). Usage: python3 package.py [-o out.zip] [--title T] [--description D] """ import os import subprocess import sys import zipfile MAX_ZIP = 25 * 1024 * 1024 # hub LIMITS.maxZipBytes HERE = os.path.dirname(os.path.abspath(__file__)) def main(): args = [a for a in sys.argv[1:] if not a.startswith("-")] flags = sys.argv[1:] if not args: print(__doc__) return 2 root = args[0] out = "game.zip" if "-o" in flags: out = flags[flags.index("-o") + 1] extra = [] for f in ("--title", "--description"): if f in flags: extra += [f, flags[flags.index(f) + 1]] v = subprocess.run([sys.executable, os.path.join(HERE, "validate.py"), root] + extra) if v.returncode != 0: print("\npackage: REFUSED — validation failed. Fix the FAIL lines above first.") return 1 n = 0 with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED, compresslevel=9) as z: for dirpath, _dirs, names in os.walk(root): for name in sorted(names): ap = os.path.join(dirpath, name) rel = os.path.relpath(ap, root).replace(os.sep, "/") z.write(ap, rel) n += 1 size = os.path.getsize(out) if size > MAX_ZIP: os.remove(out) print(f"package: REFUSED — zip is {size} bytes, over the hub's {MAX_ZIP} byte (25 MB) cap.") return 1 print(f"package: wrote {out} — {n} files, {size} bytes (hub cap {MAX_ZIP}).") print("Submit it: hub Upload a game (zip while ZIP_UPLOAD is on), or host the folder and use the Link form.") return 0 if __name__ == "__main__": sys.exit(main())