Commit
This commit is contained in:
parent
d7c2152557
commit
4d2a96c045
245
quickstart.sh
Normal file
245
quickstart.sh
Normal file
@ -0,0 +1,245 @@
|
||||
#!/usr/bin/env bash
|
||||
# quickstart.sh - improved quickstart with Docker MySQL + backend + frontend
|
||||
# Usage: ./quickstart.sh
|
||||
set -euo pipefail
|
||||
|
||||
# ---------- CONFIG ----------
|
||||
BACKEND_DIR="backend"
|
||||
FRONTEND_DIR="frontend"
|
||||
BACKEND_LOG="backend.log"
|
||||
FRONTEND_LOG="frontend.log"
|
||||
VENV_DIR="$BACKEND_DIR/.venv"
|
||||
MYSQL_CONTAINER="sqlilab_mysql"
|
||||
MYSQL_PORT=3307
|
||||
MYSQL_ROOT_PASSWORD="12345"
|
||||
MYSQL_DATABASE="sqlilab"
|
||||
PYTHON_BIN=""
|
||||
PIP_BIN=""
|
||||
# ----------------------------
|
||||
|
||||
timestamp() { date +"%Y-%m-%d %H:%M:%S"; }
|
||||
|
||||
info() { echo -e "$(timestamp) [INFO] $*"; }
|
||||
fail() { echo -e "$(timestamp) [ERROR] $*" >&2; exit 1; }
|
||||
|
||||
# Check if Docker is installed and running
|
||||
check_docker() {
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
fail "Docker not found. Please install Docker first: https://docs.docker.com/get-docker/"
|
||||
fi
|
||||
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
fail "Docker daemon is not running. Please start Docker."
|
||||
fi
|
||||
}
|
||||
|
||||
# detect python3 and pip
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
PYTHON_BIN="python3"
|
||||
elif command -v python >/dev/null 2>&1 && "$({ python -V; } 2>&1)" | grep -q "Python 3"; then
|
||||
PYTHON_BIN="python"
|
||||
else
|
||||
fail "python3 not found. Install Python 3."
|
||||
fi
|
||||
|
||||
if command -v pip3 >/dev/null 2>&1; then
|
||||
PIP_BIN="pip3"
|
||||
elif command -v pip >/dev/null 2>&1; then
|
||||
PIP_BIN="pip"
|
||||
else
|
||||
fail "pip not found. Install pip for Python 3."
|
||||
fi
|
||||
|
||||
# helper to start background processes and save PID
|
||||
start_bg() {
|
||||
# args: command logfile pidfile
|
||||
local cmd="$1"; local logfile="$2"; local pidfile="$3"
|
||||
nohup bash -lc "$cmd" >>"$logfile" 2>&1 &
|
||||
local pid=$!
|
||||
echo "$pid" > "$pidfile"
|
||||
info "Started: '$cmd' (pid=$pid) -> $logfile"
|
||||
}
|
||||
|
||||
# ensure directories exist
|
||||
[ -d "$BACKEND_DIR" ] || fail "Backend directory '$BACKEND_DIR' not found."
|
||||
[ -d "$FRONTEND_DIR" ] || fail "Frontend directory '$FRONTEND_DIR' not found."
|
||||
|
||||
# Check if init.sql exists in backend/
|
||||
if [ ! -f "./$BACKEND_DIR/init.sql" ]; then
|
||||
fail "BACKEND_DIR/init.sql not found. Please create the database initialization script at $BACKEND_DIR/init.sql"
|
||||
fi
|
||||
|
||||
# ---------- DOCKER MYSQL SETUP ----------
|
||||
info "Setting up MySQL Docker container..."
|
||||
check_docker
|
||||
|
||||
# Stop and remove existing container if it exists (we remove to ensure init.sql runs on first start)
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$"; then
|
||||
info "Removing existing MySQL container (if you want to keep data, skip removal)..."
|
||||
docker stop "$MYSQL_CONTAINER" 2>/dev/null || true
|
||||
docker rm "$MYSQL_CONTAINER" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Pull MySQL image
|
||||
info "Pulling MySQL 8.0 image..."
|
||||
docker pull mysql:8.0
|
||||
|
||||
# Start MySQL container and mount backend/init.sql into the official init folder
|
||||
info "Starting MySQL container..."
|
||||
docker run -d \
|
||||
--name "$MYSQL_CONTAINER" \
|
||||
-e MYSQL_ROOT_PASSWORD="$MYSQL_ROOT_PASSWORD" \
|
||||
-e MYSQL_DATABASE="$MYSQL_DATABASE" \
|
||||
-e MYSQL_ROOT_HOST='%' \
|
||||
-p "$MYSQL_PORT:3306" \
|
||||
-v "$(pwd)/$BACKEND_DIR/init.sql:/docker-entrypoint-initdb.d/init.sql:ro" \
|
||||
mysql:8.0 \
|
||||
--default-authentication-plugin=mysql_native_password
|
||||
|
||||
# Wait for MySQL to be ready
|
||||
info "Waiting for MySQL to be ready..."
|
||||
for i in {1..60}; do
|
||||
if docker exec "$MYSQL_CONTAINER" mysqladmin ping -h localhost -uroot -p"$MYSQL_ROOT_PASSWORD" >/dev/null 2>&1; then
|
||||
info "MySQL is ready!"
|
||||
break
|
||||
fi
|
||||
if [ "$i" -eq 60 ]; then
|
||||
fail "MySQL failed to start after 60 seconds. Check logs: docker logs $MYSQL_CONTAINER"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
|
||||
# Verify database initialization
|
||||
info "Waiting for MySQL to fully start..."
|
||||
sleep 5
|
||||
|
||||
# Wait for MySQL to accept connections (not just ping)
|
||||
for i in {1..30}; do
|
||||
if docker exec "$MYSQL_CONTAINER" mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
info "MySQL server is ready and accepting connections!"
|
||||
break
|
||||
fi
|
||||
if [ "$i" -eq 30 ]; then
|
||||
info "Warning: MySQL may not be fully ready, but continuing..."
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
info "Database '$MYSQL_DATABASE' initialization completed."
|
||||
# Now try to display tables
|
||||
info "Tables created:"
|
||||
if docker exec "$MYSQL_CONTAINER" mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" -e "SHOW TABLES;" 2>&1 | grep -v "password"; then
|
||||
info "Database tables verified successfully!"
|
||||
else
|
||||
info "Could not display tables yet. Verify manually later."
|
||||
fi
|
||||
# -------- BACKEND --------
|
||||
info "Starting backend..."
|
||||
cd "$BACKEND_DIR"
|
||||
|
||||
# Check if .env exists
|
||||
if [ ! -f ".env" ]; then
|
||||
info "Creating .env file..."
|
||||
cat > .env <<EOF
|
||||
# MySQL Configuration (Docker)
|
||||
MYSQL_HOST=localhost
|
||||
MYSQL_USER=root
|
||||
MYSQL_PASSWORD=$MYSQL_ROOT_PASSWORD
|
||||
MYSQL_DB=$MYSQL_DATABASE
|
||||
MYSQL_PORT=$MYSQL_PORT
|
||||
|
||||
# Flask Configuration
|
||||
FLASK_ENV=development
|
||||
FLASK_APP=app.py
|
||||
SECRET_KEY=your-secret-key-change-in-production
|
||||
|
||||
# Server Configuration
|
||||
PORT=5000
|
||||
HOST=0.0.0.0
|
||||
EOF
|
||||
info ".env file created"
|
||||
fi
|
||||
|
||||
# require requirements.txt
|
||||
if [ ! -f "requirements.txt" ]; then
|
||||
fail "requirements.txt not found in $BACKEND_DIR"
|
||||
fi
|
||||
|
||||
# create venv if missing
|
||||
if [ ! -d "$VENV_DIR" ]; then
|
||||
info "Creating virtualenv at $VENV_DIR"
|
||||
"$PYTHON_BIN" -m venv "$VENV_DIR"
|
||||
fi
|
||||
|
||||
# activate venv for installs
|
||||
# shellcheck source=/dev/null
|
||||
. "$VENV_DIR/bin/activate"
|
||||
|
||||
# upgrade pip in venv (non-fatal)
|
||||
info "Upgrading pip in virtualenv..."
|
||||
pip install --upgrade pip setuptools wheel >/dev/null
|
||||
|
||||
info "Installing backend Python requirements..."
|
||||
pip install -r requirements.txt
|
||||
|
||||
# default gunicorn app entrypoint: app:app (matches your original)
|
||||
APP_MODULE=${APP_MODULE:-"app:app"}
|
||||
BACKEND_CMD="gunicorn -b 0.0.0.0:5000 $APP_MODULE"
|
||||
BACKEND_PIDFILE="../backend.pid"
|
||||
start_bg "$BACKEND_CMD" "../$BACKEND_LOG" "$BACKEND_PIDFILE"
|
||||
|
||||
cd ..
|
||||
|
||||
# -------- FRONTEND --------
|
||||
info "Starting frontend..."
|
||||
cd "$FRONTEND_DIR"
|
||||
|
||||
# require package.json
|
||||
if [ ! -f "package.json" ]; then
|
||||
fail "package.json not found in $FRONTEND_DIR"
|
||||
fi
|
||||
|
||||
# Prefer npm ci when lockfile exists for reproducible installs
|
||||
if [ -f "package-lock.json" ]; then
|
||||
info "Found package-lock.json — running 'npm ci' (reproducible install)..."
|
||||
npm ci
|
||||
else
|
||||
info "Running 'npm install'..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
FRONTEND_START_CMD=${FRONTEND_START_CMD:-"npm run dev"}
|
||||
FRONTEND_PIDFILE="../frontend.pid"
|
||||
start_bg "$FRONTEND_START_CMD" "../$FRONTEND_LOG" "$FRONTEND_PIDFILE"
|
||||
|
||||
cd ..
|
||||
|
||||
# -------- FINISH --------
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "🚀 Application Started Successfully!"
|
||||
echo "========================================="
|
||||
echo "$(timestamp) MySQL (Docker) → localhost:$MYSQL_PORT"
|
||||
echo " Container: $MYSQL_CONTAINER"
|
||||
echo " Database: $MYSQL_DATABASE"
|
||||
echo " User: root"
|
||||
echo " Password: $MYSQL_ROOT_PASSWORD"
|
||||
echo ""
|
||||
echo "$(timestamp) Backend → http://localhost:5000"
|
||||
echo " Log: $BACKEND_LOG"
|
||||
echo " PID: $(cat backend.pid 2>/dev/null || echo 'N/A')"
|
||||
echo ""
|
||||
echo "$(timestamp) Frontend → http://localhost:3000"
|
||||
echo " Log: $FRONTEND_LOG"
|
||||
echo " PID: $(cat frontend.pid 2>/dev/null || echo 'N/A')"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "📝 Useful Commands:"
|
||||
echo " • View backend logs: tail -f $BACKEND_LOG"
|
||||
echo " • View frontend logs: tail -f $FRONTEND_LOG"
|
||||
echo " • View MySQL logs: docker logs -f $MYSQL_CONTAINER"
|
||||
echo " • Access MySQL: docker exec -it $MYSQL_CONTAINER mysql -uroot -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE"
|
||||
echo " • Stop services: kill \$(cat backend.pid) && kill \$(cat frontend.pid) && docker stop $MYSQL_CONTAINER"
|
||||
echo "========================================="
|
||||
Loading…
Reference in New Issue
Block a user