#!/usr/bin/env python3 """Reinstall tensors locally and on junkpile.""" from __future__ import annotations import re import subprocess import sys from pathlib import Path PROJECT_ROOT = Path(__file__).parent.parent PYPROJECT = PROJECT_ROOT / "pyproject.toml" JUNKPILE_HOST = "chi@junkpile" JUNKPILE_PATH = "~/Projects/tensors" def get_version() -> str: """Get current version from pyproject.toml.""" content = PYPROJECT.read_text() match = re.search(r'version\s*=\s*"([^"]+)"', content) if not match: raise ValueError("Could not find version in pyproject.toml") return match.group(1) def bump_version(current: str) -> str: """Bump patch version.""" parts = current.split(".") parts[-1] = str(int(parts[-1]) + 1) return ".".join(parts) def set_version(new_version: str) -> None: """Update version in pyproject.toml.""" content = PYPROJECT.read_text() # Only replace the project version (line starts with 'version') content = re.sub(r'^version\s*=\s*"[^"]+"', f'version = "{new_version}"', content, count=1, flags=re.MULTILINE) PYPROJECT.write_text(content) print(f" Updated pyproject.toml to {new_version}") def run(cmd: list[str], *, check: bool = True, capture: bool = False) -> subprocess.CompletedProcess[str]: """Run a command.""" print(f" $ {' '.join(cmd)}") return subprocess.run(cmd, check=check, capture_output=capture, text=True) def install_local() -> None: """Install locally with uv.""" print("\n[2/4] Installing locally...") run(["uv", "pip", "install", "-e", "."], check=True) def sync_to_junkpile() -> None: """Sync project to junkpile.""" print("\n[3/4] Syncing to junkpile...") excludes = [ ".git", ".venv", "__pycache__", "*.pyc", ".mypy_cache", ".pytest_cache", ".ruff_cache", ".coverage", "*.egg-info", "node_modules", ".tmp", ] cmd = ["rsync", "-avz", "--delete"] for exc in excludes: cmd.extend(["--exclude", exc]) cmd.extend([f"{PROJECT_ROOT}/", f"{JUNKPILE_HOST}:{JUNKPILE_PATH}/"]) run(cmd) def install_junkpile() -> None: """Install on junkpile.""" print("\n[4/4] Installing on junkpile...") run(["ssh", JUNKPILE_HOST, f"cd {JUNKPILE_PATH} && pip install -e '.[server]'"]) def main() -> int: """Main entry point.""" current = get_version() new_version = bump_version(current) print(f"\n[1/4] Bumping version {current} -> {new_version}...") set_version(new_version) try: install_local() sync_to_junkpile() install_junkpile() except subprocess.CalledProcessError as e: print(f"\nError: Command failed with exit code {e.returncode}") return 1 print(f"\n Done! tensors {new_version} installed locally and on junkpile") return 0 if __name__ == "__main__": sys.exit(main())