From 688c655d5a3c17fe353462035dd7192517eaeed2 Mon Sep 17 00:00:00 2001 From: alexion Date: Mon, 7 Sep 2026 14:00:11 -0400 Subject: [PATCH] fix(clew): collect compiled script archives --- src/clew/README.md | 3 ++- src/clew/clew.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/clew/README.md b/src/clew/README.md index 78227c6..86414ad 100644 --- a/src/clew/README.md +++ b/src/clew/README.md @@ -11,7 +11,8 @@ bazel run //src/clew -- \ --force ``` -The first version copies loose `.rpy` files and extracts `.rpy` files from `.rpa` archives. +The first version copies loose `.rpy` files and collects compiled script files. +It extracts `.rpy`, `.rpyc`, and `.rpymc` files from `.rpa` archives. It writes output under `source/`, `work/`, and `logs/`. Use `--force` to replace those Clew-managed directories. diff --git a/src/clew/clew.py b/src/clew/clew.py index bd68120..bc6fde3 100644 --- a/src/clew/clew.py +++ b/src/clew/clew.py @@ -11,6 +11,7 @@ from rpycdec.rpa import extract_rpa LOGGER = logging.getLogger("clew") MANAGED_DIRS = ("source", "work", "logs") +SCRIPT_SUFFIXES = (".rpy", ".rpyc", ".rpymc") def parse_args(argv: list[str]) -> argparse.Namespace: @@ -49,6 +50,17 @@ def fail(message: str) -> None: raise SystemExit(f"clew: {message}") +def resolve_output_root(output_root: Path) -> Path: + if output_root.is_absolute(): + return output_root.resolve() + + workspace = os.environ.get("BUILD_WORKSPACE_DIRECTORY") + if workspace: + return (Path(workspace) / output_root).resolve() + + return output_root.resolve() + + def prepare_output(output_root: Path, force: bool) -> tuple[Path, Path, Path]: for name in MANAGED_DIRS: path = output_root / name @@ -96,6 +108,18 @@ def copy_source_file( LOGGER.info("copied %s source: %s", label, output_relative) +def copy_compiled_file(compiled_file: Path, input_root: Path, work_dir: Path) -> None: + relative = relative_to(input_root, compiled_file) + if is_renpy_runtime_path(relative): + LOGGER.info("skipped Ren'Py runtime compiled script: %s", relative) + return + + destination = work_dir / "compiled" / relative + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(compiled_file, destination) + LOGGER.info("copied compiled script: %s", relative) + + def archive_work_path(work_dir: Path, archive_relative: Path) -> Path: return work_dir / "archives" / archive_relative.with_suffix("") @@ -114,7 +138,7 @@ def extract_archive(archive: Path, game_root: Path, source_dir: Path, work_dir: LOGGER.info("extracting archive: %s", archive_relative) with archive.open("rb") as handle: - extract_rpa(handle, output_dir=str(output_dir), suffixes=[".rpy"]) + extract_rpa(handle, output_dir=str(output_dir), suffixes=list(SCRIPT_SUFFIXES)) LOGGER.info("extracted archive: %s", archive_relative) destination_prefix = archive_destination_prefix(archive_relative) @@ -137,7 +161,7 @@ def configure_logging(logs_dir: Path) -> None: def run(args: argparse.Namespace) -> None: game_root = args.game_root.resolve() - output_root = args.output_root.resolve() + output_root = resolve_output_root(args.output_root) if not game_root.is_dir(): fail(f"game root is not a directory: {game_root}") @@ -149,6 +173,11 @@ def run(args: argparse.Namespace) -> None: for source_file in sorted(game_root.rglob("*.rpy")): copy_source_file(source_file, game_root, source_dir, "loose") + LOGGER.info("scanning loose compiled scripts") + for suffix in ("*.rpyc", "*.rpymc"): + for compiled_file in sorted(game_root.rglob(suffix)): + copy_compiled_file(compiled_file, game_root, work_dir) + LOGGER.info("scanning archives") for archive in sorted(game_root.rglob("*.rpa")): extract_archive(archive, game_root, source_dir, work_dir)