video_gen_physics_backup / scripts /materialize_humanoid_symlinks.py
doanh25032004's picture
Backup source tree of video_gen_physics (2026-07-31T14:21:08Z)
ec0a9aa verified
Raw
History Blame Contribute Delete
3.77 kB
#!/usr/bin/env python3
"""
Replace symlinks under datasets/humanoid/singleview with real file copies.
datasets/humanoid/multiview currently has no symlinks; this script only touches
singleview by default.
Run from repo root:
python scripts/materialize_humanoid_symlinks.py [--dry-run]
"""
from __future__ import annotations
import argparse
import os
import shutil
import sys
from pathlib import Path
def collect_file_symlinks(base: Path) -> list[Path]:
out: list[Path] = []
for root, dirs, files in os.walk(base, followlinks=False):
for name in list(dirs):
p = Path(root) / name
if p.is_symlink():
dirs.remove(name)
for name in files:
p = Path(root) / name
if p.is_symlink():
out.append(p)
return out
def iter_dir_symlinks(base: Path) -> list[Path]:
out: list[Path] = []
for root, dirs, _files in os.walk(base, followlinks=False):
for name in list(dirs):
p = Path(root) / name
if p.is_symlink():
out.append(p)
dirs.remove(name)
return out
def materialize_files(paths: list[Path], dry_run: bool) -> int:
err = 0
for i, p in enumerate(sorted(paths, key=str), start=1):
if not p.is_symlink():
continue
tgt = p.resolve()
if not tgt.exists():
print(f"Missing target for {p}: {tgt}", file=sys.stderr)
err += 1
continue
if not tgt.is_file():
print(f"Expected file target for {p}, got {tgt}", file=sys.stderr)
err += 1
continue
if dry_run:
if i <= 5 or i == len(paths):
print(f"[dry-run] copy file {tgt} -> {p}")
continue
os.unlink(p)
shutil.copy2(tgt, p)
if i % 50 == 0 or i == len(paths):
print(f"files: {i}/{len(paths)}", flush=True)
return err
def materialize_dir(p: Path, dry_run: bool) -> int:
if not p.is_symlink():
return 0
tgt = p.resolve()
if not tgt.is_dir():
print(f"Expected directory target for {p}, got {tgt}", file=sys.stderr)
return 1
if dry_run:
print(f"[dry-run] copytree {tgt} -> {p}")
return 0
os.unlink(p)
shutil.copytree(
tgt,
p,
symlinks=False,
copy_function=shutil.copy2,
dirs_exist_ok=False,
)
return 0
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument(
"--root",
type=Path,
default=Path(__file__).resolve().parents[1]
/ "datasets"
/ "humanoid"
/ "singleview",
help="humanoid singleview dataset root",
)
ap.add_argument("--dry-run", action="store_true")
args = ap.parse_args()
base: Path = args.root.resolve()
if not base.is_dir():
print(f"Not a directory: {base}", file=sys.stderr)
return 1
file_links = [p for p in collect_file_symlinks(base) if p.is_symlink()]
dir_links = [p for p in iter_dir_symlinks(base) if p.is_symlink()]
if args.dry_run:
print(f"[dry-run] file symlinks: {len(file_links)}")
print(f"[dry-run] directory symlinks: {len(dir_links)}")
err = materialize_files(file_links, args.dry_run)
for d in sorted(dir_links, key=str):
err += materialize_dir(d, args.dry_run)
if err:
return 1
if not args.dry_run:
leftover = collect_file_symlinks(base) + [
p for p in iter_dir_symlinks(base) if p.is_symlink()
]
if leftover:
print(f"Warning: {len(leftover)} symlink(s) remain", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())