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())