diff options
Diffstat (limited to 'tools/init_testdata.py')
| -rw-r--r-- | tools/init_testdata.py | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/tools/init_testdata.py b/tools/init_testdata.py deleted file mode 100644 index 4079cdb..0000000 --- a/tools/init_testdata.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python3 -""" -Initialize test data folders by archive signatures. - -The script scans all files in --input and copies matching archives into: - --output/nres/<relative path> - --output/rsli/<relative path> -""" - -from __future__ import annotations - -import argparse -import shutil -import sys -from pathlib import Path - -MAGIC_NRES = b"NRes" -MAGIC_RSLI = b"NL\x00\x01" - - -def is_relative_to(path: Path, base: Path) -> bool: - try: - path.relative_to(base) - except ValueError: - return False - return True - - -def detect_archive_type(path: Path) -> str | None: - try: - with path.open("rb") as handle: - magic = handle.read(4) - except OSError as exc: - print(f"[warn] cannot read {path}: {exc}", file=sys.stderr) - return None - - if magic == MAGIC_NRES: - return "nres" - if magic == MAGIC_RSLI: - return "rsli" - return None - - -def scan_archives(input_root: Path, excluded_root: Path | None) -> list[tuple[Path, str]]: - found: list[tuple[Path, str]] = [] - for path in sorted(input_root.rglob("*")): - if not path.is_file(): - continue - if excluded_root and is_relative_to(path.resolve(), excluded_root): - continue - - archive_type = detect_archive_type(path) - if archive_type: - found.append((path, archive_type)) - return found - - -def confirm_overwrite(path: Path) -> str: - prompt = ( - f"File exists: {path}\n" - "Overwrite? [y]es / [n]o / [a]ll / [q]uit (default: n): " - ) - while True: - try: - answer = input(prompt).strip().lower() - except EOFError: - return "quit" - - if answer in {"", "n", "no"}: - return "no" - if answer in {"y", "yes"}: - return "yes" - if answer in {"a", "all"}: - return "all" - if answer in {"q", "quit"}: - return "quit" - print("Please answer with y, n, a, or q.") - - -def copy_archives( - archives: list[tuple[Path, str]], - input_root: Path, - output_root: Path, - force: bool, -) -> int: - copied = 0 - skipped = 0 - overwritten = 0 - overwrite_all = force - - type_counts = {"nres": 0, "rsli": 0} - for _, archive_type in archives: - type_counts[archive_type] += 1 - - print( - f"Found archives: total={len(archives)}, " - f"nres={type_counts['nres']}, rsli={type_counts['rsli']}" - ) - - for source, archive_type in archives: - rel_path = source.relative_to(input_root) - destination = output_root / archive_type / rel_path - destination.parent.mkdir(parents=True, exist_ok=True) - - if destination.exists(): - if destination.is_dir(): - print( - f"[error] destination is a directory, expected file: {destination}", - file=sys.stderr, - ) - return 2 - - if not overwrite_all: - if not sys.stdin.isatty(): - print( - "[error] destination file exists but stdin is not interactive. " - "Use --force to overwrite without prompts.", - file=sys.stderr, - ) - return 2 - - decision = confirm_overwrite(destination) - if decision == "quit": - print("Aborted by user.") - return 130 - if decision == "no": - skipped += 1 - continue - if decision == "all": - overwrite_all = True - - overwritten += 1 - - try: - shutil.copy2(source, destination) - except OSError as exc: - print(f"[error] failed to copy {source} -> {destination}: {exc}", file=sys.stderr) - return 2 - copied += 1 - - print( - f"Done: copied={copied}, overwritten={overwritten}, skipped={skipped}, " - f"output={output_root}" - ) - return 0 - - -def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser( - description="Initialize test data by scanning NRes/RsLi signatures." - ) - parser.add_argument( - "--input", - required=True, - help="Input directory to scan recursively.", - ) - parser.add_argument( - "--output", - required=True, - help="Output root directory (archives go to nres/ and rsli/ subdirs).", - ) - parser.add_argument( - "--force", - action="store_true", - help="Overwrite destination files without confirmation prompts.", - ) - return parser - - -def main() -> int: - args = build_parser().parse_args() - - input_root = Path(args.input) - if not input_root.exists(): - print(f"[error] input directory does not exist: {input_root}", file=sys.stderr) - return 2 - if not input_root.is_dir(): - print(f"[error] input path is not a directory: {input_root}", file=sys.stderr) - return 2 - - output_root = Path(args.output) - if output_root.exists() and not output_root.is_dir(): - print(f"[error] output path exists and is not a directory: {output_root}", file=sys.stderr) - return 2 - - input_resolved = input_root.resolve() - output_resolved = output_root.resolve() - if input_resolved == output_resolved: - print("[error] input and output directories must be different.", file=sys.stderr) - return 2 - - excluded_root: Path | None = None - if is_relative_to(output_resolved, input_resolved): - excluded_root = output_resolved - print(f"Notice: output is inside input, skipping scan under: {excluded_root}") - - archives = scan_archives(input_root, excluded_root) - - output_root.mkdir(parents=True, exist_ok=True) - return copy_archives(archives, input_root, output_root, force=args.force) - - -if __name__ == "__main__": - raise SystemExit(main()) |
