more boilerplate and dev environment
This commit is contained in:
Executable
+157
@@ -0,0 +1,157 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user