| #!/usr/bin/env -S uv run --script |
| # |
| # /// script |
| # requires-python = ">=3.11" |
| # dependencies = ["mypy-primer"] |
| # |
| # [tool.uv.sources] |
| # mypy-primer = { git = "https://github.com/hauntsaninja/mypy_primer" } |
| # /// |
| |
| """Clone a mypy-primer project and set up a virtualenv with its dependencies installed. |
| |
| Usage: uv run scripts/setup_primer_project.py <project-name> [directory] |
| """ |
| |
| from __future__ import annotations |
| |
| import argparse |
| import shlex |
| import subprocess |
| import sys |
| from pathlib import Path |
| from typing import NoReturn |
| |
| from mypy_primer.model import Project |
| from mypy_primer.projects import get_projects |
| |
| |
| def find_project(name: str) -> Project: |
| projects = get_projects() |
| for p in projects: |
| if p.name == name: |
| return p |
| _project_not_found(name, projects) |
| |
| |
| def _project_not_found(name: str, projects: list[Project]) -> NoReturn: |
| print(f"error: project {name!r} not found", file=sys.stderr) |
| print("available projects:", file=sys.stderr) |
| for p in sorted(projects, key=lambda p: p.name): |
| print(f" {p.name}", file=sys.stderr) |
| sys.exit(1) |
| |
| |
| def main() -> None: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("project", help="Name of a mypy-primer project") |
| parser.add_argument( |
| "directory", |
| nargs="?", |
| help="Directory to clone into (default: project name)", |
| ) |
| args = parser.parse_args() |
| |
| project = find_project(args.project) |
| |
| target_dir = Path(args.directory or project.name).resolve() |
| |
| # Clone (shallow if no pinned revision, same as primer) |
| clone_cmd = [ |
| "git", |
| "clone", |
| "--recurse-submodules", |
| project.location, |
| str(target_dir), |
| ] |
| if not project.revision: |
| clone_cmd += ["--depth", "1"] |
| print(f"Cloning {project.location} into {target_dir}...") |
| subprocess.run(clone_cmd, check=True) |
| |
| if project.revision: |
| print(f"Checking out revision {project.revision}...") |
| subprocess.run( |
| ["git", "checkout", project.revision], cwd=target_dir, check=True |
| ) |
| |
| # Create venv (matching primer's Venv.make_venv()) |
| venv_dir = target_dir / ".venv" |
| print(f"Creating virtualenv at {venv_dir}...") |
| subprocess.run( |
| ["uv", "venv", str(venv_dir), "--python", sys.executable, "--seed", "--clear"], |
| check=True, |
| ) |
| |
| venv_python = venv_dir / "bin" / "python" |
| install_base = f"uv pip install --python {shlex.quote(str(venv_python))}" |
| |
| # Run custom install command if the project defines one (matching primer's setup()) |
| if project.install_cmd: |
| install_cmd = project.install_cmd.format(install=install_base) |
| print(f"Running install command: {install_cmd}") |
| subprocess.run(shlex.split(install_cmd), cwd=target_dir, check=True) |
| |
| # Install listed dependencies (matching primer's setup()) |
| if project.deps: |
| deps_cmd_parts = shlex.split(install_base) + project.deps |
| print(f"Installing dependencies: {', '.join(project.deps)}") |
| subprocess.run(deps_cmd_parts, cwd=target_dir, check=True) |
| |
| print(f"\nDone! Project set up at {target_dir}") |
| print(f"Activate the venv with: source {venv_dir}/bin/activate") |
| |
| |
| if __name__ == "__main__": |
| main() |