#!/usr/bin/env bash set -Eeuo pipefail readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" readonly WORKSPACE_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" readonly MODULE_ROOT="${WORKSPACE_ROOT}/module" readonly BUILD_ROOT="${WORKSPACE_ROOT}/.builds" readonly ENTRY_ROOT="${BUILD_ROOT}/.entries" readonly CONFIG_ROOT="${BUILD_ROOT}/etc" if ! command -v go >/dev/null 2>&1; then echo "error: Go is not installed or is not available in PATH" >&2 exit 1 fi if [[ ! -f "${WORKSPACE_ROOT}/go.work" ]]; then echo "error: go.work was not found in ${WORKSPACE_ROOT}" >&2 exit 1 fi export GOWORK="${WORKSPACE_ROOT}/go.work" export GOOS=linux export GOARCH=amd64 export CGO_ENABLED=0 modules=() while IFS= read -r -d '' go_mod; do modules+=("$(dirname -- "${go_mod}")") done < <(find "${MODULE_ROOT}" -type f -name go.mod -print0 | sort -z) if (( ${#modules[@]} == 0 )); then echo "error: no service modules were found under ${MODULE_ROOT}" >&2 exit 1 fi mkdir -p "${BUILD_ROOT}" mkdir -p "${ENTRY_ROOT}" cleanup() { rm -rf -- "${ENTRY_ROOT}" } trap cleanup EXIT echo "Building ${#modules[@]} service modules..." for module_dir in "${modules[@]}"; do relative_path="${module_dir#"${MODULE_ROOT}/"}" artifact_name="${relative_path//\//-}" output="${BUILD_ROOT}/${artifact_name}" if [[ -f "${module_dir}/cmd/main/main.go" ]]; then entry_file="${module_dir}/cmd/main/main.go" entry_package="./cmd/main" elif [[ -f "${module_dir}/cmd/main.go" ]]; then entry_file="${module_dir}/cmd/main.go" entry_package="./cmd" else echo "error: service entry not found under ${module_dir}/cmd" >&2 exit 1 fi mkdir -p "$(dirname -- "${output}")" echo "==> ${relative_path} -> ${output#"${WORKSPACE_ROOT}/"}" ( cd -- "${module_dir}" package_name="$(awk '$1 == "package" { print $2; exit }' "${entry_file}")" if [[ "${package_name}" == "main" ]]; then go build -trimpath -o "${output}" "${entry_package}" else module_name="$(awk '$1 == "module" { print $2; exit }' go.mod)" module_name="${module_name//$'\r'/}" wrapper_dir="${ENTRY_ROOT}/${relative_path}" wrapper_file="${wrapper_dir}/main.go" mkdir -p "${wrapper_dir}" printf '%s\n' \ 'package main' \ '' \ "import service \"${module_name}/${entry_package#./}\"" \ '' \ 'func main() {' \ $'\tservice.Run()' \ '}' >"${wrapper_file}" go build -trimpath -o "${output}" "${wrapper_file}" fi ) done # Copy production configuration only after every service has compiled successfully. mkdir -p "${CONFIG_ROOT}" config_count=0 for module_dir in "${modules[@]}"; do module_name="$(basename -- "${module_dir}")" config_name="${module_name}_prod.yaml" config_file="${module_dir}/etc/${config_name}" [[ -f "${config_file}" ]] || continue cp -- "${config_file}" "${CONFIG_ROOT}/${config_name}" ((config_count += 1)) done echo "Copied ${config_count} production configs to ${CONFIG_ROOT}" echo "Build completed successfully: ${BUILD_ROOT}"