#!/usr/bin/env bash set -Eeuo pipefail # Build all images locally, export them, and create a server runtime package. # Supports both layouts: # 1. monorepo: emp/deploy/isolated/build-package.sh # 2. split deploy: emp_test_deploy/isolated/build-package.sh with EMP_ROOT=/path/to/emp SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DIST_DIR="$SCRIPT_DIR/dist" BUILD_CONTEXT_DIR="$SCRIPT_DIR/.build-context" IMAGE_NAMESPACE="${IMAGE_NAMESPACE:-emp-test}" IMAGE_TAG="${IMAGE_TAG:-$(date '+%Y%m%d%H%M%S')}" PACKAGE_NAME="${PACKAGE_NAME:-emp-test-runtime-${IMAGE_TAG}}" PACKAGE_DIR="$DIST_DIR/$PACKAGE_NAME" PACKAGE_ARCHIVE="$DIST_DIR/${PACKAGE_NAME}.tar.gz" NPM_REGISTRY="${NPM_REGISTRY:-https://registry.npmjs.org}" SKIP_BUILD="${SKIP_BUILD:-0}" INCLUDE_MIDDLEWARE_IMAGES="${INCLUDE_MIDDLEWARE_IMAGES:-1}" JAVA_MODULES=(emp_gateway emp_auth emp_monitor emp_data) APP_IMAGES=( "$IMAGE_NAMESPACE/emp-gateway:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-gateway:latest" "$IMAGE_NAMESPACE/emp-auth:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-auth:latest" "$IMAGE_NAMESPACE/emp-monitor:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-monitor:latest" "$IMAGE_NAMESPACE/emp-data:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-data:latest" "$IMAGE_NAMESPACE/emp-pdf:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-pdf:latest" "$IMAGE_NAMESPACE/emp-ws:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-ws:latest" "$IMAGE_NAMESPACE/emp-admin:$IMAGE_TAG" "$IMAGE_NAMESPACE/emp-admin:latest" ) MIDDLEWARE_IMAGES=( "${MYSQL_IMAGE:-mysql:8.0}" "${REDIS_IMAGE:-redis:7-alpine}" "${KAFKA_IMAGE:-bitnami/kafka:3.7.0}" "${TDENGINE_IMAGE:-tdengine/tdengine:3.3.6.0}" "${NACOS_IMAGE:-nacos/nacos-server:v2.3.2-slim}" ) log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" } die() { echo "ERROR: $*" >&2 exit 1 } need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing command: $1" } has_emp_root() { [[ -d "$1/emp_server" && -d "$1/emp_admin" && -d "$1/emp_ws" ]] } resolve_root_dir() { if [[ -n "${EMP_ROOT:-}" ]]; then local root root="$(cd "$EMP_ROOT" && pwd)" has_emp_root "$root" || die "EMP_ROOT is invalid: $EMP_ROOT" printf '%s\n' "$root" return fi local candidates=( "$SCRIPT_DIR/../.." "$SCRIPT_DIR/../../emp" "$SCRIPT_DIR/.." "$PWD" ) local candidate root for candidate in "${candidates[@]}"; do if [[ -d "$candidate" ]]; then root="$(cd "$candidate" && pwd)" if has_emp_root "$root"; then printf '%s\n' "$root" return fi fi done die "Cannot find EMP root. Set EMP_ROOT=/path/to/emp where emp_server, emp_admin and emp_ws exist." } ROOT_DIR="$(resolve_root_dir)" build_java_images() { cd "$ROOT_DIR/emp_server" log "Build backend jars" mvn package -DskipTests -B -pl "$(IFS=,; echo "${JAVA_MODULES[*]}")" -am for module in "${JAVA_MODULES[@]}"; do local jar jar="$(ls "$module"/target/*.jar | grep -v original | grep -v app.jar | head -1)" [[ -n "$jar" ]] || die "Jar not found for $module" cp "$jar" "$module/target/app.jar" done log "Build backend images" docker build -f Dockerfile.service --build-arg MODULE=emp_gateway -t "$IMAGE_NAMESPACE/emp-gateway:$IMAGE_TAG" -t "$IMAGE_NAMESPACE/emp-gateway:latest" . docker build -f Dockerfile.service --build-arg MODULE=emp_auth -t "$IMAGE_NAMESPACE/emp-auth:$IMAGE_TAG" -t "$IMAGE_NAMESPACE/emp-auth:latest" . docker build -f Dockerfile.service --build-arg MODULE=emp_monitor -t "$IMAGE_NAMESPACE/emp-monitor:$IMAGE_TAG" -t "$IMAGE_NAMESPACE/emp-monitor:latest" . docker build -f Dockerfile.service --build-arg MODULE=emp_data -t "$IMAGE_NAMESPACE/emp-data:$IMAGE_TAG" -t "$IMAGE_NAMESPACE/emp-data:latest" . log "Build PDF image" docker build -f emp_pdf/Dockerfile -t "$IMAGE_NAMESPACE/emp-pdf:$IMAGE_TAG" -t "$IMAGE_NAMESPACE/emp-pdf:latest" emp_pdf } build_ws_image() { cd "$ROOT_DIR" log "Build WS/simulator image" docker build \ -f "$SCRIPT_DIR/dockerfiles/emp-ws.Dockerfile" \ --build-arg "NPM_REGISTRY=$NPM_REGISTRY" \ -t "$IMAGE_NAMESPACE/emp-ws:$IMAGE_TAG" \ -t "$IMAGE_NAMESPACE/emp-ws:latest" \ . } build_admin_image() { cd "$ROOT_DIR/emp_admin" log "Build frontend dist" pnpm install --frozen-lockfile pnpm run build:shunfeng log "Prepare frontend image context" rm -rf "$BUILD_CONTEXT_DIR/emp-admin" mkdir -p "$BUILD_CONTEXT_DIR/emp-admin" cp -R "$ROOT_DIR/emp_admin/dist" "$BUILD_CONTEXT_DIR/emp-admin/dist" cp "$SCRIPT_DIR/nginx/admin.conf" "$BUILD_CONTEXT_DIR/emp-admin/admin.conf" log "Build frontend image" docker build \ -f "$SCRIPT_DIR/dockerfiles/emp-admin.Dockerfile" \ -t "$IMAGE_NAMESPACE/emp-admin:$IMAGE_TAG" \ -t "$IMAGE_NAMESPACE/emp-admin:latest" \ "$BUILD_CONTEXT_DIR/emp-admin" } prepare_package() { rm -rf "$PACKAGE_DIR" mkdir -p "$PACKAGE_DIR" local compose_src="$SCRIPT_DIR/docker-compose.runtime.yml" local env_src="$SCRIPT_DIR/.env.example" if [[ -f "$SCRIPT_DIR/test/docker-compose.yml" ]]; then compose_src="$SCRIPT_DIR/test/docker-compose.yml" fi if [[ -f "$SCRIPT_DIR/test/env.txt" ]]; then env_src="$SCRIPT_DIR/test/env.txt" fi cp "$compose_src" "$PACKAGE_DIR/docker-compose.yml" cp "$env_src" "$PACKAGE_DIR/.env.example" cp "$SCRIPT_DIR/install.sh" "$PACKAGE_DIR/install.sh" cp "$SCRIPT_DIR/README.md" "$PACKAGE_DIR/README.md" chmod +x "$PACKAGE_DIR/install.sh" } save_images() { local images=("${APP_IMAGES[@]}") if [[ "$INCLUDE_MIDDLEWARE_IMAGES" == "1" ]]; then log "Pull middleware images" for image in "${MIDDLEWARE_IMAGES[@]}"; do docker pull "$image" images+=("$image") done fi log "Save images" docker save -o "$PACKAGE_DIR/images.tar" "${images[@]}" } archive_package() { mkdir -p "$DIST_DIR" rm -f "$PACKAGE_ARCHIVE" tar -czf "$PACKAGE_ARCHIVE" -C "$DIST_DIR" "$PACKAGE_NAME" log "Package created: $PACKAGE_ARCHIVE" } need_cmd docker need_cmd tar log "EMP root: $ROOT_DIR" log "Deploy root: $SCRIPT_DIR" if [[ "$SKIP_BUILD" != "1" ]]; then need_cmd mvn need_cmd pnpm build_java_images build_ws_image build_admin_image else log "Skip build, package existing local images only" fi prepare_package save_images archive_package