157 lines
5.4 KiB
YAML
157 lines
5.4 KiB
YAML
# artifact-export - Render artifacts to binary formats
|
|
# Usage: cat diagram.puml | artifact-export --format plantuml --to /tmp/diagram.svg
|
|
# Usage: cat model.scad | artifact-export --format openscad --to /tmp/model.png
|
|
|
|
name: artifact-export
|
|
description: Render artifact source code to binary formats (PNG, SVG, PDF)
|
|
category: Artifact
|
|
|
|
arguments:
|
|
- flag: --format
|
|
variable: format
|
|
required: true
|
|
description: "Source format: plantuml, mermaid, openscad, svg, excalidraw, code"
|
|
- flag: --to
|
|
variable: output_path
|
|
required: true
|
|
description: Output file path (extension determines output format, e.g. .png, .svg, .pdf)
|
|
|
|
steps:
|
|
- type: code
|
|
output_var: result
|
|
code: |
|
|
import subprocess
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
source_code = input.strip()
|
|
output = Path(output_path)
|
|
output_ext = output.suffix.lower()
|
|
|
|
# Ensure output directory exists
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
success = False
|
|
message = ""
|
|
|
|
if format == 'plantuml':
|
|
# Write to temp file
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.puml', delete=False) as f:
|
|
f.write(source_code)
|
|
temp_path = f.name
|
|
|
|
format_flag = {'.svg': '-tsvg', '.png': '-tpng', '.eps': '-teps', '.pdf': '-tpdf'}.get(output_ext, '-tsvg')
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['plantuml', format_flag, '-o', str(output.parent), temp_path],
|
|
capture_output=True, text=True, timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
# PlantUML outputs to same name with different extension
|
|
temp_base = Path(temp_path)
|
|
generated = output.parent / (temp_base.stem + output_ext)
|
|
if generated.exists():
|
|
import shutil
|
|
shutil.move(str(generated), str(output))
|
|
success = True
|
|
message = str(output)
|
|
else:
|
|
message = f"Generated file not found: {generated}"
|
|
else:
|
|
message = f"PlantUML error: {result.stderr}"
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
elif format == 'mermaid':
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.mmd', delete=False) as f:
|
|
f.write(source_code)
|
|
temp_path = f.name
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['mmdc', '-i', temp_path, '-o', str(output)],
|
|
capture_output=True, text=True, timeout=30
|
|
)
|
|
|
|
if result.returncode == 0 and output.exists():
|
|
success = True
|
|
message = str(output)
|
|
else:
|
|
message = f"Mermaid error: {result.stderr}"
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
elif format == 'openscad':
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.scad', delete=False) as f:
|
|
f.write(source_code)
|
|
temp_path = f.name
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
['openscad', '-o', str(output), temp_path],
|
|
capture_output=True, text=True, timeout=60
|
|
)
|
|
|
|
if result.returncode == 0 and output.exists():
|
|
success = True
|
|
message = str(output)
|
|
else:
|
|
message = f"OpenSCAD error: {result.stderr}"
|
|
finally:
|
|
os.unlink(temp_path)
|
|
|
|
elif format == 'svg':
|
|
if output_ext == '.svg':
|
|
output.write_text(source_code)
|
|
success = True
|
|
message = str(output)
|
|
elif output_ext == '.png':
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.svg', delete=False) as f:
|
|
f.write(source_code)
|
|
temp_path = f.name
|
|
|
|
try:
|
|
for cmd in [
|
|
['inkscape', temp_path, '-o', str(output)],
|
|
['rsvg-convert', temp_path, '-o', str(output)],
|
|
]:
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
if result.returncode == 0 and output.exists():
|
|
success = True
|
|
message = str(output)
|
|
break
|
|
except FileNotFoundError:
|
|
continue
|
|
if not success:
|
|
message = "SVG to PNG requires inkscape or rsvg-convert"
|
|
finally:
|
|
os.unlink(temp_path)
|
|
else:
|
|
message = f"Unsupported output format: {output_ext}"
|
|
|
|
elif format == 'code':
|
|
output.write_text(source_code)
|
|
success = True
|
|
message = str(output)
|
|
|
|
elif format == 'excalidraw':
|
|
if output_ext == '.json':
|
|
output.write_text(source_code)
|
|
success = True
|
|
message = str(output)
|
|
else:
|
|
message = "Excalidraw export currently only supports .json output"
|
|
|
|
else:
|
|
message = f"Unknown format: {format}"
|
|
|
|
print(json.dumps({'success': success, 'path' if success else 'error': message}))
|