#!/usr/bin/env bash # # build-stage.sh — Build the Stage marketing image (neuron-web + soul-demo). # # Pipeline: # 1. Stage the foundation El runtime into ./runtime/. # 2. Compile client-side El sources (src/js/*.el) to dist/js/*.js using # the JS-capable elc binary at bin/elc-linux-amd64 (CI) or the local # elc (dev). Output is gitignored and rebuilt every run. # 3. Concatenate src/*.el into dist/main-combined.el (component-first, # main.el last; matches the historical order from build-local.sh). # 4. Compile dist/main-combined.el → dist/main.c using the canonical # native elc at foundation/el/dist/platform/elc. # 5. Inject the host-side stub forward declarations into dist/main.c # (sed header rewrite, same set as the prior in-Dockerfile sed). # 6. docker buildx build --platform linux/amd64 -f Dockerfile.stage. # # bootstrap.py is no longer in the build path. The container image now # expects dist/main.c to be a finished C source — it just runs cc on it. # # Usage: # ./build-stage.sh — build marketing: set -euo pipefail cd "$(dirname "$0")" TAG="${1:-dev}" LANDING_DIR=$(pwd) EL_HOME="${EL_HOME:-${LANDING_DIR}/../../foundation/el}" ELC="${EL_HOME}/dist/platform/elc" RUNTIME_SRC="${EL_HOME}/el-compiler/runtime" # JS-capable elc: prefer committed bin/elc-linux-amd64 on CI (linux/amd64), # fall back to the local elc from the El checkout on macOS dev. if [ -f "${LANDING_DIR}/bin/elc-linux-amd64" ] && uname -m | grep -q x86_64; then ELC_JS="${LANDING_DIR}/bin/elc-linux-amd64" elif [ -x "${ELC}" ]; then ELC_JS="${ELC}" else echo "elc for JS compilation not found — expected bin/elc-linux-amd64 or ${ELC}" >&2 exit 1 fi if [ ! -x "${ELC}" ]; then echo "elc not found at ${ELC}" >&2 exit 1 fi echo "==> Staging El runtime from ${RUNTIME_SRC}" mkdir -p runtime dist cp "${RUNTIME_SRC}/el_runtime.c" runtime/ cp "${RUNTIME_SRC}/el_runtime.h" runtime/ # The JS compiler looks for el_runtime.js in the same directory as the # source file being compiled. Copy it there so --bundle can inline it. cp "${RUNTIME_SRC}/el_runtime.js" "${LANDING_DIR}/src/js/" echo "==> Compiling client-side El (src/js/*.el) → dist/js/" mkdir -p dist/js for f in "${LANDING_DIR}/src/js/"*.el; do name=$(basename "$f" .el) "${ELC_JS}" --target=js --bundle --minify --obfuscate "$f" > "${LANDING_DIR}/dist/js/${name}.js" echo " compiled: src/js/${name}.el → dist/js/${name}.js" done # Clean up the staged runtime (not a source file) rm -f "${LANDING_DIR}/src/js/el_runtime.js" echo "==> Combining El sources → dist/main-combined.el" COMPONENTS=(nav hero pillars how_it_works inference efficiency comparison environmental enterprise mission local_first pricing marketplace viral footer styles about founding_badge terms enterprise_terms checkout safety gallery account) { for f in "${COMPONENTS[@]}"; do if [ -f "src/${f}.el" ]; then grep -hv '^[[:space:]]*from\|^[[:space:]]*import' "src/${f}.el" echo "" fi done grep -v '^from\|^import' src/main.el } > dist/main-combined.el echo " $(wc -l < dist/main-combined.el) lines" echo "==> Compiling dist/main-combined.el → dist/main.c via ${ELC}" "${ELC}" dist/main-combined.el > dist/main.c echo " $(wc -l < dist/main.c) lines of C" echo "==> Injecting host-side stub forward declarations" # GNU vs BSD sed: -i with no arg works on GNU, breaks on macOS BSD sed # (BSD requires -i ''). Detect and branch. SED_INPLACE=(-i) if sed --version >/dev/null 2>&1; then SED_INPLACE=(-i) else SED_INPLACE=(-i '') fi sed "${SED_INPLACE[@]}" \ 's|#include "el_runtime.h"|#include "el_runtime.h"\nel_val_t http_get_auth(el_val_t url, el_val_t tok);\nel_val_t http_post_auth(el_val_t url, el_val_t tok, el_val_t body);\nel_val_t http_post_auth_json(el_val_t url, el_val_t tok, el_val_t body);\nel_val_t http_delete_auth(el_val_t url, el_val_t bearer_tok, el_val_t apikey);\nel_val_t cwd(void);\nel_val_t color_bold(el_val_t s);\nel_val_t unix_timestamp(void);\nel_val_t gcs_write(el_val_t bucket, el_val_t object_name, el_val_t content);\nel_val_t gcs_read(el_val_t bucket, el_val_t object_name);\nel_val_t supabase_insert(el_val_t project_url, el_val_t service_key, el_val_t table, el_val_t row_json);\nel_val_t supabase_get(el_val_t project_url, el_val_t service_key, el_val_t table_and_query);\nel_val_t supabase_auth_user(el_val_t project_url, el_val_t anon_key, el_val_t user_jwt);\nel_val_t supabase_admin_invite(el_val_t project_url, el_val_t service_key, el_val_t body_json);\nel_val_t supabase_upsert_user(el_val_t project_url, el_val_t anon_key, el_val_t user_jwt, el_val_t table_and_query, el_val_t row_json);|' \ dist/main.c echo "==> Building Docker image marketing:${TAG}" # Plain `docker build` — the gitea runner doesn't ship buildx, so # `docker buildx build --platform ...` exits 125 ("unknown flag: # --platform"). The runner host is already linux/amd64 so the # explicit --platform is redundant. BUILDKIT_INLINE_CACHE works with # plain docker as long as DOCKER_BUILDKIT=1 is set (default on the # runner). docker build \ --build-arg BUILDKIT_INLINE_CACHE=1 \ --cache-from us-central1-docker.pkg.dev/neuron-785695/neuron-marketing/marketing:latest \ -f Dockerfile.stage \ -t "marketing:${TAG}" \ . echo "==> Done. marketing:${TAG} built."