feat: composer improvements
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
"""µFrame compile, DSL metadata, and image upload endpoints."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException, UploadFile, File
|
||||
@@ -14,6 +17,31 @@ from uframe.registry import get_dsl_meta
|
||||
router = APIRouter()
|
||||
|
||||
UPLOAD_DIR = Path(os.environ.get("SOURCES_DIR", "/data/sources")) / "images"
|
||||
BACKEND_DIR = str(Path(__file__).resolve().parent)
|
||||
|
||||
|
||||
def execute_dynamic_script(script: str, timeout: int = 10) -> str:
|
||||
"""Execute a dynamic page script and return its stdout (micron output).
|
||||
|
||||
Used by both the compile preview and the browse page reader.
|
||||
"""
|
||||
env = {**os.environ, "PYTHONPATH": BACKEND_DIR}
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
|
||||
f.write(script)
|
||||
f.flush()
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[sys.executable, f.name],
|
||||
capture_output=True, text=True, timeout=timeout,
|
||||
cwd=BACKEND_DIR, env=env,
|
||||
)
|
||||
if result.returncode != 0 and result.stderr:
|
||||
return result.stderr
|
||||
return result.stdout
|
||||
except subprocess.TimeoutExpired:
|
||||
return "Error: script timed out"
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
class CompileRequest(BaseModel):
|
||||
@@ -31,12 +59,26 @@ class CompileResponse(BaseModel):
|
||||
|
||||
@router.post("/compile", response_model=CompileResponse)
|
||||
async def compile_source(req: CompileRequest):
|
||||
"""Compile µFrame .uf source into ASCII and Micron output."""
|
||||
"""Compile µFrame .uf source into ASCII and Micron output.
|
||||
|
||||
For dynamic pages, the generated script is executed and the
|
||||
resolved micron output replaces the static micron in the response.
|
||||
"""
|
||||
try:
|
||||
result = uframe.compile(req.source, width=req.width)
|
||||
|
||||
micron = result.micron
|
||||
if result.is_dynamic and result.script:
|
||||
executed = execute_dynamic_script(result.script)
|
||||
# Strip cache header line if present
|
||||
lines = executed.split("\n")
|
||||
if lines and lines[0].startswith("#!c="):
|
||||
lines = lines[1:]
|
||||
micron = "\n".join(lines)
|
||||
|
||||
return CompileResponse(
|
||||
ascii=result.ascii,
|
||||
micron=result.micron,
|
||||
micron=micron,
|
||||
script=result.script,
|
||||
is_dynamic=result.is_dynamic,
|
||||
warnings=[w.message for w in result.warnings],
|
||||
|
||||
Reference in New Issue
Block a user