#!/usr/bin/env python3
"""
Validate that the build package includes all necessary files.
This MUST pass before any installation.
"""
import sys
import subprocess
import tempfile
import shutil
from pathlib import Path
import zipfile
PROJECT_ROOT = Path(__file__).parent.parent
def run_command(cmd, cwd=None):
"""Run a command and return output."""
result = subprocess.run(
cmd,
shell=True,
capture_output=True,
text=True,
cwd=cwd or PROJECT_ROOT
)
return result.returncode == 0, result.stdout, result.stderr
def validate_build():
"""Validate the build package."""
print("=" * 60)
print("AMICUS MCP BUILD VALIDATION")
print("=" * 60)
print()
# Step 1: Build the package
print("Step 1: Building package...")
success, stdout, stderr = run_command("python -m build --wheel")
if not success:
print(f"✗ FAILED: Could not build package")
print(f" stderr: {stderr}")
return False
print("✓ Package built successfully")
print()
# Step 2: Find the wheel file
dist_dir = PROJECT_ROOT / "dist"
wheels = list(dist_dir.glob("amicus_mcp-*.whl"))
if not wheels:
print(f"✗ FAILED: No wheel file found in {dist_dir}")
return False
wheel_file = wheels[-1] # Latest wheel
print(f"Step 2: Inspecting wheel: {wheel_file.name}")
print()
# Step 3: Check wheel contents
required_files = [
"amicus/__init__.py",
"amicus/server.py",
"amicus/cli.py",
"amicus/core.py",
"amicus/config.py",
"amicus/monitor.py",
"amicus/security.py",
]
try:
with zipfile.ZipFile(wheel_file, 'r') as zf:
wheel_contents = set(zf.namelist())
print("Step 3: Checking required files in wheel...")
missing_files = []
for required_file in required_files:
if required_file not in wheel_contents:
missing_files.append(required_file)
print(f" ✗ Missing: {required_file}")
else:
print(f" ✓ Present: {required_file}")
if missing_files:
print(f"\n✗ FAILED: Missing {len(missing_files)} required files")
return False
# Check for .pyc files (shouldn't be in wheel)
pyc_files = [f for f in wheel_contents if f.endswith('.pyc')]
if pyc_files:
print(f"\n⚠ WARNING: Wheel contains .pyc files ({len(pyc_files)})")
except Exception as e:
print(f"✗ FAILED: Could not inspect wheel: {e}")
return False
print()
# Step 4: Test installation in temporary environment
print("Step 4: Testing installation in temporary environment...")
with tempfile.TemporaryDirectory() as tmpdir:
venv_dir = Path(tmpdir) / "test-env"
# Create venv
success, _, stderr = run_command(f"python -m venv {venv_dir}")
if not success:
print(f"✗ FAILED: Could not create venv: {stderr}")
return False
# Install wheel
pip_exe = venv_dir / "bin" / "pip"
success, _, stderr = run_command(f"{pip_exe} install {wheel_file}")
if not success:
print(f"✗ FAILED: Could not install wheel: {stderr}")
return False
# Test import
python_exe = venv_dir / "bin" / "python"
success, stdout, stderr = run_command(
f"{python_exe} -c 'import amicus.server; print(\"OK\")'"
)
if not success or "OK" not in stdout:
print(f"✗ FAILED: Could not import amicus.server: {stderr}")
return False
print("✓ Package installs and imports successfully")
print()
print("=" * 60)
print("✓ BUILD VALIDATION PASSED")
print("=" * 60)
return True
def main():
"""Run validation and exit with appropriate code."""
try:
result = validate_build()
sys.exit(0 if result else 1)
except Exception as e:
print(f"\n✗ VALIDATION FAILED WITH EXCEPTION:")
print(f" {type(e).__name__}: {e}")
import traceback
traceback.print_exc()
sys.exit(2)
if __name__ == "__main__":
main()