#!/usr/bin/env bash # Tangle an .org file and compile the resulting .lisp with SBCL. # Reports the first compile error with line numbers. # # Usage: check-tangle # Exit 0 if compile succeeds, 1 if tangled or compilation fails set -euo pipefail if [ $# -ne 1 ]; then echo "Usage: check-tangle " >&2 exit 2 fi ORG_FILE="$1" if [ ! -f "$ORG_FILE" ]; then echo "Error: File not found: $ORG_FILE" >&2 exit 1 fi # Determine the tangle target from the org file TANGLE=$(grep -m1 'header-args.*:tangle' "$ORG_FILE" | sed 's/.*:tangle //' | head -1 || true) if [ -z "$TANGLE" ]; then echo "SKIP: $ORG_FILE — no :tangle header" >&2 exit 0 fi # Resolve relative tangle path ORG_DIR=$(dirname "$ORG_FILE") if [ "$TANGLE" = "${TANGLE#/}" ]; then # Relative path LISP_FILE=$(cd "$ORG_DIR" && realpath -m "$TANGLE" 2>/dev/null || echo "$ORG_DIR/$TANGLE") else # Absolute path LISP_FILE="$TANGLE" fi echo "Tangling: $ORG_FILE → $LISP_FILE" >&2 # Prefer the memex's own tangle tool, then fall back to PATH if [ -x "projects/tangle-tool/tangle" ]; then TANGLE_CMD="projects/tangle-tool/tangle" elif command -v tangle &>/dev/null; then TANGLE_CMD="tangle" else TANGLE_CMD="/home/user/.opencode/bin/tangle" fi if ! "$TANGLE_CMD" "$ORG_FILE"; then echo "FAIL: Tangling $ORG_FILE failed" >&2 exit 1 fi if [ ! -f "$LISP_FILE" ]; then echo "SKIP: Tangle target $LISP_FILE not found after tangling" >&2 exit 0 fi echo "Compiling: $LISP_FILE" >&2 # Compile with SBCL, capturing errors OUTPUT=$(sbcl --noinform --no-userinit --disable-debugger --quit \ --eval "(handler-case (progn (compile-file \"$LISP_FILE\") (print :OK)) (error (c) (print c) (sb-ext:exit :code 1)))" 2>&1 || true) if echo "$OUTPUT" | grep -q ":OK"; then echo "OK: $ORG_FILE compiles cleanly" >&2 exit 0 else echo "FAIL: $ORG_FILE — compilation error" >&2 echo "$OUTPUT" exit 1 fi