#!/usr/bin/env python3 """Sync selected upstream MobileModels data into this repository.""" from __future__ import annotations import argparse import filecmp import shutil import subprocess import sys import tempfile from pathlib import Path from project_layout import PROJECT_ROOT, WORKSPACE_ROOT DEFAULT_REPO_URL = "https://github.com/KHwang9883/MobileModels.git" DEFAULT_BRANCH = "master" SYNC_PATHS = [ "brands", "misc", "CHANGELOG.md", "CHANGELOG_en.md", "LICENSE.txt", ] def run(cmd: list[str], cwd: Path | None = None) -> None: subprocess.run(cmd, cwd=cwd or PROJECT_ROOT, check=True) def remove_path(path: Path) -> None: if path.is_dir(): shutil.rmtree(path) elif path.exists(): path.unlink() def sync_path(src: Path, dst: Path) -> None: if src.is_dir(): dst.mkdir(parents=True, exist_ok=True) source_children = {child.name for child in src.iterdir()} for existing in dst.iterdir(): if existing.name not in source_children: remove_path(existing) for child in src.iterdir(): sync_path(child, dst / child.name) return dst.parent.mkdir(parents=True, exist_ok=True) if dst.exists() and filecmp.cmp(src, dst, shallow=False): return shutil.copy2(src, dst) def sync_selected_paths(upstream_root: Path) -> None: for relative_path in SYNC_PATHS: src = upstream_root / relative_path dst = WORKSPACE_ROOT / relative_path if not src.exists(): raise FileNotFoundError(f"Missing upstream path: {relative_path}") sync_path(src, dst) def build_index(output_path: str) -> None: run( [ sys.executable, str(PROJECT_ROOT / "tools/device_mapper.py"), "--repo-root", str(WORKSPACE_ROOT), "build", "--output", output_path, ] ) def export_mysql_seed(output_path: str) -> None: run( [ sys.executable, str(PROJECT_ROOT / "tools/export_mysql_seed.py"), "--output", output_path, "--repo-root", str(WORKSPACE_ROOT), ] ) def load_mysql_seed(seed_path: str) -> None: run( [ sys.executable, str(PROJECT_ROOT / "tools/load_mysql_seed.py"), "--seed", seed_path, ] ) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( description="Sync upstream MobileModels raw data and optionally rebuild the device index." ) parser.add_argument("--repo-url", default=DEFAULT_REPO_URL, help="Upstream git repository URL") parser.add_argument("--branch", default=DEFAULT_BRANCH, help="Upstream branch to sync from") parser.add_argument( "--build-index", action="store_true", help="Rebuild dist/device_index.json after syncing upstream data", ) parser.add_argument( "--index-output", default="dist/device_index.json", help="Output path for the rebuilt device index", ) parser.add_argument( "--export-mysql-seed", action="store_true", help="Export MySQL seed SQL after syncing upstream data", ) parser.add_argument( "--mysql-seed-output", default="dist/mobilemodels_mysql_seed.sql", help="Output path for the exported MySQL seed SQL", ) parser.add_argument( "--load-mysql", action="store_true", help="Load schema and seed data into MySQL after exporting seed SQL", ) return parser.parse_args() def main() -> int: args = parse_args() with tempfile.TemporaryDirectory(prefix="mobilemodels-upstream-") as tmpdir: upstream_root = Path(tmpdir) / "upstream" run( [ "git", "clone", "--depth", "1", "--branch", args.branch, args.repo_url, str(upstream_root), ] ) sync_selected_paths(upstream_root) if args.build_index: build_index(args.index_output) if args.export_mysql_seed or args.load_mysql: export_mysql_seed(args.mysql_seed_output) if args.load_mysql: load_mysql_seed(args.mysql_seed_output) return 0 if __name__ == "__main__": raise SystemExit(main())