EchoLVFM / space /scripts /sync_to_hub.py
EngEmmanuel's picture
Initial commit
0f5513d
"""One-shot push: stage the Space layout in a tempdir and upload it to
`EngEmmanuel/EchoLVFM` (private by default).
The Space repo mirrors the local layout — `space/`, `utils/`, `vae/`, `src/`
sit as siblings at the Space root, with `space/README.md` and
`space/requirements.txt` promoted to root so HF picks them up. The README's
frontmatter declares `app_file: space/app.py`, so the Space launcher finds
the entrypoint inside the `space/` package — and `space/app.py`'s existing
`sys.path` shim makes `from space import ...` and `from utils.hub import ...`
resolve identically locally and on the Space.
"""
from __future__ import annotations
import argparse
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
DEFAULT_REPO_ID = "EngEmmanuel/EchoLVFM"
# Folders copied verbatim into the Space upload, preserving their layout.
DEPS = ["space", "utils", "vae", "src"]
# Stale paths from the previous (flat) push that need wiping before the
# mirrored structure lands. `hf repos delete-files` takes literal paths
# and shallow `*` globs (no `**` recursion), so list each subdir's known
# files explicitly to be sure the wipe lands.
STALE_PATTERNS = [
"app.py", "assets.py", "inference.py", "metrics.py", "video_io.py",
"samples/*", "samples/*/*",
"assets/*",
"scripts/build_samples.py", "scripts/sync_to_hub.py",
]
def _parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--repo-id", default=DEFAULT_REPO_ID)
p.add_argument("--public", action="store_true",
help="Create the Space as public (default: private).")
return p.parse_args()
def _stage(tmp: Path) -> None:
"""Materialise the Space-shaped tree under `tmp/`."""
ignore = shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyo")
for name in DEPS:
shutil.copytree(REPO_ROOT / name, tmp / name, ignore=ignore)
# Promote the Space README + requirements to the upload root so HF picks
# them up; the originals live under `space/` for editing convenience.
shutil.move(str(tmp / "space" / "README.md"), str(tmp / "README.md"))
shutil.move(str(tmp / "space" / "requirements.txt"),
str(tmp / "requirements.txt"))
def main() -> int:
args = _parse_args()
create_cmd = [
"hf", "repos", "create", args.repo_id,
"--type", "space", "--space-sdk", "gradio", "--exist-ok",
]
if not args.public:
create_cmd.append("--private")
print("$", " ".join(create_cmd))
rc = subprocess.call(create_cmd)
if rc != 0:
return rc
# Wipe the stale flat-file root from a prior push. Best-effort —
# `delete-files` returns non-zero when patterns match nothing, which
# is fine on a fresh repo.
delete_cmd = [
"hf", "repos", "delete-files", args.repo_id, *STALE_PATTERNS,
"--type", "space",
"--commit-message", "Drop stale flat-file root before mirrored push",
]
print("$", " ".join(delete_cmd))
subprocess.call(delete_cmd)
with tempfile.TemporaryDirectory(prefix="echolvfm_space_") as td:
tmp = Path(td)
_stage(tmp)
upload_cmd = [
"hf", "upload", args.repo_id, str(tmp), ".",
"--type", "space",
"--commit-message",
"Sync EchoLVFM Space (mirrored layout: space/, utils/, vae/, src/)",
]
print("$", " ".join(upload_cmd))
return subprocess.call(upload_cmd)
if __name__ == "__main__":
sys.exit(main())