"""Shared helpers for the M5 Robot E2E verification commands.""" from __future__ import annotations import sys from pathlib import Path from typing import Any, NoReturn, cast from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from cleveragents.application.services.resource_registry_service import ( ResourceRegistryService, ) from cleveragents.domain.models.core.project import ( NamespacedProject, parse_namespaced_name, ) from cleveragents.infrastructure.database.models import Base from cleveragents.infrastructure.database.repositories import ( NamespacedProjectRepository, ProjectResourceLinkRepository, ) def _fail(msg: str) -> NoReturn: """Print failure message to stderr and exit with code 1.""" print(f"FAIL: {msg}", file=sys.stderr) raise SystemExit(1) class _NoClose: """Session wrapper that suppresses ``close()`` for in-memory SQLite.""" def __init__(self, session: object) -> None: object.__setattr__(self, "_s", session) def close(self) -> None: pass def __getattr__(self, name: str) -> Any: return getattr(object.__getattribute__(self, "_s"), name) def _setup_db() -> tuple[ NamespacedProjectRepository, ProjectResourceLinkRepository, ResourceRegistryService, Any, ]: """Create an in-memory SQLite DB with all tables.""" engine = create_engine("sqlite:///:memory:", echo=False) Base.metadata.create_all(engine) session = sessionmaker(bind=engine, expire_on_commit=False)() wrapper = _NoClose(session) def factory() -> Session: return cast(Session, wrapper) proj_repo = NamespacedProjectRepository(session_factory=factory) link_repo = ProjectResourceLinkRepository(session_factory=factory) svc = ResourceRegistryService(session_factory=factory) svc.bootstrap_builtin_types() return proj_repo, link_repo, svc, factory def _create_project( repo: NamespacedProjectRepository, name: str, description: str | None = None, ) -> NamespacedProject: """Create and return a NamespacedProject via the repository.""" parsed = parse_namespaced_name(name) proj = NamespacedProject( name=parsed.name, namespace=parsed.namespace, description=description, ) repo.create(proj) return repo.get(proj.namespaced_name) def _create_large_python_repo(root: Path) -> int: """Populate *root* with 10,000 small Python files and return the count.""" file_count = 0 for i in range(100): module_dir = root / f"module_{i:03d}" module_dir.mkdir(parents=True, exist_ok=True) for j in range(100): (module_dir / f"file_{j:03d}.py").write_text( f"def f_{i}_{j}():\n return {i + j}\n" ) file_count += 1 return file_count