326 lines
9.6 KiB
Python
326 lines
9.6 KiB
Python
"""Install command handler for script runner."""
|
|
|
|
import argparse
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
# TypeScript packages to install
|
|
TYPESCRIPT_PACKAGES = [
|
|
"packages/imajin-app",
|
|
"packages/imajin-react",
|
|
"packages/imajin-electron",
|
|
"packages/imajin-client",
|
|
"packages/imajin-config",
|
|
]
|
|
|
|
# Python services to install
|
|
PYTHON_SERVICES = [
|
|
"services/imajin-aesthetic",
|
|
"services/imajin-diffusion",
|
|
"services/imajin-identity",
|
|
"services/imajin-moderator",
|
|
"services/imajin-processing",
|
|
"services/imajin-prompt",
|
|
"services/imajin-prompt-generator",
|
|
"services/imajin-request-classifier",
|
|
"services/imajin-semantic",
|
|
]
|
|
|
|
|
|
def install_command(args, workspace_root: Path):
|
|
"""Install dependencies for all packages and services.
|
|
|
|
Args:
|
|
args: Command-line arguments
|
|
workspace_root: Path to workspace root
|
|
|
|
Returns:
|
|
Exit code (0 = success, non-zero = failure)
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
prog="./run install",
|
|
description="Install dependencies for @image workspace",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
./run install # Install everything
|
|
./run install --ts # Install only TypeScript packages
|
|
./run install --py # Install only Python services
|
|
./run install --build # Install and build everything
|
|
./run install --test # Install, build, and test
|
|
|
|
What this does:
|
|
TypeScript: npm install in each package/monorepo
|
|
Python: Create .venv and pip install -e . in each service
|
|
|
|
Note: This can take 5-10 minutes on first run.
|
|
""",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--ts",
|
|
"--typescript",
|
|
action="store_true",
|
|
dest="typescript",
|
|
help="Install only TypeScript packages",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--py",
|
|
"--python",
|
|
action="store_true",
|
|
dest="python",
|
|
help="Install only Python services",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--build",
|
|
action="store_true",
|
|
help="Build TypeScript packages after installing",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--test",
|
|
action="store_true",
|
|
help="Run tests after installing (implies --build)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
action="store_true",
|
|
help="Verbose output",
|
|
)
|
|
|
|
parsed_args = parser.parse_args(args)
|
|
|
|
# If no flags, install both
|
|
if not parsed_args.typescript and not parsed_args.python:
|
|
parsed_args.typescript = True
|
|
parsed_args.python = True
|
|
|
|
# --test implies --build
|
|
if parsed_args.test:
|
|
parsed_args.build = True
|
|
|
|
print("@image workspace install\n")
|
|
|
|
failed = []
|
|
succeeded = []
|
|
|
|
# Install root workspace (if exists)
|
|
root_package_json = workspace_root / "package.json"
|
|
if root_package_json.exists() and parsed_args.typescript:
|
|
print("Root Workspace")
|
|
print("─" * 50)
|
|
print("▶ Installing: workspace root")
|
|
|
|
result = subprocess.run(
|
|
["pnpm", "install"],
|
|
cwd=workspace_root,
|
|
capture_output=not parsed_args.verbose,
|
|
check=False,
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print("✓ PASS: workspace root")
|
|
succeeded.append("workspace:root")
|
|
else:
|
|
print("✗ FAIL: workspace root")
|
|
if not parsed_args.verbose and result.stderr:
|
|
print(f" Error: {result.stderr.decode()[:300]}")
|
|
failed.append("workspace:root")
|
|
|
|
print()
|
|
|
|
# Install TypeScript packages
|
|
if parsed_args.typescript:
|
|
print("TypeScript Packages")
|
|
print("─" * 50)
|
|
|
|
for pkg in TYPESCRIPT_PACKAGES:
|
|
pkg_path = workspace_root / pkg
|
|
|
|
if not pkg_path.exists():
|
|
print(f"⊘ SKIP: {pkg} (directory not found)")
|
|
continue
|
|
|
|
package_json = pkg_path / "package.json"
|
|
if not package_json.exists():
|
|
print(f"⊘ SKIP: {pkg} (no package.json)")
|
|
continue
|
|
|
|
print(f"▶ Installing: {pkg}")
|
|
|
|
# Run pnpm install
|
|
install_cmd = ["pnpm", "install"]
|
|
result = subprocess.run(
|
|
install_cmd,
|
|
cwd=pkg_path,
|
|
capture_output=not parsed_args.verbose,
|
|
check=False,
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print(f"✓ PASS: {pkg}")
|
|
succeeded.append(f"ts:{pkg}")
|
|
else:
|
|
print(f"✗ FAIL: {pkg}")
|
|
if not parsed_args.verbose and result.stderr:
|
|
print(f" Error: {result.stderr.decode()[:300]}")
|
|
failed.append(f"ts:{pkg}")
|
|
|
|
print()
|
|
|
|
print()
|
|
|
|
# Install Python services
|
|
if parsed_args.python:
|
|
print("Python Services")
|
|
print("─" * 50)
|
|
|
|
for service in PYTHON_SERVICES:
|
|
service_path = workspace_root / service
|
|
|
|
if not service_path.exists():
|
|
print(f"⊘ SKIP: {service} (directory not found)")
|
|
continue
|
|
|
|
# Check for pyproject.toml or setup.py
|
|
has_pyproject = (service_path / "pyproject.toml").exists()
|
|
has_setup = (service_path / "setup.py").exists()
|
|
|
|
if not has_pyproject and not has_setup:
|
|
print(f"⊘ SKIP: {service} (no pyproject.toml or setup.py)")
|
|
continue
|
|
|
|
print(f"▶ Installing: {service}")
|
|
|
|
venv_path = service_path / ".venv"
|
|
|
|
# Create venv if it doesn't exist
|
|
if not venv_path.exists():
|
|
print(f" Creating virtual environment...")
|
|
venv_cmd = ["python3", "-m", "venv", ".venv"]
|
|
result = subprocess.run(
|
|
venv_cmd,
|
|
cwd=service_path,
|
|
capture_output=not parsed_args.verbose,
|
|
check=False,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
print(f"✗ FAIL: {service} (venv creation failed)")
|
|
if not parsed_args.verbose and result.stderr:
|
|
print(f" Error: {result.stderr.decode()[:300]}")
|
|
failed.append(f"py:{service}")
|
|
print()
|
|
continue
|
|
|
|
# Install package in editable mode
|
|
print(f" Installing dependencies...")
|
|
activate_script = venv_path / "bin" / "activate"
|
|
|
|
# Install package in editable mode
|
|
pip_cmd = f"source {activate_script} && pip install -e ."
|
|
|
|
# Also install dev dependencies if available
|
|
if has_pyproject:
|
|
# Check if there are dev/test extras
|
|
pip_cmd += " && pip install -e '.[dev]' 2>/dev/null || true"
|
|
|
|
result = subprocess.run(
|
|
["bash", "-c", pip_cmd],
|
|
cwd=service_path,
|
|
capture_output=not parsed_args.verbose,
|
|
check=False,
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print(f"✓ PASS: {service}")
|
|
succeeded.append(f"py:{service}")
|
|
else:
|
|
print(f"✗ FAIL: {service}")
|
|
if not parsed_args.verbose and result.stderr:
|
|
print(f" Error: {result.stderr.decode()[:300]}")
|
|
failed.append(f"py:{service}")
|
|
|
|
print()
|
|
|
|
print()
|
|
|
|
# Summary
|
|
total = len(succeeded) + len(failed)
|
|
print("─" * 50)
|
|
print(f"Installed: {len(succeeded)}/{total} succeeded")
|
|
|
|
if failed:
|
|
print(f"\nFailed:")
|
|
for item in failed:
|
|
print(f" ✗ {item}")
|
|
return 1
|
|
|
|
print("\n✓ All dependencies installed successfully")
|
|
|
|
# Build if requested
|
|
if parsed_args.build and parsed_args.typescript:
|
|
print("\n" + "═" * 50)
|
|
print("Building TypeScript packages...")
|
|
print("═" * 50 + "\n")
|
|
|
|
# Import and call build command
|
|
import importlib.util
|
|
script_path = Path(__file__).resolve()
|
|
build_cmd_path = script_path.parent / "build_command.py"
|
|
spec = importlib.util.spec_from_file_location("build_command", build_cmd_path)
|
|
build_cmd = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(build_cmd)
|
|
|
|
build_args = []
|
|
if parsed_args.verbose:
|
|
build_args.append("-v")
|
|
|
|
result = build_cmd.build_command(build_args, workspace_root)
|
|
if result != 0:
|
|
print("\n✗ Build failed")
|
|
return result
|
|
|
|
# Test if requested
|
|
if parsed_args.test:
|
|
print("\n" + "═" * 50)
|
|
print("Running tests...")
|
|
print("═" * 50 + "\n")
|
|
|
|
# Import and call test command
|
|
import importlib.util
|
|
script_path = Path(__file__).resolve()
|
|
test_cmd_path = script_path.parent / "test_command.py"
|
|
spec = importlib.util.spec_from_file_location("test_command", test_cmd_path)
|
|
test_cmd = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(test_cmd)
|
|
|
|
test_args = ["--unit"] # Run unit tests only by default
|
|
if parsed_args.verbose:
|
|
test_args.append("-v")
|
|
|
|
result = test_cmd.test_command(test_args, workspace_root)
|
|
if result != 0:
|
|
print("\n✗ Tests failed")
|
|
return result
|
|
|
|
return 0
|
|
|
|
|
|
def register_install_command(runner):
|
|
"""Register the install command with the script runner.
|
|
|
|
Args:
|
|
runner: ScriptRunner instance
|
|
"""
|
|
runner.register_command(
|
|
"install",
|
|
install_command,
|
|
"Install dependencies for all packages",
|
|
)
|