- gui_emummc_tools: re-apply container position after reload so content does not jump to top when returning from sub-windows (Change emuMMC, etc.) - Add sd_out.py: pack build output to output/hekate_X.Y.Z_Nyx_A.B.C.zip (payload.bin, bootloader/update.bin, bootloader/sys/*, no ini/patches) - Add nyx/BOOTLOADER_SYS_ORIGINS.md: where res.pak, thk.bin, emummc.kipm, l4t/ come from Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Pack hekate build output into a ZIP with SD card layout:
|
|
ZIP
|
|
├── payload.bin (hekate payload for injection / root of SD)
|
|
└── bootloader/
|
|
├── update.bin (hekate payload; for modchips / auto-update)
|
|
├── ini/ (empty; for More configs)
|
|
├── res/ (empty; for user icons/background)
|
|
├── payloads/ (empty; for Payloads menu)
|
|
└── sys/
|
|
├── nyx.bin
|
|
├── libsys_lp0.bso
|
|
└── libsys_minerva.bso
|
|
|
|
Run from repo root after `make`. No hekate_ipl.ini or patches.ini.
|
|
Optional: res.pak, thk.bin, emummc.kipm must be added separately.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent
|
|
OUTPUT = REPO_ROOT / "output"
|
|
|
|
|
|
def parse_versions():
|
|
"""Read Versions.inc and return (bl_ver, nyx_ver) e.g. ('6.5.1', '1.9.1')."""
|
|
inc = REPO_ROOT / "Versions.inc"
|
|
if not inc.exists():
|
|
return ("0.0.0", "0.0.0")
|
|
vals = {}
|
|
for line in inc.read_text().splitlines():
|
|
m = re.match(r"(\w+)\s*:?=\s*(\d+)", line.strip())
|
|
if m:
|
|
vals[m.group(1)] = m.group(2)
|
|
bl_ver = f"{vals.get('BLVERSION_MAJOR', 0)}.{vals.get('BLVERSION_MINOR', 0)}.{vals.get('BLVERSION_HOTFX', 0)}"
|
|
nyx_ver = f"{vals.get('NYXVERSION_MAJOR', 0)}.{vals.get('NYXVERSION_MINOR', 0)}.{vals.get('NYXVERSION_HOTFX', 0)}"
|
|
return (bl_ver, nyx_ver)
|
|
|
|
|
|
def main():
|
|
bl_ver, nyx_ver = parse_versions()
|
|
zip_name = f"hekate_{bl_ver}_Nyx_{nyx_ver}.zip"
|
|
zip_path = OUTPUT / zip_name
|
|
|
|
# Required build artifacts
|
|
payload_src = OUTPUT / "hekate.bin"
|
|
sys_files = [
|
|
("bootloader/sys/nyx.bin", OUTPUT / "nyx.bin"),
|
|
("bootloader/sys/libsys_lp0.bso", OUTPUT / "libsys_lp0.bso"),
|
|
("bootloader/sys/libsys_minerva.bso", OUTPUT / "libsys_minerva.bso"),
|
|
]
|
|
|
|
missing = []
|
|
if not payload_src.exists():
|
|
missing.append(str(payload_src))
|
|
for _, src in sys_files:
|
|
if not src.exists():
|
|
missing.append(str(src))
|
|
if missing:
|
|
print("Missing build outputs (run 'make' first):", file=sys.stderr)
|
|
for m in missing:
|
|
print(" ", m, file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
zip_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
# Payload at root (for injection / some setups)
|
|
zf.write(payload_src, "payload.bin")
|
|
# bootloader/update.bin (same payload; for modchips / auto-update)
|
|
zf.write(payload_src, "bootloader/update.bin")
|
|
|
|
# bootloader/sys/*
|
|
for arc, src in sys_files:
|
|
zf.write(src, arc)
|
|
|
|
# Empty dirs (ZIP has no true directories; .keep so extractors create them)
|
|
for d in ("bootloader/ini/", "bootloader/res/", "bootloader/payloads/", "bootloader/screenshots/"):
|
|
zf.writestr(d + ".keep", "")
|
|
|
|
print(f"Wrote {zip_path}")
|
|
print("Note: res.pak, thk.bin, emummc.kipm are not in this repo; add to bootloader/sys/ if needed.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|