#!/usr/bin/env bash # ============================================================ # init.sh — Scaffold a new service from java-service-template # ============================================================ # Usage: # ./init.sh --service order-service # ./init.sh --service user-service --package com.acme # ./init.sh --service device-service --sample none # ./init.sh --service order-service --no-table-prefix # # Parameters: # --service Service name, lowercase with hyphens (required) # --package Root package (default: com.ljwx) # --sample order|none Keep sample order code or remove (default: order) # --no-table-prefix Remove "t_" prefix from table names # ============================================================ set -euo pipefail # ── macOS / Linux sed compatibility ── SED_INPLACE=(-i) if [[ "$(uname)" == "Darwin" ]]; then SED_INPLACE=(-i '') fi # ── Defaults ── SERVICE="" PACKAGE="com.ljwx" SAMPLE="order" NO_TABLE_PREFIX=false SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # ── Parse arguments ── while [[ $# -gt 0 ]]; do case "$1" in --service) SERVICE="$2"; shift 2 ;; --package) PACKAGE="$2"; shift 2 ;; --sample) SAMPLE="$2"; shift 2 ;; --no-table-prefix) NO_TABLE_PREFIX=true; shift ;; -h|--help) head -14 "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) echo "ERROR: Unknown option: $1" >&2; exit 1 ;; esac done # ── Validate ── if [[ -z "$SERVICE" ]]; then echo "ERROR: --service is required." >&2; exit 1 fi if [[ ! "$SERVICE" =~ ^[a-z][a-z0-9-]*$ ]]; then echo "ERROR: --service must be lowercase alphanumeric with hyphens." >&2; exit 1 fi if [[ "$SAMPLE" != "order" && "$SAMPLE" != "none" ]]; then echo "ERROR: --sample must be 'order' or 'none'." >&2; exit 1 fi # ── Derived values ── # For Java package: "order-service" → "order_service" SERVICE_PKG="${SERVICE//-/_}" # For PascalCase: "order-service" → "OrderService" SERVICE_PASCAL="$(echo "$SERVICE" | sed -E 's/(^|-)([a-z])/\U\2/g')" # Package paths PACKAGE_PATH="${PACKAGE//./\/}" OLD_PKG_FULL="com.ljwx.tmpl" OLD_PKG_PATH="com/ljwx/tmpl" NEW_PKG_FULL="${PACKAGE}.${SERVICE_PKG}" NEW_PKG_PATH="${PACKAGE_PATH}/${SERVICE_PKG}" # Old / new identifiers OLD_PREFIX="tmpl" OLD_APP_CLASS="TmplApplication" NEW_APP_CLASS="${SERVICE_PASCAL}Application" OLD_GROUP_ID="com.ljwx.tmpl" NEW_GROUP_ID="${PACKAGE}.${SERVICE_PKG}" echo "============================================================" echo " Service: ${SERVICE}" echo " Package: ${NEW_PKG_FULL}" echo " GroupId: ${NEW_GROUP_ID}" echo " Sample: ${SAMPLE}" echo " Table prefix: $(${NO_TABLE_PREFIX} && echo 'none' || echo 't_')" echo "============================================================" echo "" # ── Step 1: Rename module directories (keep hyphens in dir names) ── echo "[1/7] Renaming module directories..." for MODULE in domain application infrastructure api; do OLD_DIR="${SCRIPT_DIR}/${OLD_PREFIX}-${MODULE}" NEW_DIR="${SCRIPT_DIR}/${SERVICE}-${MODULE}" if [[ -d "$OLD_DIR" ]]; then mv "$OLD_DIR" "$NEW_DIR" echo " ${OLD_PREFIX}-${MODULE} → ${SERVICE}-${MODULE}" fi done # ── Step 2: Rename Java package directories ── echo "[2/7] Renaming Java package directories..." # Process deepest paths first (sort -r) to avoid mv conflicts find "${SCRIPT_DIR}" -type d -path "*/${OLD_PKG_PATH}" | sort -r | while read -r DIR; do PARENT="$(dirname "$(dirname "$(dirname "$DIR")")")" RELATIVE="${DIR#"${PARENT}/"}" NEW_REL="${RELATIVE/${OLD_PKG_PATH}/${NEW_PKG_PATH}}" TARGET="${PARENT}/${NEW_REL}" mkdir -p "$(dirname "$TARGET")" mv "$DIR" "$TARGET" done # Clean up empty directories left behind find "${SCRIPT_DIR}" -type d -empty -delete 2>/dev/null || true # ── Step 3: Update POM files ── echo "[3/7] Updating POM files..." find "${SCRIPT_DIR}" -name "pom.xml" -exec sed "${SED_INPLACE[@]}" \ -e "s|${OLD_GROUP_ID}|${NEW_GROUP_ID}|g" \ -e "s|java-service-template|${SERVICE}|g" \ -e "s|${OLD_PREFIX}-|${SERVICE}-|g" \ -e "s|${OLD_PREFIX}-|${SERVICE}-|g" \ {} + # ── Step 4: Update Java source (package declarations, imports, class refs) ── echo "[4/7] Updating Java source files..." find "${SCRIPT_DIR}" -type f \( -name "*.java" -o -name "*.xml" -o -name "*.yml" \ -o -name "*.yaml" -o -name "*.properties" \) \ -exec sed "${SED_INPLACE[@]}" \ -e "s|${OLD_PKG_FULL}|${NEW_PKG_FULL}|g" \ -e "s|${OLD_APP_CLASS}|${NEW_APP_CLASS}|g" \ {} + # Rename main application class file find "${SCRIPT_DIR}" -name "${OLD_APP_CLASS}.java" | while read -r FILE; do mv "$FILE" "$(dirname "$FILE")/${NEW_APP_CLASS}.java" echo " Renamed ${OLD_APP_CLASS}.java → ${NEW_APP_CLASS}.java" done # ── Step 5: Update config files ── echo "[5/7] Updating configuration files..." find "${SCRIPT_DIR}" -type f \( -name "*.yml" -o -name "*.yaml" \ -o -name "*.properties" -o -name "docker-compose.yml" \) \ -exec sed "${SED_INPLACE[@]}" \ -e "s|java-service-template|${SERVICE}|g" \ -e "s|tmpl_db|${SERVICE_PKG}_db|g" \ -e "s|tmpl_test|${SERVICE_PKG}_test|g" \ -e "s|tmpl-postgres|${SERVICE}-postgres|g" \ -e "s|tmpl-redis|${SERVICE}-redis|g" \ {} + # Update Dockerfile image references if [[ -f "${SCRIPT_DIR}/Dockerfile" ]]; then sed "${SED_INPLACE[@]}" \ -e "s|${OLD_PREFIX}-api|${SERVICE}-api|g" \ "${SCRIPT_DIR}/Dockerfile" fi # ── Step 6: Handle --sample ── if [[ "$SAMPLE" == "none" ]]; then echo "[6/7] Removing sample order code..." find "${SCRIPT_DIR}" -type f -path "*/order/*" -delete 2>/dev/null || true find "${SCRIPT_DIR}" -type d -name "order" -exec rmdir {} + 2>/dev/null || true find "${SCRIPT_DIR}" -name "V2__*" -delete 2>/dev/null || true echo " Removed order domain model, persistence adapter, and V2 migration." else echo "[6/7] Keeping sample order code." fi # ── Step 7: Handle --no-table-prefix ── if ${NO_TABLE_PREFIX}; then echo "[7/7] Removing table prefix 't_'..." find "${SCRIPT_DIR}" -type f \( -name "*.sql" -o -name "*.java" \) \ -exec sed "${SED_INPLACE[@]}" \ -e 's/t_order/order/g' \ -e 's/t_app_meta/app_meta/g' \ {} + echo " Replaced t_order → order, t_app_meta → app_meta." else echo "[7/7] Table prefix 't_' unchanged." fi # ── Done ── echo "" echo "============================================================" echo " Done! Project scaffolded as: ${SERVICE}" echo "" echo " Next steps:" echo " cd $(basename "${SCRIPT_DIR}")" echo " docker compose up -d" echo " mvn clean test" echo " mvn spring-boot:run -pl ${SERVICE}-api \\" echo " -Dspring-boot.run.profiles=dev" echo "============================================================"