launch-dev script commit
This commit is contained in:
131
scripts/launch-dev.sh
Normal file
131
scripts/launch-dev.sh
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="${MOUSEHOLD_ROOT:-/mnt/DATA/git/mousehold}"
|
||||||
|
PYTHON="${PYTHON:-$ROOT/.venv/bin/python}"
|
||||||
|
NPM="${NPM:-npm}"
|
||||||
|
BACKEND_HOST="${MOUSEHOLD_BACKEND_HOST:-127.0.0.1}"
|
||||||
|
BACKEND_PORT="${MOUSEHOLD_BACKEND_PORT:-8000}"
|
||||||
|
FRONTEND_HOST="${MOUSEHOLD_FRONTEND_HOST:-127.0.0.1}"
|
||||||
|
FRONTEND_PORT="${MOUSEHOLD_FRONTEND_PORT:-5173}"
|
||||||
|
OPEN_BROWSER="${OPEN_BROWSER:-1}"
|
||||||
|
|
||||||
|
LOG_DIR="$ROOT/data/dev-launcher"
|
||||||
|
BACKEND_LOG="$LOG_DIR/backend.log"
|
||||||
|
FRONTEND_LOG="$LOG_DIR/frontend.log"
|
||||||
|
BACKEND_URL="http://$BACKEND_HOST:$BACKEND_PORT"
|
||||||
|
FRONTEND_URL="http://$FRONTEND_HOST:$FRONTEND_PORT"
|
||||||
|
|
||||||
|
backend_pid=""
|
||||||
|
frontend_pid=""
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf 'launch-dev: %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
port_is_free() {
|
||||||
|
"$PYTHON" - "$1" "$2" <<'PY'
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
port = int(sys.argv[2])
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
try:
|
||||||
|
sock.bind((host, port))
|
||||||
|
except OSError:
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_url() {
|
||||||
|
"$PYTHON" - "$1" <<'PY'
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
url = sys.argv[1]
|
||||||
|
deadline = time.monotonic() + 60
|
||||||
|
last_error = None
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(url, timeout=2) as response:
|
||||||
|
if 200 <= response.status < 500:
|
||||||
|
raise SystemExit(0)
|
||||||
|
except Exception as exc: # noqa: BLE001 - printed only on timeout.
|
||||||
|
last_error = exc
|
||||||
|
time.sleep(1)
|
||||||
|
print(f"Timed out waiting for {url}: {last_error}", file=sys.stderr)
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [ -n "${frontend_pid:-}" ] && kill -0 "$frontend_pid" 2>/dev/null; then
|
||||||
|
kill "$frontend_pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if [ -n "${backend_pid:-}" ] && kill -0 "$backend_pid" 2>/dev/null; then
|
||||||
|
kill "$backend_pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
[ -x "$PYTHON" ] || fail "Python virtualenv not found at $PYTHON. Run: cd $ROOT && python -m venv .venv && . .venv/bin/activate && pip install -r requirements-dev.txt && pip install -e ."
|
||||||
|
command -v "$NPM" >/dev/null 2>&1 || fail "npm not found. Install Node.js/npm, then rerun this launcher."
|
||||||
|
[ -d "$ROOT/node_modules" ] || fail "node_modules missing. Run: cd $ROOT && npm install"
|
||||||
|
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
: > "$BACKEND_LOG"
|
||||||
|
: > "$FRONTEND_LOG"
|
||||||
|
|
||||||
|
port_is_free "$BACKEND_HOST" "$BACKEND_PORT" || fail "$BACKEND_URL is already in use"
|
||||||
|
port_is_free "$FRONTEND_HOST" "$FRONTEND_PORT" || fail "$FRONTEND_URL is already in use"
|
||||||
|
|
||||||
|
printf 'Starting Mousehold API at %s\n' "$BACKEND_URL"
|
||||||
|
(
|
||||||
|
cd "$ROOT"
|
||||||
|
"$PYTHON" -m uvicorn mousehold_api.main:app --host "$BACKEND_HOST" --port "$BACKEND_PORT" --reload
|
||||||
|
) >"$BACKEND_LOG" 2>&1 &
|
||||||
|
backend_pid="$!"
|
||||||
|
|
||||||
|
printf 'Waiting for %s/health\n' "$BACKEND_URL"
|
||||||
|
wait_for_url "$BACKEND_URL/health" || {
|
||||||
|
tail -n 80 "$BACKEND_LOG" >&2 || true
|
||||||
|
fail "backend did not become healthy"
|
||||||
|
}
|
||||||
|
|
||||||
|
printf 'Starting Mousehold Web UI at %s\n' "$FRONTEND_URL"
|
||||||
|
(
|
||||||
|
cd "$ROOT/apps/web"
|
||||||
|
"$NPM" run dev -- --host "$FRONTEND_HOST" --port "$FRONTEND_PORT"
|
||||||
|
) >"$FRONTEND_LOG" 2>&1 &
|
||||||
|
frontend_pid="$!"
|
||||||
|
|
||||||
|
printf 'Waiting for %s\n' "$FRONTEND_URL"
|
||||||
|
wait_for_url "$FRONTEND_URL" || {
|
||||||
|
tail -n 80 "$FRONTEND_LOG" >&2 || true
|
||||||
|
fail "frontend did not become reachable"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$OPEN_BROWSER" = "1" ] && command -v xdg-open >/dev/null 2>&1; then
|
||||||
|
xdg-open "$FRONTEND_URL" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Mousehold is running.
|
||||||
|
Web UI: $FRONTEND_URL
|
||||||
|
API: $BACKEND_URL
|
||||||
|
Health: $BACKEND_URL/health
|
||||||
|
Docs: $BACKEND_URL/docs
|
||||||
|
|
||||||
|
Logs:
|
||||||
|
Backend: $BACKEND_LOG
|
||||||
|
Web UI: $FRONTEND_LOG
|
||||||
|
|
||||||
|
Press Ctrl+C to stop both processes.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
wait
|
||||||
Reference in New Issue
Block a user