Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/studio/studio_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3165,6 +3165,21 @@ void draw_bulk_migrate(StudioModel& model, const Theme& th) {
retcomm::studio::run_project_studio_async(model, std::move(args), nullptr);
};

auto run_update_cmake = [&](bool dry_run) {
const std::string csv = select_csv();
if (csv.empty()) {
model.append_log("[FAIL] No repos selected");
return;
}
std::vector<std::string> args = {"git", "bulk-update-cmake", "--select", csv,
"--jobs", std::to_string(model.bulk_jobs)};
if (model.migrate_push) args.push_back("--push");
if (dry_run) args.push_back("--dry-run");
model.append_log(dry_run ? "--- Bulk update CMake (dry run) ---"
: "--- Bulk update CMake ---");
retcomm::studio::run_project_studio_async(model, std::move(args), nullptr);
};

if (bulk_btn("Select all")) {
for (auto& kv : model.bulk_selected) kv.second = true;
for (const auto& e : model.repos) model.bulk_selected[e.path] = true;
Expand All @@ -3176,6 +3191,14 @@ void draw_bulk_migrate(StudioModel& model, const Theme& th) {
const bool go = bulk_btn("Migrate selected");
accent_button_pop();
if (go) run_migrate(false);
if (bulk_btn("Update CMake")) run_update_cmake(false);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal))
ImGui::SetTooltip("Sync ticked titles' CMakeLists.txt with psxrecomp's scaffold template\n"
"(tools/update_cmake.py) and commit CMakeLists.txt only.\n"
"Honours Push.");
if (bulk_btn("Dry run CMake")) run_update_cmake(true);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal))
ImGui::SetTooltip("Report which ticked titles' CMakeLists.txt would change; writes nothing.");
end_wrapped_line();
wrapped(th.text_muted,
"Per-title results stream into the Activity log as [OK] / [FAIL] lines with the "
Expand Down
69 changes: 69 additions & 0 deletions tools/new_project_layout/project_studio/bulkops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,75 @@ def one(label: str, root: Path) -> list[CmdResult]:
return map_repos(repos, one, jobs=jobs, on_repo=on_repo)


def bulk_update_cmake(
repos: list[tuple[str, Path]],
*,
commit: bool = True,
push_remote: bool = False,
dry_run: bool = False,
jobs: int = 1,
on_repo: OnRepoResults | None = None,
) -> list[CmdResult]:
"""PSX: sync each repo's CMakeLists.txt with psxrecomp's scaffold template.

The work is psxrecomp's own ``tools/update_cmake.py`` (one owner, no copy
here): the sibling psxrecomp checkout's if there is one -- it carries the
newest managed blocks -- else the title's pinned ``psxrecomp/`` submodule.
Only CMakeLists.txt is committed."""
import subprocess
import sys

from . import platforms
from .paths import psxrecomp_root_from_toolkit

if platforms.current().key != "psx":
return [CmdResult(False, "update-cmake: PSX titles only (psxrecomp scaffold)")]

def one(label: str, root: Path) -> list[CmdResult]:
root = Path(root).expanduser().resolve()
if not (root / "CMakeLists.txt").is_file():
return [CmdResult(False, f"{label}: no CMakeLists.txt")]
sibling = psxrecomp_root_from_toolkit()
script = next(
(c for c in ((sibling / "tools" / "update_cmake.py") if sibling else None,
root / "psxrecomp" / "tools" / "update_cmake.py")
if c is not None and c.is_file()),
None,
)
if script is None:
return [CmdResult(False, f"{label}: no psxrecomp tools/update_cmake.py (sibling checkout or pinned submodule); update psxrecomp")]

def run(*cmd: str) -> subprocess.CompletedProcess:
return subprocess.run(list(cmd), cwd=str(root), capture_output=True, text=True,
encoding="utf-8", errors="replace", check=False)

r = run(sys.executable, str(script), "--project", str(root), "--check")
if r.returncode == 0:
return [CmdResult(True, f"{label}: CMakeLists.txt up to date")]
if r.returncode != 1:
return [CmdResult(False, f"{label}: update_cmake failed", (r.stdout + r.stderr).strip())]
if dry_run:
return [CmdResult(True, f"{label}: would update CMakeLists.txt", r.stdout.strip())]
r = run(sys.executable, str(script), "--project", str(root))
if r.returncode != 0:
return [CmdResult(False, f"{label}: update_cmake failed", (r.stdout + r.stderr).strip())]
if not commit:
return [CmdResult(True, f"{label}: updated CMakeLists.txt (uncommitted)")]
r = run("git", "add", "--", "CMakeLists.txt")
if r.returncode == 0:
r = run("git", "commit", "-m", "CMake: sync managed blocks (update_cmake)", "--", "CMakeLists.txt")
if r.returncode != 0:
return [CmdResult(False, f"{label}: updated but commit failed", (r.stdout + r.stderr).strip())]
if push_remote:
pr = push(root)
if not pr.ok:
return [CmdResult(False, f"{label}: committed, push failed", pr.detail)]
return [CmdResult(True, f"{label}: updated, committed, pushed")]
return [CmdResult(True, f"{label}: updated + committed")]

return map_repos(repos, one, jobs=jobs, on_repo=on_repo)


def bulk_install_ci(
repos: list[tuple[str, Path]],
*,
Expand Down
39 changes: 39 additions & 0 deletions tools/new_project_layout/project_studio/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,34 @@ def on_repo(label: str, results: list) -> None:
return 1 if failed else 0


def cmd_git_bulk_update_cmake(args: argparse.Namespace) -> int:
from project_studio.bulkops import bulk_update_cmake
from project_studio.repo_index import load_index

repos = _bulk_repos_or_die(args)
if repos is None:
return 2
jobs = int(getattr(args, "jobs", 0) or 0) or int(getattr(load_index(), "bulk_jobs", 1) or 1)

def on_repo(label: str, results: list) -> None:
for r in results:
print(f" [{'OK' if r.ok else 'FAIL'}] {r.message}", flush=True)
for ln in (r.detail or "").splitlines():
print(f" {ln}", flush=True)

results = bulk_update_cmake(
repos,
commit=not bool(getattr(args, "no_commit", False)),
push_remote=bool(getattr(args, "push", False)),
dry_run=bool(getattr(args, "dry_run", False)),
jobs=jobs,
on_repo=on_repo,
)
failed = sum(1 for r in results if not r.ok)
print(f"bulk update-cmake: {len(results) - failed} ok, {failed} failed", flush=True)
return 1 if failed else 0


def cmd_git_release(args: argparse.Namespace) -> int:
from project_studio.gitops import run_release_workflow

Expand Down Expand Up @@ -3508,6 +3536,17 @@ def add_bulk_targets(p: argparse.ArgumentParser) -> None:
)
p_gbci.set_defaults(func=cmd_git_bulk_install_ci)

p_gbuc = git_sub.add_parser(
"bulk-update-cmake",
help="PSX: sync selected repos' CMakeLists.txt with psxrecomp's scaffold template "
"via psxrecomp/tools/update_cmake.py (commits CMakeLists.txt only)",
)
add_bulk_select(p_gbuc)
p_gbuc.add_argument("--no-commit", action="store_true", help="Edit CMakeLists.txt but do not commit")
p_gbuc.add_argument("--push", action="store_true", help="Push after committing")
p_gbuc.add_argument("--jobs", type=int, default=0, help="Parallel repos (default: index setting)")
p_gbuc.set_defaults(func=cmd_git_bulk_update_cmake)

p_gbmb = git_sub.add_parser(
"bulk-migrate-bundled",
help="PSX: move selected repos onto bundled releases (bump psxrecomp/recomp-ui, "
Expand Down
Loading