#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" . "$ROOT_DIR/scripts/lib.sh" load_env if [ ! -f "$ROOT_DIR/.env" ]; then cp "$ROOT_DIR/.env.example" "$ROOT_DIR/.env" fi ensure_secret_file load_env PROFILE="${COMPOSE_PROFILES:-base}" OFFLINE_BUNDLE="" SKIP_LOGIN=false usage() { cat <<'EOF' Usage: ./scripts/install.sh [options] Options: --profile Docker Compose profiles, for example: base,im,push,update,license --mysql-mode external or managed --redis-mode external or managed --offline-bundle Load images from an offline bundle before deployment --skip-registry-login Skip docker login (use when already logged in or in offline mode) -h, --help Show help EOF } while [ "$#" -gt 0 ]; do case "$1" in --skip-registry-login) SKIP_LOGIN=true shift ;; --profile) PROFILE="${2:-}" shift 2 ;; --profile=*) PROFILE="${1#--profile=}" shift ;; --mysql-mode) MYSQL_MODE="${2:-}" set_env_value "$ROOT_DIR/.env" "MYSQL_MODE" "$MYSQL_MODE" set_env_value "$ROOT_DIR/config/infra.env" "MYSQL_MODE" "$MYSQL_MODE" shift 2 ;; --mysql-mode=*) MYSQL_MODE="${1#--mysql-mode=}" set_env_value "$ROOT_DIR/.env" "MYSQL_MODE" "$MYSQL_MODE" set_env_value "$ROOT_DIR/config/infra.env" "MYSQL_MODE" "$MYSQL_MODE" shift ;; --redis-mode) REDIS_MODE="${2:-}" set_env_value "$ROOT_DIR/.env" "REDIS_MODE" "$REDIS_MODE" set_env_value "$ROOT_DIR/config/infra.env" "REDIS_MODE" "$REDIS_MODE" shift 2 ;; --redis-mode=*) REDIS_MODE="${1#--redis-mode=}" set_env_value "$ROOT_DIR/.env" "REDIS_MODE" "$REDIS_MODE" set_env_value "$ROOT_DIR/config/infra.env" "REDIS_MODE" "$REDIS_MODE" shift ;; --offline-bundle) OFFLINE_BUNDLE="${2:-}" shift 2 ;; --offline-bundle=*) OFFLINE_BUNDLE="${1#--offline-bundle=}" shift ;; -h|--help) usage exit 0 ;; *) fail_json "XUQM_PRIVATE_4002" "unknown install option: $1" "install" ;; esac done [ -n "$PROFILE" ] || fail_json "XUQM_PRIVATE_4003" "profile cannot be empty" "install" set_env_value "$ROOT_DIR/.env" "COMPOSE_PROFILES" "$PROFILE" audit "install" "STARTED" "profile=$PROFILE" progress "install" "STARTED" "profile=$PROFILE" require_cmd docker if [ -n "$OFFLINE_BUNDLE" ]; then [ -f "$OFFLINE_BUNDLE" ] || fail_json "XUQM_PRIVATE_4004" "offline bundle not found: $OFFLINE_BUNDLE" "install" docker load -i "$OFFLINE_BUNDLE" SKIP_LOGIN=true fi # Login to image registry (skip for offline bundles or when already authenticated) if [ "$SKIP_LOGIN" = "false" ] && [ -n "${REGISTRY:-}" ]; then REGISTRY_HOST="$(printf '%s' "$REGISTRY" | cut -d/ -f1)" REGISTRY_USER="${REGISTRY_USER:-}" REGISTRY_PASSWORD="${REGISTRY_PASSWORD:-}" if [ -n "$REGISTRY_USER" ] && [ -n "$REGISTRY_PASSWORD" ]; then printf '%s' "$REGISTRY_PASSWORD" | \ docker login "$REGISTRY_HOST" -u "$REGISTRY_USER" --password-stdin \ || fail_json "XUQM_PRIVATE_4005" "docker login failed for $REGISTRY_HOST" "install" audit "install" "REGISTRY_LOGIN_OK" "host=$REGISTRY_HOST" else audit "install" "REGISTRY_LOGIN_SKIPPED" "REGISTRY_USER/REGISTRY_PASSWORD not set; assuming pre-authenticated" fi fi if [ "${MYSQL_MODE:-external}" = "managed" ]; then "$ROOT_DIR/scripts/install-mysql.sh" fi if [ "${REDIS_MODE:-external}" = "managed" ]; then "$ROOT_DIR/scripts/install-redis.sh" fi "$ROOT_DIR/scripts/render-config.sh" COMPOSE_PROFILES="$PROFILE" compose up -d "$ROOT_DIR/scripts/healthcheck.sh" audit "install" "DONE" "profile=$PROFILE" progress "install" "DONE" "profile=$PROFILE"