"""compile_scad — generate STL from an OpenSCAD script."""
from __future__ import annotations
import asyncio
import shutil
from pathlib import Path
from .config import Settings
async def compile_scad(
settings: Settings,
session_id: str,
source_path: str,
output_path: str,
) -> dict:
"""Compile a .scad file into a binary STL.
Returns a dict with:
- success (bool)
- output (str) — human-readable summary
- error (str | None)
- metadata (dict) — output_path, size_kb
"""
if not shutil.which(settings.openscad):
return {
"success": False,
"output": "OpenSCAD is not installed on this system.",
"error": "openscad_not_found",
"metadata": {},
}
try:
scad_path = settings.resolve_path(session_id, source_path)
stl_path = settings.resolve_path(session_id, output_path)
except ValueError as exc:
return {
"success": False,
"output": str(exc),
"error": "invalid_path",
"metadata": {},
}
if not scad_path.exists():
return {
"success": False,
"output": f"SCAD file not found: {scad_path}",
"error": "scad_not_found",
"metadata": {},
}
if not scad_path.is_file():
return {
"success": False,
"output": f"Path is not a file: {scad_path}",
"error": "not_a_file",
"metadata": {},
}
stl_path.parent.mkdir(parents=True, exist_ok=True)
proc = await asyncio.create_subprocess_exec(
settings.openscad,
"--export-format", "binstl",
"-o", str(stl_path),
str(scad_path),
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await proc.communicate()
if proc.returncode != 0:
err = (stderr.decode(errors="replace") or "OpenSCAD exited with an error.").strip()
return {
"success": False,
"output": f"OpenSCAD failed to compile STL:\n{err}",
"error": "openscad_compile_error",
"metadata": {},
}
if not stl_path.exists():
return {
"success": False,
"output": "OpenSCAD completed but no STL file was produced.",
"error": "no_output",
"metadata": {},
}
size_kb = stl_path.stat().st_size / 1024
return {
"success": True,
"output": (
f"Generated: {stl_path.name}\n"
f"Path: {stl_path}\n"
f"Size: {size_kb:.1f} KB"
),
"error": None,
"metadata": {
"output_path": str(stl_path),
"size_kb": round(size_kb, 1),
},
}