#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "$script_dir/../.." && pwd)" env_file="$script_dir/.env" env_example_file="$script_dir/.env.example" docker_contexts_dir="$script_dir/build/local-docker-contexts" service_names=( spring-cloud-config-server pcp-srpring-boot-admin-server pcp-satellite-catalog-service pcp-ballistics-service pcp-request-service pcp-route-processing-service slots-service pcp-complex-mission-service pcp-mission-planing-service pcp-coverage-scheme-service pcp-dynamic-plan-service pcp-stations-service pcp-ui-service pcp-tgu-service ) ensure_env_file() { if [[ ! -f "$env_file" && -f "$env_example_file" ]]; then cp "$env_example_file" "$env_file" echo "Created $env_file from .env.example" fi } ensure_source_config_repo_dir() { if grep -q '^CONFIG_REPO_DIR=' "$env_file"; then sed -i "s#^CONFIG_REPO_DIR=.*#CONFIG_REPO_DIR=$repo_root/config-repo#" "$env_file" else printf '\nCONFIG_REPO_DIR=%s/config-repo\n' "$repo_root" >> "$env_file" fi } load_env() { set -a # shellcheck disable=SC1090 source "$env_file" set +a } require_command() { local command_name="$1" if ! command -v "$command_name" >/dev/null 2>&1; then echo "$command_name is required." >&2 exit 1 fi } compose() { if docker compose version >/dev/null 2>&1; then docker compose --project-directory "$script_dir" -f "$script_dir/docker-compose.yml" "$@" elif command -v docker-compose >/dev/null 2>&1; then docker-compose --project-directory "$script_dir" -f "$script_dir/docker-compose.yml" "$@" else echo "docker compose or docker-compose is required." >&2 exit 1 fi } copy_single_boot_jar() { local service_name="$1" local context_dir="$2" local jar_count local jar_file jar_count="$( find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | wc -l )" if [[ "$jar_count" != "1" ]]; then echo "Expected exactly one bootJar for $service_name, found $jar_count:" >&2 find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' -print >&2 || true exit 1 fi jar_file="$( find "$repo_root/services/$service_name/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | head -n 1 )" mkdir -p "$context_dir/build/libs" cp "$repo_root/services/$service_name/Dockerfile" "$context_dir/Dockerfile" cp "$jar_file" "$context_dir/build/libs/app.jar" } build_images() { local gradle_max_workers="${GRADLE_MAX_WORKERS:-1}" local gradle_jvmargs="${GRADLE_JVMARGS:--Xmx2g -Dfile.encoding=UTF-8}" local kotlin_daemon_jvmargs="${KOTLIN_DAEMON_JVMARGS:--Xmx3g -XX:MaxMetaspaceSize=768m}" local gradle_offline="${GRADLE_OFFLINE:-true}" local runtime_image="${LOCAL_BUNDLE_RUNTIME_IMAGE:-bellsoft/liberica-openjre-alpine:21.0.5}" local image_tag="${PCP_IMAGE_TAG:-local}" local service_name local image_name local context_dir local gradle_common_args=( "--no-parallel" "--max-workers=$gradle_max_workers" "-Dorg.gradle.jvmargs=$gradle_jvmargs" "-Pkotlin.daemon.jvmargs=$kotlin_daemon_jvmargs" ) if [[ "$gradle_offline" == "true" ]]; then gradle_common_args+=("--offline") fi echo "Building local Docker images..." echo "Gradle offline mode: $gradle_offline" echo "Local image tag: $image_tag" echo "Runtime image: $runtime_image" for service_name in "${service_names[@]}"; do echo "Building bootJar for $service_name..." "$repo_root/gradlew" --project-dir "$repo_root" "${gradle_common_args[@]}" ":services:$service_name:bootJar" done rm -rf "$docker_contexts_dir" mkdir -p "$docker_contexts_dir" for service_name in "${service_names[@]}"; do image_name="pcp/$service_name:$image_tag" context_dir="$docker_contexts_dir/$service_name" copy_single_boot_jar "$service_name" "$context_dir" echo "Building Docker image $image_name..." docker build \ --build-arg "RUNTIME_IMAGE=$runtime_image" \ --file "$context_dir/Dockerfile" \ --tag "$image_name" \ "$context_dir" done } usage() { cat <<'EOF' Usage: ./deploy/local-bundle/run-local.sh [command] Commands: start Build service images locally and start docker compose. restart Stop compose stack, then build and start. build Build service images locally, without starting compose. stop Stop compose stack. status Show compose status. logs Follow compose logs. EOF } start_local() { build_images "$script_dir/scripts/start.sh" } command="${1:-start}" case "$command" in help|-h|--help) usage exit 0 ;; esac ensure_env_file ensure_source_config_repo_dir load_env require_command docker case "$command" in start) start_local ;; restart) "$script_dir/scripts/stop.sh" start_local ;; build) build_images ;; stop) "$script_dir/scripts/stop.sh" ;; status) "$script_dir/scripts/status.sh" ;; logs) compose logs -f ;; *) usage >&2 exit 1 ;; esac