mirror of
https://github.com/itsPLK/ps5-webkit-autoloader.git
synced 2026-10-19 02:09:45 -05:00
- Unify userland exploit runner, ROP primitives, and payload pipeline on ps5-webkit-remote-loader - Drop legacy umtx2 (FW <= 5.50) - Improve Relapse stability
167 lines
5.4 KiB
Python
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())
|