File size: 2,777 Bytes
ecc81b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Copy the built viewer into the package, where the wheel can carry it.

    cd viewer && npm install && npm run build
    python viewer/install_bundle.py

Run from the repo root or from ``viewer/``; both work. The bundle lands in
``src/torch_dimensions/viz/static`` and is deliberately **not** committed —
it is a build artifact, it changes on every rebuild, and a repo that carries
its own build output accumulates diffs nobody reads. CI builds it before
packaging; ``pyproject.toml`` lists it under ``artifacts`` so hatchling
includes it even though ``.gitignore`` hides it.

The size guard here is the sdist-bloat lesson from DEBUG.md, one directory
over: `node_modules` once reached a released tarball because nothing looked at
what was actually in it.
"""

from __future__ import annotations

import shutil
import sys
from pathlib import Path

MAX_MB = 8.0

root = Path(__file__).resolve().parent.parent
src = root / "viewer" / "dist"
dest = root / "src" / "torch_dimensions" / "viz" / "static"


def main() -> int:
    if not (src / "index.html").exists():
        print(f"no build found at {src}\nrun: cd viewer && npm install && npm run build")
        return 1

    size_mb = sum(f.stat().st_size for f in src.rglob("*") if f.is_file()) / 2**20
    files = sum(1 for f in src.rglob("*") if f.is_file())
    if size_mb > MAX_MB:
        print(f"refusing to install a {size_mb:.1f} MB bundle (limit {MAX_MB} MB)")
        print("something is being bundled that should not be — check for source maps or assets")
        return 1
    if any(p.name == "node_modules" for p in src.rglob("*")):
        print("node_modules is inside the build output; refusing")
        return 1

    if dest.exists():
        shutil.rmtree(dest)
    shutil.copytree(src, dest)

    # Vite copies everything in `viewer/public/` into the build, and the live
    # training script writes `viewer/public/run.json` there. Left alone, a
    # wheel would carry whatever run happened to be on the packager's laptop —
    # and the viewer would load it in preference to the model the user passed
    # to `td.viz.show`, which is how this was noticed at all.
    # `weights.json` is the same kind of stray: `td.viz.show(model)` serves the
    # real one from memory, and a packaged copy would show the packager's
    # weights for somebody else's model.
    for name in ("run.json", "weights.json"):
        for stray in dest.rglob(name):
            stray.unlink()
            print(f"stripped {stray.relative_to(dest)} (a local artefact, not part of the viewer)")

    installed = sum(1 for f in dest.rglob("*") if f.is_file())
    print(f"installed {installed} of {files} files, {size_mb:.2f} MB -> {dest.relative_to(root)}")
    return 0


if __name__ == "__main__":
    sys.exit(main())