- Implemented 3-tier release feed status (MANIFEST_LIVE, PACKAGE_LIVE, PACKAGE_HASH_VERIFIED) - Added reproducible package and checksum builder in scripts/build_dist.py - Preserved user header comments across YAML saves in router_config.py - Connected model_timeout_seconds, monitoring_interval_seconds, and auto_monitoring to runtime - Guarded global gemini:antigravity credential swap with _AGY_INVOCATION_LOCK to eliminate concurrent subprocess race - Added concurrency regression test in tests/test_antigravity_concurrency.py - Added interprocess file locking (_FileLock) for router_state.json in health_tracker.py - Sandboxed APPDATA and USERPROFILE in tests/test_installer.py - Exported roadmap modules in router/__init__.py - Verified 151 passing tests (100%) and 7/7 release gate checks
79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
"""Hermes Hub — Reproducible Package & Checksums Builder.
|
|
|
|
Builds distribution archive (hermes-hub-<version>.zip), computes SHA-256 hashes,
|
|
and writes canonical dist/checksums.txt.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import os
|
|
import zipfile
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
|
|
from antigravity_provider.version import __version__
|
|
DIST_DIR = ROOT / "dist"
|
|
SRC_DIR = ROOT / "src"
|
|
|
|
|
|
def sha256_file(filepath: Path) -> str:
|
|
h = hashlib.sha256()
|
|
with open(filepath, "rb") as f:
|
|
while chunk := f.read(65536):
|
|
h.update(chunk)
|
|
return h.hexdigest()
|
|
|
|
|
|
def build_package_zip(version: str = __version__) -> Path:
|
|
DIST_DIR.mkdir(parents=True, exist_ok=True)
|
|
zip_name = f"hermes-hub-{version}.zip"
|
|
zip_path = DIST_DIR / zip_name
|
|
|
|
# Create reproducible zip archive with deterministic timestamps
|
|
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
for root, dirs, files in os.walk(SRC_DIR):
|
|
for file in sorted(files):
|
|
if file.endswith((".pyc", ".pyo")) or "__pycache__" in root:
|
|
continue
|
|
file_path = Path(root) / file
|
|
arcname = file_path.relative_to(ROOT).as_posix()
|
|
zf.write(file_path, arcname=arcname)
|
|
|
|
# Include config and docs
|
|
for extra in ("config/compatibility.json", "README.md", "pyproject.toml"):
|
|
extra_path = ROOT / extra
|
|
if extra_path.is_file():
|
|
zf.write(extra_path, arcname=extra)
|
|
|
|
return zip_path
|
|
|
|
|
|
def update_checksums():
|
|
DIST_DIR.mkdir(parents=True, exist_ok=True)
|
|
checksum_file = DIST_DIR / "checksums.txt"
|
|
|
|
lines = []
|
|
for item in sorted(DIST_DIR.iterdir()):
|
|
if item.is_file() and item.name != "checksums.txt":
|
|
digest = sha256_file(item)
|
|
lines.append(f"{digest} {item.name}")
|
|
|
|
if lines:
|
|
checksum_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
print(f"Updated {checksum_file} with {len(lines)} artifact checksum(s):")
|
|
for line in lines:
|
|
print(f" {line}")
|
|
|
|
|
|
def main():
|
|
print(f"Building Hermes Hub distribution package v{__version__}...")
|
|
zip_path = build_package_zip(__version__)
|
|
print(f"Created: {zip_path}")
|
|
update_checksums()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|