Files
najdek 4488577730 feat: v0.6.0 release - unify architecture on ps5-webkit-remote-loader
- Unify userland exploit runner, ROP primitives, and payload pipeline on ps5-webkit-remote-loader
- Drop legacy umtx2 (FW <= 5.50)
- Improve Relapse stability
2026-10-07 17:14:39 +02:00

167 lines
5.4 KiB
Python

#!/usr/bin/env python3
"""Compute the build version and generate include/wkali_version.h + assets/param.json.
Version scheme (mirrors the ps5-bdjb-autoloader project):
dev: <base>-<build_type>-<suffix>
stable: <base>
pre-release: <base>-pre-<suffix>
e.g. 0.0.1-dev-abc1234 clean tree, dev build
0.0.1-dev-20260806123500 dirty tree — timestamp instead of hash
0.0.1-pre-abc1234 clean tree, pre-release build
0.0.1 stable build — no hash/timestamp suffix
The base version comes from WKAL_VERSION in include/wkali.h. BUILD_TYPE is
taken from the BUILD_TYPE environment variable (default: dev).
When CUSTOM_VERSION is set, it is appended to the base version and takes
precedence over the build type (e.g. CUSTOM_VERSION=cache-test -> 0.0.1-cache-test).
The custom suffix is also shown in the PS5 homescreen app title.
Usage:
gen_version.py # (re)generate version header and app metadata
gen_version.py --print # print the full version string
gen_version.py --page-config PATH # emit standalone UI build information
"""
import datetime
import json
import os
import re
import subprocess
import sys
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
HEADER = os.path.join(REPO, "include", "wkali_version.h")
WKALI_H = os.path.join(REPO, "include", "wkali.h")
PARAM_JSON = os.path.join(REPO, "assets", "param.json")
PARAM_TEMPLATE = os.path.join(REPO, "assets", "param.json.template")
VERSION_PLACEHOLDER = b"[[VERSION_PLACEHOLDER]]"
def read_base_version():
"""Read the base WKAL_VERSION from include/wkali.h."""
try:
with open(WKALI_H) as f:
content = f.read()
m = re.search(r'#define\s+WKAL_VERSION\s+"([^"]+)"', content)
if m:
return m.group(1)
except OSError:
pass
return "0.0.0"
def git(*args):
"""Run a git command in the repo; returns stdout stripped or ''."""
try:
return subprocess.run(
["git", *args], cwd=REPO, capture_output=True, text=True, errors="replace"
).stdout.strip()
except OSError:
return ""
def get_version_info(build_type=None):
"""Compute the version components. Returns a dict with 'full' being the
version string to display everywhere."""
if build_type is None:
build_type = os.environ.get("BUILD_TYPE", "dev")
if build_type not in ("dev", "stable", "pre-release"):
build_type = "dev"
base = read_base_version()
custom = os.environ.get("CUSTOM_VERSION", "").strip()
git_hash = git("rev-parse", "--short", "HEAD")
dirty = git("status", "--porcelain")
suffix = git_hash or "unknown"
if dirty:
suffix = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
if custom:
full = f"{base}-{custom}"
elif build_type == "stable":
full = base
else:
segment = "pre" if build_type == "pre-release" else "dev"
full = f"{base}-{segment}-{suffix}"
return {
"base": base,
"build_type": build_type,
"suffix": suffix,
"full": os.environ.get("BUILD_VERSION") or full,
"git_hash": git_hash or "unknown",
"dirty": bool(dirty),
"build_time": datetime.datetime.now(datetime.timezone.utc).strftime(
"%Y-%m-%d %H:%M:%S UTC"
),
"title": full if custom else base,
}
def header_text(info):
return (
"#pragma once\n"
"/* Auto-generated by tools/gen_version.py - do not edit. */\n"
"\n"
f'#define WKAL_BASE_VERSION "{info["base"]}"\n'
f'#define WKAL_BUILD_TYPE "{info["build_type"]}"\n'
f'#define WKAL_BUILD_SUFFIX "{info["suffix"]}"\n'
f'#define WKAL_FULL_VERSION "{info["full"]}"\n'
f'#define WKAL_BUILD_TIME "{info["build_time"]}"\n'
)
def write_if_changed(path, data):
"""Write bytes only when the content differs, to avoid pointless rebuilds."""
try:
with open(path, "rb") as f:
if f.read() == data:
return
except OSError:
pass
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "wb") as f:
f.write(data)
def main(argv=None):
argv = argv if argv is not None else sys.argv[1:]
if argv and argv[0] == "--print":
print(get_version_info()["full"])
return 0
if argv and argv[0] == "--build-time":
print(get_version_info()["build_time"])
return 0
if argv and argv[0] == "--title":
info = get_version_info()
print(f"WebKit Autoloader v{info['full']} by PLK (built {info['build_time']})")
return 0
if len(argv) == 2 and argv[0] == "--page-config":
info = get_version_info()
config = {"version": info["full"], "buildTime": info["build_time"]}
data = "window.WKAL_PAGE = " + json.dumps(config).replace("<", "\\u003c") + ";\n"
write_if_changed(os.path.abspath(argv[1]), data.encode("utf-8"))
return 0
info = get_version_info()
write_if_changed(HEADER, header_text(info).encode("utf-8"))
# PS5 homescreen app metadata — title gets the base version (or the full
# custom version) so the app label reflects what was built.
with open(PARAM_TEMPLATE, "rb") as f:
param = f.read()
write_if_changed(
PARAM_JSON, param.replace(VERSION_PLACEHOLDER, info["title"].encode("utf-8"))
)
return 0
if __name__ == "__main__":
sys.exit(main())