Files
common-scripts/deploy/springboot/generator.sh

389 lines
12 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
###############################################################################
# Spring Boot 部署脚本生成器(交互式)
#
# 功能说明:
# 1. 交互式采集部署参数,提供默认值和选择项
# 2. 汇总展示参数,支持按编号二次修改
# 3. 用户确认后,以 deploy.sh 为模板生成 deploy-xxx.sh
# 4. 生成脚本中的参数会被固化为本次采集结果
###############################################################################
set -u
BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
TEMPLATE_FILE="${BASE_DIR}/deploy.sh"
COLOR_RESET="\033[0m"
COLOR_INFO="\033[1;34m"
COLOR_WARN="\033[1;33m"
COLOR_ERROR="\033[1;31m"
COLOR_SUCCESS="\033[1;32m"
log_info() {
echo -e "${COLOR_INFO}[INFO]${COLOR_RESET} $*"
}
log_warn() {
echo -e "${COLOR_WARN}[WARN]${COLOR_RESET} $*"
}
log_error() {
echo -e "${COLOR_ERROR}[ERROR]${COLOR_RESET} $*"
}
log_success() {
echo -e "${COLOR_SUCCESS}[SUCCESS]${COLOR_RESET} $*"
}
usage() {
cat <<EOF
用法:
$(basename "$0")
说明:
该脚本会基于同目录 deploy.sh 模板,交互式生成 deploy-xxx.sh。
EOF
}
# 读取用户输入,支持默认值
ask_input() {
local prompt="$1"
local default_value="${2:-}"
local input
if [[ -n "${default_value}" ]]; then
read -r -p "${prompt} [默认: ${default_value}]: " input
if [[ -z "${input}" ]]; then
input="${default_value}"
fi
else
read -r -p "${prompt}: " input
fi
echo "${input}"
}
# 选择输入(数字菜单)
ask_choice() {
local title="$1"
local default_index="$2"
shift 2
local options=("$@")
local i
echo >&2
echo "${title}" >&2
for i in "${!options[@]}"; do
printf " %d) %s\n" "$((i + 1))" "${options[$i]}" >&2
done
local selected
while true; do
read -r -p "请输入选项序号 [默认: ${default_index}]: " selected
if [[ -z "${selected}" ]]; then
selected="${default_index}"
fi
if [[ "${selected}" =~ ^[0-9]+$ ]] && (( selected >= 1 && selected <= ${#options[@]} )); then
echo "${options[$((selected - 1))]}"
return 0
fi
echo "输入无效,请输入 1-${#options[@]} 的数字。" >&2
done
}
# 是否确认y/n
ask_confirm() {
local prompt="$1"
local default_yes="${2:-y}"
local input
while true; do
if [[ "${default_yes}" == "y" ]]; then
read -r -p "${prompt} [Y/n]: " input
input="${input:-y}"
else
read -r -p "${prompt} [y/N]: " input
input="${input:-n}"
fi
case "${input}" in
y|Y) return 0 ;;
n|N) return 1 ;;
*) log_warn "请输入 y 或 n。" ;;
esac
done
}
# 转义用于 sed 替换的值
escape_sed_replacement() {
echo "$1" | sed -e 's/[\\&|]/\\&/g'
}
# 替换形如 VAR="..." 的变量定义行
replace_var_in_file() {
local file="$1"
local var_name="$2"
local var_value="$3"
local escaped
escaped="$(escape_sed_replacement "${var_value}")"
sed -i "s|^${var_name}=.*$|${var_name}=\"${escaped}\"|" "${file}"
}
# 展示当前采集到的配置
print_config_summary() {
echo
echo "================ 已采集参数(可二次修改) ================"
echo " 1) 应用标识(APP_KEY) : ${APP_KEY}"
echo " 2) 目标脚本路径(TARGET) : ${TARGET_SCRIPT}"
echo " 3) JDK_HOME : ${JDK_HOME}"
echo " 4) APP_HOME : ${APP_HOME}"
echo " 5) LOG_DIR : ${LOG_DIR}"
echo " 6) CONFIG_DIR : ${CONFIG_DIR}"
echo " 7) JAR_NAME : ${JAR_NAME:-<自动发现>}"
echo " 8) SPRING_PROFILE : ${SPRING_PROFILE}"
echo " 9) JVM_OPTS : ${JVM_OPTS}"
echo " 10) JAVA_SYS_PROPS : ${JAVA_SYS_PROPS}"
echo " 11) DEBUG_ENABLED : ${DEBUG_ENABLED}"
echo " 12) DEBUG_PORT : ${DEBUG_PORT}"
echo " 13) DEBUG_SUSPEND : ${DEBUG_SUSPEND}"
echo " 14) DEBUG_ADDRESS : ${DEBUG_ADDRESS}"
echo " 15) STOP_TIMEOUT : ${STOP_TIMEOUT}"
echo " 16) START_WAIT : ${START_WAIT}"
echo " 17) SPRING_EXTRA_ARGS : ${SPRING_EXTRA_ARGS}"
echo "=========================================================="
}
modify_one_field() {
local idx="$1"
case "${idx}" in
1)
APP_KEY="$(ask_input "请输入应用标识(仅用于脚本命名,如 order、pay" "${APP_KEY}")"
APP_KEY="$(echo "${APP_KEY}" | tr ' ' '-' | tr -cd '[:alnum:]_-')"
if [[ -z "${APP_KEY}" ]]; then
APP_KEY="app"
fi
TARGET_SCRIPT="${BASE_DIR}/deploy-${APP_KEY}.sh"
;;
2)
TARGET_SCRIPT="$(ask_input "请输入目标脚本完整路径" "${TARGET_SCRIPT}")"
;;
3)
JDK_HOME="$(ask_input "请输入 JDK_HOME" "${JDK_HOME}")"
;;
4)
APP_HOME="$(ask_input "请输入 APP_HOMEJar 运行目录)" "${APP_HOME}")"
;;
5)
LOG_DIR="$(ask_input "请输入 LOG_DIR日志目录" "${LOG_DIR}")"
;;
6)
CONFIG_DIR="$(ask_input "请输入 CONFIG_DIR外置配置目录" "${CONFIG_DIR}")"
;;
7)
local jar_mode
jar_mode="$(ask_choice "请选择 Jar 名称模式" "1" "自动发现JAR_NAME 留空)" "手动指定 Jar 名称")"
if [[ "${jar_mode}" == "自动发现JAR_NAME 留空)" ]]; then
JAR_NAME=""
else
JAR_NAME="$(ask_input "请输入 Jar 名称(如 demo.jar" "${JAR_NAME}")"
fi
;;
8)
local profile_choice
profile_choice="$(ask_choice "请选择 Spring Profile" "4" "dev" "test" "stage" "prod" "custom")"
if [[ "${profile_choice}" == "custom" ]]; then
SPRING_PROFILE="$(ask_input "请输入自定义 profile" "${SPRING_PROFILE}")"
else
SPRING_PROFILE="${profile_choice}"
fi
;;
9)
JVM_OPTS="$(ask_input "请输入 JVM_OPTS" "${JVM_OPTS}")"
;;
10)
JAVA_SYS_PROPS="$(ask_input "请输入 JAVA_SYS_PROPS" "${JAVA_SYS_PROPS}")"
;;
11)
local debug_choice
debug_choice="$(ask_choice "是否启用 Debug" "1" "false" "true")"
DEBUG_ENABLED="${debug_choice}"
;;
12)
DEBUG_PORT="$(ask_input "请输入 DEBUG_PORT" "${DEBUG_PORT}")"
;;
13)
DEBUG_SUSPEND="$(ask_choice "DEBUG_SUSPEND 选择" "2" "y" "n")"
;;
14)
DEBUG_ADDRESS="$(ask_input "请输入 DEBUG_ADDRESS" "${DEBUG_ADDRESS}")"
;;
15)
STOP_TIMEOUT="$(ask_input "请输入 STOP_TIMEOUT" "${STOP_TIMEOUT}")"
;;
16)
START_WAIT="$(ask_input "请输入 START_WAIT" "${START_WAIT}")"
;;
17)
SPRING_EXTRA_ARGS="$(ask_input "请输入 SPRING_EXTRA_ARGS可留空" "${SPRING_EXTRA_ARGS}")"
;;
*)
log_warn "忽略无效编号:${idx}"
;;
esac
}
collect_inputs() {
echo "============================================================"
echo "Spring Boot 部署脚本生成器"
echo "模板文件:${TEMPLATE_FILE}"
echo "============================================================"
if [[ ! -f "${TEMPLATE_FILE}" ]]; then
log_error "模板文件不存在:${TEMPLATE_FILE}"
log_error "请先确认同目录下存在 deploy.sh"
exit 1
fi
APP_KEY="$(ask_input "请输入应用标识(用于生成 deploy-xxx.sh" "app")"
APP_KEY="$(echo "${APP_KEY}" | tr ' ' '-' | tr -cd '[:alnum:]_-')"
if [[ -z "${APP_KEY}" ]]; then
APP_KEY="app"
fi
TARGET_SCRIPT="${BASE_DIR}/deploy-${APP_KEY}.sh"
JDK_HOME="$(ask_input "请输入 JDK_HOME" "/usr/local/jdk")"
APP_HOME="$(ask_input "请输入 APP_HOMEJar 运行目录)" "/opt/apps/springboot")"
LOG_DIR="$(ask_input "请输入 LOG_DIR日志目录" "/opt/logs/springboot")"
CONFIG_DIR="$(ask_input "请输入 CONFIG_DIR外置配置目录" "/opt/config/springboot")"
local jar_mode
jar_mode="$(ask_choice "请选择 Jar 名称模式" "1" "自动发现JAR_NAME 留空)" "手动指定 Jar 名称")"
if [[ "${jar_mode}" == "自动发现JAR_NAME 留空)" ]]; then
JAR_NAME=""
else
JAR_NAME="$(ask_input "请输入 Jar 名称(如 demo.jar" "")"
fi
local profile_choice
profile_choice="$(ask_choice "请选择 Spring Profile" "4" "dev" "test" "stage" "prod" "custom")"
if [[ "${profile_choice}" == "custom" ]]; then
SPRING_PROFILE="$(ask_input "请输入自定义 profile" "prod")"
else
SPRING_PROFILE="${profile_choice}"
fi
JVM_OPTS="$(ask_input "请输入 JVM_OPTS" "-Xms512m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_DIR}/heapdump.hprof -Dfile.encoding=UTF-8")"
JAVA_SYS_PROPS="$(ask_input "请输入 JAVA_SYS_PROPS" "-Duser.timezone=Asia/Shanghai")"
local debug_choice
debug_choice="$(ask_choice "是否启用 Debug" "1" "false" "true")"
DEBUG_ENABLED="${debug_choice}"
DEBUG_PORT="5005"
DEBUG_SUSPEND="n"
DEBUG_ADDRESS="0.0.0.0"
if [[ "${DEBUG_ENABLED}" == "true" ]]; then
DEBUG_PORT="$(ask_input "请输入 DEBUG_PORT" "5005")"
DEBUG_SUSPEND="$(ask_choice "DEBUG_SUSPEND 选择" "2" "y" "n")"
DEBUG_ADDRESS="$(ask_input "请输入 DEBUG_ADDRESS" "0.0.0.0")"
fi
STOP_TIMEOUT="$(ask_input "请输入 STOP_TIMEOUT" "30")"
START_WAIT="$(ask_input "请输入 START_WAIT" "8")"
SPRING_EXTRA_ARGS="$(ask_input "请输入 SPRING_EXTRA_ARGS可留空" "")"
}
review_and_modify_loop() {
while true; do
print_config_summary
echo
echo "如需修改参数,请输入编号(支持多个,逗号分隔,例如 3,4,7。"
echo "直接回车表示不修改。输入 q 退出生成。"
local selection
read -r -p "请输入: " selection
if [[ "${selection}" == "q" ]]; then
log_warn "已取消生成。"
exit 0
fi
if [[ -n "${selection}" ]]; then
# 将逗号转换为空格后逐个处理
local token
for token in ${selection//,/ }; do
if [[ "${token}" =~ ^[0-9]+$ ]]; then
modify_one_field "${token}"
else
log_warn "忽略无效输入:${token}"
fi
done
continue
fi
if ask_confirm "确认以上配置并生成脚本吗?" "y"; then
break
fi
done
}
generate_script() {
local target_dir
target_dir="$(dirname "${TARGET_SCRIPT}")"
if [[ ! -d "${target_dir}" ]]; then
log_info "目标目录不存在,正在创建:${target_dir}"
mkdir -p "${target_dir}"
fi
if [[ -f "${TARGET_SCRIPT}" ]]; then
if ! ask_confirm "目标脚本已存在,是否覆盖?" "n"; then
log_warn "用户取消覆盖,生成中止。"
exit 0
fi
fi
cp "${TEMPLATE_FILE}" "${TARGET_SCRIPT}"
# 将模板中的顶部参数固化为本次采集值
replace_var_in_file "${TARGET_SCRIPT}" "JDK_HOME" "${JDK_HOME}"
replace_var_in_file "${TARGET_SCRIPT}" "APP_HOME" "${APP_HOME}"
replace_var_in_file "${TARGET_SCRIPT}" "LOG_DIR" "${LOG_DIR}"
replace_var_in_file "${TARGET_SCRIPT}" "CONFIG_DIR" "${CONFIG_DIR}"
replace_var_in_file "${TARGET_SCRIPT}" "JAR_NAME" "${JAR_NAME}"
replace_var_in_file "${TARGET_SCRIPT}" "JVM_OPTS" "${JVM_OPTS}"
replace_var_in_file "${TARGET_SCRIPT}" "SPRING_PROFILE" "${SPRING_PROFILE}"
replace_var_in_file "${TARGET_SCRIPT}" "JAVA_SYS_PROPS" "${JAVA_SYS_PROPS}"
replace_var_in_file "${TARGET_SCRIPT}" "DEBUG_ENABLED" "${DEBUG_ENABLED}"
replace_var_in_file "${TARGET_SCRIPT}" "DEBUG_PORT" "${DEBUG_PORT}"
replace_var_in_file "${TARGET_SCRIPT}" "DEBUG_SUSPEND" "${DEBUG_SUSPEND}"
replace_var_in_file "${TARGET_SCRIPT}" "DEBUG_ADDRESS" "${DEBUG_ADDRESS}"
replace_var_in_file "${TARGET_SCRIPT}" "STOP_TIMEOUT" "${STOP_TIMEOUT}"
replace_var_in_file "${TARGET_SCRIPT}" "START_WAIT" "${START_WAIT}"
replace_var_in_file "${TARGET_SCRIPT}" "SPRING_EXTRA_ARGS" "${SPRING_EXTRA_ARGS}"
chmod +x "${TARGET_SCRIPT}" 2>/dev/null || true
log_success "生成完成:${TARGET_SCRIPT}"
log_info "可以直接执行:${TARGET_SCRIPT}"
}
main() {
if [[ "${1:-}" == "--help" ]]; then
usage
exit 0
fi
collect_inputs
review_and_modify_loop
generate_script
}
main "$@"