This commit is contained in:
120
dev.sh
120
dev.sh
@@ -1,20 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# dev.sh — start/stop the frontend (Nuxt) and backend (Express) together.
|
||||
# dev.sh — start/stop the frontend (Nuxt), backend (Express) and the Lean
|
||||
# editor server (lean4web via docker compose) together.
|
||||
#
|
||||
# Usage:
|
||||
# ./dev.sh Start both in the foreground (Ctrl+C stops both)
|
||||
# ./dev.sh start Start both dev servers in the background
|
||||
# ./dev.sh stop Stop both dev servers
|
||||
# ./dev.sh Start everything in the foreground (Ctrl+C stops all)
|
||||
# ./dev.sh start Start everything in the background
|
||||
# ./dev.sh stop Stop everything
|
||||
# ./dev.sh restart Stop then start
|
||||
# ./dev.sh status Show which services are running
|
||||
# ./dev.sh logs [service] Follow logs (all, backend, or frontend)
|
||||
# ./dev.sh status Show what is running
|
||||
# ./dev.sh logs [service] Follow logs (all, backend, frontend, or lean)
|
||||
#
|
||||
# backend and frontend are npm dev servers; lean is the Lean editor server
|
||||
# from docker-compose.yml (see lean/). It is the heavy one — the image's
|
||||
# first build fetches Mathlib — so dev.sh only rides along with docker: when
|
||||
# docker is not available it says so and starts the other two regardless.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PID_DIR="$ROOT/.pids"
|
||||
LOG_DIR="$ROOT/.logs"
|
||||
COMPOSE="$ROOT/docker-compose.yml"
|
||||
SERVICES=("backend" "frontend")
|
||||
LEAN_LOG="$LOG_DIR/lean.log"
|
||||
|
||||
compose() { docker compose -f "$COMPOSE" "$@"; }
|
||||
|
||||
# The Lean server needs docker up, not just installed — probing the daemon
|
||||
# keeps a dead docker socket from failing backend + frontend.
|
||||
docker_ready() {
|
||||
command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1
|
||||
}
|
||||
|
||||
lean_running() {
|
||||
docker_ready && [[ -n "$(compose ps --status running --services 2>/dev/null | grep -x lean)" ]]
|
||||
}
|
||||
|
||||
pid_of() {
|
||||
local pid_file="$PID_DIR/$1.pid"
|
||||
@@ -43,6 +63,25 @@ start_service() {
|
||||
echo "started $name (PID $pid) — log: $LOG_DIR/$name.log"
|
||||
}
|
||||
|
||||
# `up -d` also builds the image the first time it is asked for (heavy:
|
||||
# Mathlib), so this rides in the background with its output to lean.log
|
||||
# rather than holding `start` hostage to a cold build.
|
||||
start_lean() {
|
||||
if lean_running; then
|
||||
echo "lean is already running (docker compose)"
|
||||
return
|
||||
fi
|
||||
if ! docker_ready; then
|
||||
echo "lean: docker is not available — skipping the Lean server (see lean/README.md)" >&2
|
||||
return
|
||||
fi
|
||||
mkdir -p "$LOG_DIR"
|
||||
setsid bash -c 'cd "$1" && exec docker compose -f "$2" up -d lean' _ "$ROOT" "$COMPOSE" \
|
||||
> "$LEAN_LOG" 2>&1 &
|
||||
echo "starting lean (docker compose) — log: $LEAN_LOG"
|
||||
echo " (the first build fetches Mathlib and takes a while)"
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
local name="$1"
|
||||
local pid
|
||||
@@ -68,6 +107,17 @@ stop_service() {
|
||||
echo "stopped $name (PID $pid)"
|
||||
}
|
||||
|
||||
# `stop`, not `down` — the container is kept (like a stopped dev server),
|
||||
# and `docker compose down` stays the maintainer's call.
|
||||
stop_lean() {
|
||||
if ! lean_running; then
|
||||
echo "lean is not running"
|
||||
return
|
||||
fi
|
||||
compose stop lean >/dev/null 2>&1 || true
|
||||
echo "stopped lean (docker compose)"
|
||||
}
|
||||
|
||||
status() {
|
||||
for name in "${SERVICES[@]}"; do
|
||||
if is_running "$name"; then
|
||||
@@ -76,9 +126,17 @@ status() {
|
||||
echo "$name: stopped"
|
||||
fi
|
||||
done
|
||||
if lean_running; then
|
||||
echo "lean: running (docker compose)"
|
||||
elif docker_ready; then
|
||||
echo "lean: stopped"
|
||||
else
|
||||
echo "lean: stopped (docker is not available)"
|
||||
fi
|
||||
}
|
||||
|
||||
FG_PIDS=()
|
||||
LEAN_PID=""
|
||||
SHUTTING=0
|
||||
|
||||
# Stop all foreground services (and their process groups). A second call
|
||||
@@ -88,11 +146,17 @@ fg_stop_all() {
|
||||
if [[ $SHUTTING -eq 1 ]]; then sig=KILL; else
|
||||
SHUTTING=1
|
||||
echo
|
||||
echo "stopping frontend + backend..."
|
||||
echo "stopping backend + frontend + lean..."
|
||||
fi
|
||||
for pid in "${FG_PIDS[@]:-}"; do
|
||||
kill -"$sig" -- "-$pid" 2>/dev/null || kill -"$sig" "$pid" 2>/dev/null || true
|
||||
done
|
||||
if [[ -n "$LEAN_PID" ]]; then
|
||||
kill -"$sig" -- "-$LEAN_PID" 2>/dev/null || kill -"$sig" "$LEAN_PID" 2>/dev/null || true
|
||||
# belt and braces: if the compose client died before telling dockerd,
|
||||
# the container is still up — `stop` is quick and idempotent.
|
||||
docker_ready && compose stop lean >/dev/null 2>&1 || true
|
||||
fi
|
||||
wait 2>/dev/null || true
|
||||
for name in "${SERVICES[@]}"; do rm -f "$PID_DIR/$name.pid"; done
|
||||
exit 0
|
||||
@@ -116,11 +180,22 @@ foreground() {
|
||||
FG_PIDS+=("$pid")
|
||||
echo "$pid" > "$PID_DIR/$name.pid"
|
||||
done
|
||||
# The Lean server rides along the same way — compose `up` streams its
|
||||
# build/run output, tagged. But the pair stays in charge: lean's absence
|
||||
# (no docker) or its failure (no image, daemon flake) never takes them
|
||||
# down, so `wait -n` watches only the npm services.
|
||||
if docker_ready; then
|
||||
setsid bash -c 'cd "$1" && exec docker compose -f "$2" up lean' _ "$ROOT" "$COMPOSE" \
|
||||
> >(sed -u "s/^/[lean] /") 2>&1 &
|
||||
LEAN_PID=$!
|
||||
else
|
||||
echo "[lean] docker is not available — running without the Lean server (see lean/README.md)" >&2
|
||||
fi
|
||||
trap 'fg_stop_all' INT TERM
|
||||
echo "frontend + backend running — press Ctrl+C to stop both"
|
||||
# Exit as soon as either service dies, so they always run/stop together.
|
||||
wait -n
|
||||
echo "a dev server exited — stopping the other one..."
|
||||
echo "backend + frontend running (lean if docker allows) — press Ctrl+C to stop all"
|
||||
# Exit as soon as either dev server dies, so they always run/stop together.
|
||||
wait -n "${FG_PIDS[@]}"
|
||||
echo "a dev server exited — stopping the others..."
|
||||
fg_stop_all
|
||||
}
|
||||
|
||||
@@ -130,29 +205,46 @@ case "${1:-dev}" in
|
||||
;;
|
||||
start)
|
||||
for name in "${SERVICES[@]}"; do start_service "$name"; done
|
||||
start_lean
|
||||
echo
|
||||
echo "backend: http://localhost:5000"
|
||||
echo "frontend: http://localhost:3000"
|
||||
echo "lean: http://localhost:8080 (docker compose) — the wiki frames it at /lean"
|
||||
;;
|
||||
stop)
|
||||
for name in "${SERVICES[@]}"; do stop_service "$name"; done
|
||||
stop_lean
|
||||
;;
|
||||
restart)
|
||||
for name in "${SERVICES[@]}"; do stop_service "$name"; done
|
||||
stop_lean
|
||||
for name in "${SERVICES[@]}"; do start_service "$name"; done
|
||||
start_lean
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
logs)
|
||||
case "${2:-all}" in
|
||||
all) tail -f "$LOG_DIR"/*.log ;;
|
||||
# `all` mixes the file logs with the container's — lean lives in
|
||||
# docker, not in a dev.log, once it is up.
|
||||
all)
|
||||
if docker_ready; then
|
||||
compose logs -f lean &
|
||||
LEAN_LOG_PID=$!
|
||||
trap 'kill "$LEAN_LOG_PID" 2>/dev/null || true' INT TERM
|
||||
fi
|
||||
tail -f "$LOG_DIR"/*.log
|
||||
;;
|
||||
backend|frontend) tail -f "$LOG_DIR/$2.log" ;;
|
||||
*) echo "usage: $0 logs [all|backend|frontend]"; exit 1 ;;
|
||||
lean)
|
||||
if docker_ready; then compose logs -f lean; else echo "docker is not available" >&2; exit 1; fi
|
||||
;;
|
||||
*) echo "usage: $0 logs [all|backend|frontend|lean]"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [dev|start|stop|restart|status|logs [all|backend|frontend]] (default: dev)"
|
||||
echo "usage: $0 [dev|start|stop|restart|status|logs [all|backend|frontend|lean]] (default: dev)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user