158 lines
4.5 KiB
Bash
Executable File
158 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Dev startup script for OwOrganizer.
|
|
# Runs the database in Docker and the backend/frontend natively.
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
DB_CONTAINER_NAME="oworganizer-dev-db"
|
|
DB_ROOT_PASSWORD="${DB_ROOT_PASSWORD:-top-secret}"
|
|
DB_PASSWORD="${DB_PASSWORD:-secret}"
|
|
DB_USER="oworganizer"
|
|
DB_NAME="oworganizer"
|
|
DB_PORT="${DB_PORT:-3306}"
|
|
|
|
# Colors for output
|
|
RESET='\033[0m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
RED='\033[0;31m'
|
|
|
|
log() {
|
|
echo -e "${GREEN}[dev]${RESET} $1"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[dev]${RESET} $1"
|
|
}
|
|
|
|
cleanup() {
|
|
echo
|
|
warn "Shutting down dev environment..."
|
|
|
|
if [[ -n "${BACKEND_PID:-}" ]] && kill -0 "$BACKEND_PID" 2>/dev/null; then
|
|
log "Stopping backend (PID $BACKEND_PID)..."
|
|
kill "$BACKEND_PID" 2>/dev/null || true
|
|
wait "$BACKEND_PID" 2>/dev/null || true
|
|
fi
|
|
|
|
if [[ -n "${FRONTEND_PID:-}" ]] && kill -0 "$FRONTEND_PID" 2>/dev/null; then
|
|
log "Stopping frontend (PID $FRONTEND_PID)..."
|
|
kill "$FRONTEND_PID" 2>/dev/null || true
|
|
wait "$FRONTEND_PID" 2>/dev/null || true
|
|
fi
|
|
|
|
if [[ "${STOP_DB_ON_EXIT:-true}" == "true" ]]; then
|
|
log "Stopping database container..."
|
|
docker stop "$DB_CONTAINER_NAME" >/dev/null 2>&1 || true
|
|
else
|
|
warn "Leaving database container '$DB_CONTAINER_NAME' running."
|
|
fi
|
|
|
|
log "Dev environment stopped."
|
|
}
|
|
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# Ensure required tools are available
|
|
command -v docker >/dev/null 2>&1 || { echo -e "${RED}docker is required but not installed.${RESET}"; exit 1; }
|
|
command -v go >/dev/null 2>&1 || { echo -e "${RED}go is required but not installed.${RESET}"; exit 1; }
|
|
command -v npm >/dev/null 2>&1 || { echo -e "${RED}npm is required but not installed.${RESET}"; exit 1; }
|
|
|
|
# Start the database container if it's not already running
|
|
if docker ps --format '{{.Names}}' | grep -q "^${DB_CONTAINER_NAME}$"; then
|
|
warn "Database container '$DB_CONTAINER_NAME' is already running. Reusing it."
|
|
elif docker ps -a --format '{{.Names}}' | grep -q "^${DB_CONTAINER_NAME}$"; then
|
|
log "Starting existing database container '$DB_CONTAINER_NAME'..."
|
|
docker start "$DB_CONTAINER_NAME" >/dev/null
|
|
else
|
|
log "Creating and starting database container '$DB_CONTAINER_NAME'..."
|
|
docker run -d \
|
|
--name "$DB_CONTAINER_NAME" \
|
|
-e MYSQL_ROOT_PASSWORD="$DB_ROOT_PASSWORD" \
|
|
-e MYSQL_USER="$DB_USER" \
|
|
-e MYSQL_PASSWORD="$DB_PASSWORD" \
|
|
-e MYSQL_DATABASE="$DB_NAME" \
|
|
-p "${DB_PORT}:3306" \
|
|
mariadb:10 \
|
|
--character-set-server=utf8mb4 \
|
|
--collation-server=utf8mb4_unicode_ci \
|
|
>/dev/null
|
|
fi
|
|
|
|
# Wait for MariaDB to be ready
|
|
log "Waiting for database to be ready..."
|
|
for i in {1..60}; do
|
|
if docker exec "$DB_CONTAINER_NAME" mysqladmin ping \
|
|
-h localhost -u "$DB_USER" --password="$DB_PASSWORD" \
|
|
>/dev/null 2>&1; then
|
|
# mysqladmin ping can return true before the server accepts SQL connections,
|
|
# so wait a little longer for the server to finish initializing.
|
|
sleep 2
|
|
log "Database is ready."
|
|
break
|
|
fi
|
|
if [[ "$i" -eq 60 ]]; then
|
|
echo -e "${RED}Database did not become ready in time.${RESET}"
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# Start the backend (with retries in case the DB isn't fully accepting connections yet)
|
|
log "Starting backend..."
|
|
cd "$PROJECT_DIR/backend"
|
|
|
|
BACKEND_START_ATTEMPTS="${BACKEND_START_ATTEMPTS:-3}"
|
|
for attempt in $(seq 1 "$BACKEND_START_ATTEMPTS"); do
|
|
DB_HOST=localhost DB_PASSWORD="$DB_PASSWORD" go run . &
|
|
BACKEND_PID=$!
|
|
|
|
# Wait for backend to be ready
|
|
log "Waiting for backend to be ready (attempt $attempt/$BACKEND_START_ATTEMPTS)..."
|
|
ready=false
|
|
for i in {1..30}; do
|
|
if curl -s http://localhost:8080/ping >/dev/null 2>&1; then
|
|
log "Backend is ready at http://localhost:8080"
|
|
ready=true
|
|
break
|
|
fi
|
|
if ! kill -0 "$BACKEND_PID" 2>/dev/null; then
|
|
warn "Backend exited early, possibly waiting for DB."
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [[ "$ready" == "true" ]]; then
|
|
break
|
|
fi
|
|
|
|
if [[ "$attempt" -eq "$BACKEND_START_ATTEMPTS" ]]; then
|
|
echo -e "${RED}Backend did not become ready after $BACKEND_START_ATTEMPTS attempts.${RESET}"
|
|
exit 1
|
|
fi
|
|
|
|
warn "Retrying backend startup..."
|
|
sleep 2
|
|
done
|
|
|
|
# Start the frontend
|
|
log "Starting frontend..."
|
|
cd "$PROJECT_DIR/frontend"
|
|
if [[ ! -f .env ]]; then
|
|
warn "No .env file found in frontend/. Creating from .env.example..."
|
|
cp .env.example .env
|
|
fi
|
|
npm run dev &
|
|
FRONTEND_PID=$!
|
|
|
|
log "Frontend starting. It will be available at http://localhost:5173"
|
|
log "${BLUE}Press Ctrl-C to stop all services.${RESET}"
|
|
|
|
# Wait for either process to exit
|
|
wait -n "$BACKEND_PID" "$FRONTEND_PID" 2>/dev/null || true
|