File size: 3,765 Bytes
ec0a9aa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | #!/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())
|