Files
psxrecomp/tools/new_project_layout/project_studio/plan.py
T
Alex Vanderveen 874df9b5bb release: ship bundled, compiled games from committed generated/ C
Retire the setup-host release model (CI wiped generated/ and shipped
emitters + sources + a wizard so every player regenerated and rebuilt the
title). Titles now commit generated/ and CI ships the compiled game.

- docs/ci/templates/game-release.yml replaces setup-release.yml: gate on
  committed game C (tools/ci/check_generated.sh), emit the OpenBIOS backend
  in CI (tools/ci/generate_openbios.sh), configure with
  PSXRECOMP_REQUIRE_GAME_C=ON and assert the full path was taken, package
  with tools/package_game_release.sh, verify the zip is a game not a kit.
- tools/package_game_release.sh: exe, assets, bundled OpenBIOS, configs, mod
  catalog + overlay toolchain via release_stage.py, notices; refuses sources,
  emitters, generated C, BIOS dumps. clear_generated.sh removed;
  package_setup_host.sh marked retired.
- Scaffold: gitignore templates track generated/, package_release.sh.in
  wrapper, setup_project.{sh,ps1} commit generated/ after Generate.
- Project Studio: audit flags ignored/untracked generated/, retail BIOS C
  and setup-host workflows; merge_gitignore un-ignores generated/; ops emit
  the bundled packager + workflow; generate_ci uses the new template.
- Docs: docs/ci/BUNDLED_RELEASES.md replaces HOST_ONLY_RELEASES.md.
- Tests: tools/tests/test_bundled_release_layout.py; fix pre-existing
  false positives in the packager-surface and overlay-static tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-30 17:11:14 -04:00

132 lines
4.4 KiB
Python

"""Build an ordered migration plan from an audit + options."""
from __future__ import annotations
from pathlib import Path
from .detect import audit_project
from .models import AuditReport, LayoutClass, MigrateOptions, Plan, PlanStep
# Topological order for apply. Ops not listed are appended at the end.
_OP_ORDER = [
"rename_psxrecomp_submodule",
"repair_psxrecomp_submodule",
"ensure_psxrecomp_submodule",
"ensure_recomp_ui_submodule",
"emit_codegen_setup",
"emit_version",
"emit_symbols_toml",
"emit_sync_symbols",
"merge_gitignore",
"emit_mods_preloaded",
"relocate_boxart",
"emit_boxart_stub",
"ensure_app_icon",
"rewrite_cmake_setup_host",
"emit_packager",
"sync_packager_project_dirs",
"emit_ci_workflow",
"annotate_legacy_packaging",
"probe_disc_refresh",
"record_framework_pins",
"patch_readme_metrics",
]
_OP_TITLES = {
"rename_psxrecomp_submodule": "Consolidate on psxrecomp/ (remove psxrecomp-v4)",
"repair_psxrecomp_submodule": "Repair broken psxrecomp/ git checkout",
"ensure_psxrecomp_submodule": "Add psxrecomp submodule",
"ensure_recomp_ui_submodule": "Add recomp-ui submodule",
"emit_codegen_setup": "Emit codegen_setup.c / .h",
"emit_version": "Emit VERSION",
"emit_symbols_toml": "Emit symbols.toml stub",
"emit_sync_symbols": "Install tools/sync_symbols.py",
"merge_gitignore": "Merge .gitignore rules (un-ignore generated/)",
"emit_mods_preloaded": "Stub mods/preloaded catalog",
"relocate_boxart": "Relocate boxart → launcher_assets/",
"emit_boxart_stub": "Create launcher_assets stub dir",
"ensure_app_icon": "Install assets/psxrecomp app icon",
"rewrite_cmake_setup_host": "Rewrite CMakeLists.txt (psxrecomp_add_game_runtime)",
"emit_packager": "Emit scripts/package_release.sh (bundled release)",
"sync_packager_project_dirs": "Stage src/ + mods/ the release zip is missing",
"emit_ci_workflow": "Emit bundled release.yml",
"annotate_legacy_packaging": "Annotate hand-forked packaging scripts",
"probe_disc_refresh": "Refresh disc identity via probe_disc.py",
"record_framework_pins": "Write framework_pins.txt",
"patch_readme_metrics": "Patch README badges, Retro Launcher, and R.A.I.D. footer",
}
def build_plan(
root: Path,
options: MigrateOptions | None = None,
report: AuditReport | None = None,
) -> Plan:
root = root.resolve()
options = options or MigrateOptions()
report = report or audit_project(root)
wanted = set(report.failing_ops())
# Option-gated extras
if options.probe_disc and options.disc:
wanted.add("probe_disc_refresh")
if options.record_pins:
wanted.add("record_framework_pins")
if options.merge_gitignore:
# only if audit asked for it — already in failing_ops when needed
pass
if options.relocate_boxart:
pass # already from audit
if not options.rewrite_cmake:
wanted.discard("rewrite_cmake_setup_host")
if not options.enable_ci:
wanted.discard("emit_ci_workflow")
if not options.probe_disc:
wanted.discard("probe_disc_refresh")
if not options.record_pins:
wanted.discard("record_framework_pins")
if options.only:
wanted = {o for o in wanted if o in options.only} | set(options.only)
if options.skip:
wanted -= set(options.skip)
# Force-include rewrite when legacy cmake and rewrite enabled
if options.rewrite_cmake and report.layout == LayoutClass.LEGACY_PACKAGING:
wanted.add("rewrite_cmake_setup_host")
wanted.add("emit_codegen_setup")
wanted.add("emit_packager")
if options.enable_ci:
wanted.add("emit_ci_workflow")
# Always ensure wizard/codegen (first-run disc picker) when rewriting
if "rewrite_cmake_setup_host" in wanted:
wanted.add("emit_codegen_setup")
ordered = [op for op in _OP_ORDER if op in wanted]
for op in sorted(wanted):
if op not in ordered:
ordered.append(op)
steps = [
PlanStep(
op_id=op,
title=_OP_TITLES.get(op, op),
detail=next(
(c.detail for c in report.checks if c.fix_op == op),
"",
),
selected=True,
)
for op in ordered
]
return Plan(
root=str(root),
layout=report.layout,
steps=steps,
options=options,
)