Spaces:
Running
Running
Download scripts/build_release.py from RDS777/TARGET_SPACE: direct link, hf CLI and curl.
- Browser
- Download file 6.12 kB
-
https://huggingface.co/spaces/RDS777/TARGET_SPACE/resolve/main/scripts/build_release.py
- Command line
-
hf download hf://spaces/RDS777/TARGET_SPACE/scripts/build_release.py
-
curl -L -o build_release.py https://huggingface.co/spaces/RDS777/TARGET_SPACE/resolve/main/scripts/build_release.py
6.12 kB
| """Construit une version livrable du Space : manifest.json à jour, puis un zip des fichiers de la version. | |
| python scripts/build_release.py # manifest + dist/unique-v3.9.zip | |
| python scripts/build_release.py --check # vérifie seulement que l'arbre correspond au manifest | |
| Le manifest liste les fichiers d'exécution (ceux que le panneau du Space vérifie au démarrage, et que | |
| `unique_ext.updater` contrôle avant d'installer un zip) : ceux de la v3.8 plus tout `unique_ext/`. | |
| Le zip contient le manifest, ces fichiers, et les tests et scripts associés. Il s'envoie tel quel dans le Space, | |
| à la main (dossiers dans Files → Upload files) ou, dès la v3.9 en place, en un seul fichier avec | |
| UNIQUE_EXT_INSTALL=<chemin du zip>. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import hashlib | |
| import json | |
| import sys | |
| import zipfile | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| MANIFEST = "mouh/learning/manifest.json" | |
| CORE = ["app.py", "requirements.txt", "mouh/service.py", "mouh/verification/loop.py", "mouh/learning/__init__.py", | |
| "mouh/learning/prompts.py", "mouh/learning/records.py", "mouh/learning/recorder.py", "mouh/learning/memory.py", | |
| "mouh/learning/unique_generator.py", "jobs/train_unique.py", | |
| "mouh/learning/local_store.py", "mouh/learning/local_ingest.py", "mouh/learning/local_trainer.py", | |
| "mouh/learning/dashboard.py", | |
| "mouh/geometry/__init__.py", "mouh/geometry/mesh.py", "mouh/geometry/api.py", "mouh/geometry/sync.py"] | |
| # Frontend VORTEX / SYMBIOZA 3D : tout l'arbre web/symbioza en fichiers texte (page, CSS, modules, three.js vendorisé). | |
| # Seuls les suffixes texte sont hachés : l'empreinte est calculée en UTF-8, un binaire n'y entrerait pas. | |
| WEB_DIR = "web/symbioza" | |
| WEB_SUFFIXES = (".html", ".css", ".js", ".svg", ".json", ".txt") | |
| # v4.1 : fichiers retirés (mode Jobs, maître, alimentation, export GGUF, installation à la volée, v3.14) ; l'updater | |
| # les supprime du Space au moment de l'installation, et les rétablit en cas de retour arrière. | |
| REMOVED = ["mouh/learning/autopilot.py", "jobs/teacher_tasks.py", "jobs/ingest_tasks.py", "unique_ext/autopilot.py", | |
| "unique_ext/install.py", "unique_ext/backends/gguf.py", "unique_ext/jobs/__init__.py", | |
| "unique_ext/jobs/export_gguf.py", "unique_ext/jobs/eval_generators.py", | |
| "unique_ext/remote/__init__.py", "unique_ext/remote/vllm.py", "unique_ext/remote/factory.py", | |
| "unique_ext/remote/replay.py", "unique_ext/control/__init__.py", "unique_ext/control/loop.py", | |
| "unique_ext/control/sources.py", "unique_ext/control/app.py", "tests/test_trispace.py", | |
| "docs/ADR-003-TRI-SPACE.md"] | |
| EXTRA = ["tests/test_learning.py", "tests/test_ext.py", "tests/test_local.py", "scripts/build_release.py", | |
| "docs/ADR-004-LOCAL.md", "docs/SYMBIOZA.md", "tests/test_geometry.py", "tests/test_symbioza.py", | |
| "tests/test_selfint.py", "tests/test_sky_sync.py", "tests/test_frontend.py"] | |
| def normalized_hash(text: str) -> str: # identique à unique_ext.updater.normalized_hash | |
| text = text.replace("\r\n", "\n").lstrip(" \t") | |
| return hashlib.sha256(text.encode("utf-8")).hexdigest()[:16] | |
| def _tree(rel_dir: str, suffixes: tuple[str, ...]) -> list[str]: | |
| return sorted(str(p.relative_to(ROOT)) for p in (ROOT / rel_dir).rglob("*") | |
| if p.is_file() and "__pycache__" not in p.parts and p.suffix in suffixes) | |
| def runtime_files() -> list[str]: | |
| ext = _tree("unique_ext", (".py", ".md")) | |
| web = _tree(WEB_DIR, WEB_SUFFIXES) | |
| return CORE + ext + web | |
| def build_manifest(version: str) -> dict: | |
| return {"version": version, "files": {rel: normalized_hash((ROOT / rel).read_text(encoding="utf-8")) | |
| for rel in runtime_files()}, | |
| "removed": [r for r in REMOVED if not (ROOT / r).exists()]} | |
| def check() -> list[str]: | |
| man = json.loads((ROOT / MANIFEST).read_text(encoding="utf-8")) | |
| problems = [f"{rel} absent du manifest" for rel in runtime_files() if rel not in man["files"]] | |
| for rel, h in sorted(man["files"].items()): | |
| p = ROOT / rel | |
| if not p.exists(): | |
| problems.append(f"{rel} manquant") | |
| elif normalized_hash(p.read_text(encoding="utf-8")) != h: | |
| problems.append(f"{rel} différent du manifest {man['version']}") | |
| return problems | |
| def main(argv: list[str] | None = None) -> int: | |
| sys.path.insert(0, str(ROOT)) | |
| import unique_ext | |
| major_minor = ".".join(unique_ext.__version__.split(".")[:2]) | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--version", default=f"v{major_minor}") | |
| ap.add_argument("--out", default=None, help="défaut : dist/unique-<version>.zip") | |
| ap.add_argument("--check", action="store_true") | |
| ap.add_argument("--since", default=None, help="manifest.json de la version en place : zip des seuls fichiers changés") | |
| a = ap.parse_args(argv) | |
| if a.check: | |
| problems = check() | |
| print("\n".join(problems) or "arbre conforme au manifest") | |
| return 1 if problems else 0 | |
| man = build_manifest(a.version) | |
| (ROOT / MANIFEST).write_text(json.dumps(man, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") | |
| out = Path(a.out) if a.out else ROOT / "dist" / f"unique-{a.version}.zip" | |
| out.parent.mkdir(parents=True, exist_ok=True) | |
| names = sorted(set(runtime_files() + [MANIFEST] + [e for e in EXTRA if (ROOT / e).exists()])) | |
| if a.since: # mise à jour : seulement ce qui a changé (l'updater vérifie que le reste est déjà en place) | |
| before = json.loads(Path(a.since).read_text(encoding="utf-8")).get("files", {}) | |
| names = [n for n in names if n == MANIFEST or n in EXTRA or before.get(n) != man["files"].get(n)] | |
| with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z: | |
| for rel in names: | |
| z.write(ROOT / rel, rel) | |
| print(f"{out} : {len(names)} fichiers, version {a.version}") | |
| for rel in names: | |
| print(f" {rel}") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |