this repo has no description
1#!/bin/bash
2# Deploy interactive OCaml demo pages.
3#
4# This script builds 6 demo pages that showcase in-browser OCaml evaluation
5# using the odoc-interactive-extension and js_top_worker (jtw).
6#
7# ─── One-time setup ──────────────────────────────────────────────────────
8#
9# This script uses `jtw opam` to build universes from local opam switches.
10# In production, `day10 batch --with-jtw` does this at scale inside
11# containers (see docs/jtw-admin-guide.md). The manual switch setup
12# below is the local-dev path for running these demos.
13#
14# 1. Create the opam switches. The "default" switch is used for building
15# the monorepo and for the yojson 3.x universes.
16#
17# # default switch (should already exist)
18# opam switch create default ocaml-base-compiler.5.4.1
19# eval $(opam env --switch default --set-switch)
20# opam install yojson
21#
22# # yojson 2.x switch (for demo2_v2)
23# opam switch create demo-yojson-v2 ocaml-base-compiler.5.4.1
24# eval $(opam env --switch demo-yojson-v2 --set-switch)
25# opam install yojson.2.2.2
26#
27# # OxCaml switch (for demo3_oxcaml)
28# opam switch create 5.2.0+ox \
29# --repos ox=git+https://github.com/oxcaml/opam-repository.git,default
30#
31# 2. Pin and install js_top_worker packages in every switch that needs a
32# universe. From the monorepo root:
33#
34# for sw in default demo-yojson-v2 5.2.0+ox; do
35# eval $(opam env --switch $sw --set-switch)
36# opam pin add js_top_worker . --no-action
37# opam pin add js_top_worker-web . --no-action
38# opam install js_top_worker js_top_worker-web
39# done
40#
41# 3. Build and install the monorepo tools (jtw, odoc, the extension)
42# into the default switch:
43#
44# eval $(opam env --switch default --set-switch)
45# dune build @install && dune install
46#
47# After this, `jtw opam --help` should work.
48#
49# ─── Production alternative (day10) ─────────────────────────────────────
50#
51# For building universes at scale (e.g. all of opam), use day10 instead
52# of manual switches. day10 runs builds in OCI containers with cached
53# overlay layers. See day10/docs/ADMIN_GUIDE.md for full details.
54#
55# dune exec -- day10 batch \
56# --cache-dir /var/cache/day10 \
57# --opam-repository /var/cache/opam-repository \
58# --local-repo /path/to/js_top_worker \
59# --with-jtw \
60# --jtw-output /var/www/jtw \
61# --html-output /var/www/docs \
62# --with-doc \
63# @packages.json
64#
65# --local-repo pins js_top_worker packages from a local checkout instead
66# of the default remote git repo. day10 discovers *.opam files in that
67# directory, bind-mounts it into the container, and uses it for pinning.
68# This is the easiest way to test local changes to js_top_worker.
69#
70# day10 handles switch creation, dependency solving, js_top_worker
71# installation, and per-package universe assembly automatically.
72#
73# ─── Usage ───────────────────────────────────────────────────────────────
74#
75# ./deploy.sh # build everything and serve on port 8080
76# ./deploy.sh --no-serve # build only, don't start HTTP server
77
78set -euo pipefail
79
80MONO=$(cd "$(dirname "$0")/.." && pwd)
81DOC_HTML="$MONO/_build/default/_doc/_html/odoc-interactive-extension"
82ODOCL="$MONO/_build/default/_doc/_odocl/odoc-interactive-extension"
83OPAM_ODOC="$HOME/.opam/default/bin/odoc"
84UNIVERSES=$(mktemp -d)
85SERVE=true
86
87if [[ "${1:-}" == "--no-serve" ]]; then
88 SERVE=false
89fi
90
91echo "=== Step 1: Install odoc extension into opam switch ==="
92cd "$MONO"
93export OPAMSWITCH=default
94eval "$(opam env)"
95dune build @install
96dune install 2>&1 | tail -5
97
98echo ""
99echo "=== Step 2: Build odoc docs (generates .odocl + base HTML) ==="
100# @doc may exit non-zero due to warnings in other packages (e.g. odoc's own
101# cheatsheet referencing cmdliner). We tolerate that as long as the odocl
102# files we need were actually produced.
103dune build @doc 2>&1 | tail -5 || true
104if [ ! -f "$ODOCL/page-demo1.odocl" ]; then
105 echo "ERROR: odocl files not generated — dune build @doc failed." >&2
106 exit 1
107fi
108
109echo ""
110echo "=== Step 3: Regenerate demo HTML with opam odoc (has extension) ==="
111# dune's workspace-local odoc can't find dune-site plugins, so we use the
112# opam-installed one which has the extension registered.
113for page in demo1 demo2_v2 demo2_v3 demo3_oxcaml demo4_crossorigin demo5_multiverse; do
114 chmod u+w "$DOC_HTML/${page}.html" 2>/dev/null || true
115 "$OPAM_ODOC" html-generate "$ODOCL/page-${page}.odocl" \
116 -o "$DOC_HTML/.." \
117 --support-uri=_odoc_support 2>&1
118 echo " regenerated ${page}.html"
119done
120
121echo ""
122echo "=== Step 4: Build x-ocaml.js ==="
123dune build x-ocaml/src/x_ocaml.bc.js
124
125echo ""
126echo "=== Step 5: Build universes ==="
127
128# 5a. Default universe (yojson 3.0 — used by demo1)
129echo " building default universe (yojson, default switch)..."
130jtw opam --switch=default -o "$UNIVERSES/default" yojson
131
132# 5b. Yojson v2 universe
133echo " building yojson-v2 universe (demo-yojson-v2 switch)..."
134jtw opam --switch=demo-yojson-v2 -o "$UNIVERSES/v2" yojson
135
136# 5c. Yojson v3 universe (same as default, but separate dir for isolation)
137echo " building yojson-v3 universe (default switch)..."
138jtw opam --switch=default -o "$UNIVERSES/v3" yojson
139
140# 5d. OxCaml universe (stdlib only)
141echo " building oxcaml universe (5.2.0+ox switch)..."
142jtw opam --switch=5.2.0+ox -o "$UNIVERSES/oxcaml"
143
144echo ""
145echo "=== Step 6: Deploy assets into doc HTML output ==="
146
147# _x-ocaml runtime (shared by all pages)
148mkdir -p "$DOC_HTML/_x-ocaml"
149chmod -R u+w "$DOC_HTML/_x-ocaml" 2>/dev/null || true
150cp "$MONO/_build/default/x-ocaml/src/x_ocaml.bc.js" "$DOC_HTML/_x-ocaml/x-ocaml.js"
151cp "$UNIVERSES/default/worker.js" "$DOC_HTML/_x-ocaml/worker.js"
152echo " deployed _x-ocaml/"
153
154# Make deployed dirs writable so re-runs can overwrite them.
155chmod -R u+w "$DOC_HTML/universe" "$DOC_HTML/universe-v2" \
156 "$DOC_HTML/universe-v3" "$DOC_HTML/universe-oxcaml" 2>/dev/null || true
157
158# demo1: ./universe
159rm -rf "$DOC_HTML/universe"
160cp -r "$UNIVERSES/default" "$DOC_HTML/universe"
161echo " deployed universe/ (demo1)"
162
163# demo2_v2: ./universe-v2
164rm -rf "$DOC_HTML/universe-v2"
165cp -r "$UNIVERSES/v2" "$DOC_HTML/universe-v2"
166echo " deployed universe-v2/ (demo2_v2)"
167
168# demo2_v3: ./universe-v3
169rm -rf "$DOC_HTML/universe-v3"
170cp -r "$UNIVERSES/v3" "$DOC_HTML/universe-v3"
171echo " deployed universe-v3/ (demo2_v3)"
172
173# demo3_oxcaml: ./universe-oxcaml
174rm -rf "$DOC_HTML/universe-oxcaml"
175cp -r "$UNIVERSES/oxcaml" "$DOC_HTML/universe-oxcaml"
176echo " deployed universe-oxcaml/ (demo3_oxcaml)"
177
178# Copy x-ocaml.js into each universe (for cross-origin blob: fallback)
179for d in universe universe-v2 universe-v3 universe-oxcaml; do
180 cp "$DOC_HTML/_x-ocaml/x-ocaml.js" "$DOC_HTML/$d/x-ocaml.js"
181done
182
183# Cross-origin universe (same content as default, served on port 9090)
184CROSSORIGIN_DIR="$DOC_HTML/../_crossorigin_universes"
185chmod -R u+w "$CROSSORIGIN_DIR" 2>/dev/null || true
186rm -rf "$CROSSORIGIN_DIR"
187mkdir -p "$CROSSORIGIN_DIR"
188cp -r "$DOC_HTML/universe" "$CROSSORIGIN_DIR/universe"
189echo " deployed _crossorigin_universes/ (for port 9090)"
190
191# Multiverse (per-package layout with universe linking)
192echo ""
193echo "=== Step 7: Build multiverse (per-package layout) ==="
194MULTIVERSE_DIR="$DOC_HTML/../_multiverse"
195chmod -R u+w "$MULTIVERSE_DIR" 2>/dev/null || true
196rm -rf "$MULTIVERSE_DIR"
197jtw opam-all --switch=default yojson -o "$MULTIVERSE_DIR"
198cp "$MONO/_build/default/x-ocaml/src/x_ocaml.bc.js" "$MULTIVERSE_DIR/x-ocaml.js"
199echo " deployed _multiverse/ (for port 9090)"
200
201echo ""
202echo "=== Done ==="
203echo "Demo pages at: $DOC_HTML/"
204echo ""
205echo " demo1.html — basic OCaml + yojson (default switch)"
206echo " demo2_v2.html — yojson 2.2.2 (demo-yojson-v2 switch)"
207echo " demo2_v3.html — yojson 3.0.0 (default switch)"
208echo " demo3_oxcaml.html — OxCaml extensions (5.2.0+ox switch)"
209echo " demo4_crossorigin.html — cross-origin loading (needs port 9090)"
210echo " demo5_multiverse.html — multiverse per-package layout (needs port 9090)"
211echo ""
212echo "Cross-origin demos (demo4, demo5) require a CORS-enabled server on port 9090."
213echo "They serve different directories, so you can only test one at a time:"
214echo ""
215echo " demo4 (cross-origin):"
216echo " python3 $MONO/odoc-interactive-extension/cors_server.py 9090 $DOC_HTML/../_crossorigin_universes"
217echo ""
218echo " demo5 (multiverse):"
219echo " python3 $MONO/odoc-interactive-extension/cors_server.py 9090 $DOC_HTML/../_multiverse"
220
221# Clean up
222rm -rf "$UNIVERSES"
223
224if $SERVE; then
225 echo ""
226 echo "Starting HTTP server on http://localhost:8080"
227 echo "Visit: http://localhost:8080/odoc-interactive-extension/demo1.html"
228 echo ""
229 cd "$DOC_HTML/.."
230 exec python3 -m http.server 8080
231fi