#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" COMPOSE_FILE="${COMPOSE_FILE:-$ROOT_DIR/docker-compose.demo.yml}" POSTGRES_CONTAINER_NAME="${POSTGRES_CONTAINER_NAME:-dbtool-cli-v1-postgres-1}" MYSQL_CONTAINER_NAME="${MYSQL_CONTAINER_NAME:-dbtool-cli-v1-mysql-1}" DEMO_NETWORK_NAME="${DEMO_NETWORK_NAME:-dbtool-cli-v1_default}" usage() { echo "usage: scripts/tui/demo-stack.sh " >&2 exit 2 } docker_compose_available() { docker compose version >/dev/null 2>&1 } container_exists() { local container_name="$1" docker container inspect "$container_name" >/dev/null 2>&1 } container_running() { local container_name="$1" [ "$(docker inspect -f '{{.State.Running}}' "$container_name" 2>/dev/null || true)" = "true" ] } ensure_network() { if ! docker network inspect "$DEMO_NETWORK_NAME" >/dev/null 2>&1; then docker network create "$DEMO_NETWORK_NAME" >/dev/null fi } wait_for_health() { local container_name="$1" local max_attempts="${2:-60}" local attempt=1 while [ "$attempt" -le "$max_attempts" ]; do local health health="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}running{{end}}' "$container_name" 2>/dev/null || true)" if [ "$health" = "healthy" ] || [ "$health" = "running" ]; then return 0 fi sleep 2 attempt=$((attempt + 1)) done echo "error: container did not become healthy: $container_name" >&2 docker logs --tail 50 "$container_name" >&2 || true exit 1 } run_postgres_container() { if container_exists "$POSTGRES_CONTAINER_NAME"; then if ! container_running "$POSTGRES_CONTAINER_NAME"; then docker start "$POSTGRES_CONTAINER_NAME" >/dev/null fi return fi ensure_network docker run -d \ --name "$POSTGRES_CONTAINER_NAME" \ --network "$DEMO_NETWORK_NAME" \ -p 55432:5432 \ -e POSTGRES_DB=dbtool_demo \ -e POSTGRES_USER=dbtool \ -e POSTGRES_PASSWORD=dbtool \ --health-cmd 'pg_isready -U dbtool -d dbtool_demo' \ --health-interval 5s \ --health-timeout 5s \ --health-retries 20 \ postgres:16 >/dev/null } run_mysql_container() { if container_exists "$MYSQL_CONTAINER_NAME"; then if ! container_running "$MYSQL_CONTAINER_NAME"; then docker start "$MYSQL_CONTAINER_NAME" >/dev/null fi return fi ensure_network docker run -d \ --name "$MYSQL_CONTAINER_NAME" \ --network "$DEMO_NETWORK_NAME" \ -p 53306:3306 \ -e MYSQL_DATABASE=dbtool_demo \ -e MYSQL_USER=dbtool \ -e MYSQL_PASSWORD=dbtool \ -e MYSQL_ROOT_PASSWORD=dbtoolroot \ --health-cmd 'mysqladmin ping -uroot -pdbtoolroot' \ --health-interval 5s \ --health-timeout 5s \ --health-retries 30 \ mysql:8.4 \ mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci >/dev/null } up_stack() { if docker_compose_available; then docker compose -f "$COMPOSE_FILE" up -d postgres mysql else run_postgres_container run_mysql_container fi wait_for_health "$POSTGRES_CONTAINER_NAME" wait_for_health "$MYSQL_CONTAINER_NAME" echo "Demo stack is ready." } down_stack() { if docker_compose_available; then docker compose -f "$COMPOSE_FILE" down -v return fi docker rm -f "$POSTGRES_CONTAINER_NAME" "$MYSQL_CONTAINER_NAME" >/dev/null 2>&1 || true } seed_stack() { "$ROOT_DIR/examples/scripts/bootstrap-postgres.sh" "$ROOT_DIR/examples/scripts/bootstrap-mysql.sh" } status_stack() { docker ps --filter "name=$POSTGRES_CONTAINER_NAME" --filter "name=$MYSQL_CONTAINER_NAME" \ --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' } command="${1:-}" case "$command" in up) up_stack ;; down) down_stack ;; seed) seed_stack ;; reset) down_stack up_stack seed_stack ;; status) status_stack ;; *) usage ;; esac