feat: add unified installer management menu
This commit is contained in:
@@ -35,10 +35,10 @@ curl -fsSL https://raw.githubusercontent.com/zxyszx/NewSzxcn-Email/main/install.
|
|||||||
bash <(curl -fsSL https://raw.githubusercontent.com/zxyszx/NewSzxcn-Email/main/install.sh)
|
bash <(curl -fsSL https://raw.githubusercontent.com/zxyszx/NewSzxcn-Email/main/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
空白服务器会进入防火墙、邮件域名、管理员账号和 Web 部署方式的引导。检测到
|
脚本会先显示统一管理菜单。空白服务器默认选择安装,并进入防火墙、邮件域名、管理员
|
||||||
`/opt/newszxcn-email/.env` 时,脚本会先询问是更新现有邮局、修复现有安装、退出,
|
账号和 Web 部署方式的引导;检测到已有安装时默认选择安全更新。选择重新安装会先将
|
||||||
还是完整备份旧目录后全新安装;不会再直接跳过引导并重启服务。更新会先备份数据库,
|
`/opt/newszxcn-email` 完整改名备份,再进入首次安装流程。更新会先备份数据库,并在
|
||||||
并在启动失败时自动回滚。
|
启动失败时自动回滚。
|
||||||
|
|
||||||
脚本会自动完成:
|
脚本会自动完成:
|
||||||
|
|
||||||
|
|||||||
+71
-22
@@ -4,7 +4,7 @@ set -Eeuo pipefail
|
|||||||
REPOSITORY="zxyszx/NewSzxcn-Email"
|
REPOSITORY="zxyszx/NewSzxcn-Email"
|
||||||
RAW_BASE="https://raw.githubusercontent.com/${REPOSITORY}/main"
|
RAW_BASE="https://raw.githubusercontent.com/${REPOSITORY}/main"
|
||||||
INSTALL_DIR="${LANQIN_INSTALL_DIR:-/opt/newszxcn-email}"
|
INSTALL_DIR="${LANQIN_INSTALL_DIR:-/opt/newszxcn-email}"
|
||||||
COMMAND="${1:-install}"
|
COMMAND="${1:-menu}"
|
||||||
ROLLBACK_FILE="${INSTALL_DIR}/.rollback-image"
|
ROLLBACK_FILE="${INSTALL_DIR}/.rollback-image"
|
||||||
NGINX_CONFIG="/etc/nginx/conf.d/newszxcn-email.conf"
|
NGINX_CONFIG="/etc/nginx/conf.d/newszxcn-email.conf"
|
||||||
ACME_WEBROOT="/var/www/newszxcn-acme"
|
ACME_WEBROOT="/var/www/newszxcn-acme"
|
||||||
@@ -21,7 +21,8 @@ NewSzxcn Email 管理命令
|
|||||||
|
|
||||||
用法:newszxcn-email <command>
|
用法:newszxcn-email <command>
|
||||||
|
|
||||||
install 首次安装;检测到已有安装时显示操作菜单
|
menu 显示安装与运维菜单
|
||||||
|
install 首次安装;已有安装会先完整备份再重新安装
|
||||||
update 备份数据库并更新到最新版
|
update 备份数据库并更新到最新版
|
||||||
status 查看容器与健康状态
|
status 查看容器与健康状态
|
||||||
logs 持续查看运行日志
|
logs 持续查看运行日志
|
||||||
@@ -163,19 +164,24 @@ prompt_choice() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt_existing_install_action() {
|
prompt_menu_choice() {
|
||||||
local public_url action
|
local default_value="$1" value="${LANQIN_MENU_ACTION:-}"
|
||||||
public_url="$(env_value LANQIN_PUBLIC_BASE_URL || true)"
|
if [[ -z "${value}" ]] && ! has_tty; then
|
||||||
prompt_text "\n[发现] 检测到已有 NewSzxcn Email 安装:${INSTALL_DIR}\n"
|
fail "非交互环境请直接使用 install、update、status 等子命令。"
|
||||||
if [[ -n "${public_url}" ]]; then
|
|
||||||
prompt_text "[发现] 当前访问地址:${public_url}\n"
|
|
||||||
fi
|
fi
|
||||||
prompt_text '请选择操作 [1]:\n1. 更新现有邮局(推荐,自动备份并支持回滚)\n2. 修复现有安装(保留配置和数据)\n3. 退出,不做任何修改\n4. 备份现有安装并全新安装\n'
|
while true; do
|
||||||
if [[ -z "${LANQIN_EXISTING_ACTION:-}" ]] && ! has_tty; then
|
if [[ -z "${value}" ]] && has_tty; then
|
||||||
fail "非交互环境不能选择已有安装操作;更新请执行 newszxcn-email update。"
|
read -r -p "请选择 [${default_value}]: " value </dev/tty
|
||||||
fi
|
fi
|
||||||
action="$(prompt_choice LANQIN_EXISTING_ACTION "请选择 [1]: " "1" "4")"
|
value="${value:-${default_value}}"
|
||||||
printf '%s' "${action}"
|
if [[ "${value}" =~ ^[0-9]$ ]]; then
|
||||||
|
printf '%s' "${value}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
prompt_text "[提示] 请输入 0 至 9。\n"
|
||||||
|
value=""
|
||||||
|
has_tty || fail "LANQIN_MENU_ACTION 必须设置为 0 至 9。"
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
has_tty() {
|
has_tty() {
|
||||||
@@ -605,15 +611,8 @@ do_repair_install() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_install() {
|
do_install() {
|
||||||
local action
|
|
||||||
if [[ -f "${INSTALL_DIR}/.env" ]]; then
|
if [[ -f "${INSTALL_DIR}/.env" ]]; then
|
||||||
action="$(prompt_existing_install_action)"
|
do_backup_reinstall
|
||||||
case "${action}" in
|
|
||||||
1) do_update ;;
|
|
||||||
2) do_repair_install ;;
|
|
||||||
3) success "已退出,现有邮局未作修改。" ;;
|
|
||||||
4) do_backup_reinstall ;;
|
|
||||||
esac
|
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -749,6 +748,55 @@ do_backup_reinstall() {
|
|||||||
do_install
|
do_install
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_menu() {
|
||||||
|
local installed="false" default_choice="1" public_url="" choice
|
||||||
|
if [[ -f "${INSTALL_DIR}/.env" ]]; then
|
||||||
|
installed="true"
|
||||||
|
default_choice="2"
|
||||||
|
public_url="$(env_value LANQIN_PUBLIC_BASE_URL || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
prompt_text '\n==================================================\n'
|
||||||
|
prompt_text ' NewSzxcn Email 一键安装与管理\n'
|
||||||
|
prompt_text '==================================================\n'
|
||||||
|
if [[ "${installed}" == "true" ]]; then
|
||||||
|
prompt_text " 状态:已安装\n 路径:${INSTALL_DIR}\n"
|
||||||
|
[[ -n "${public_url}" ]] && prompt_text " 地址:${public_url}\n"
|
||||||
|
else
|
||||||
|
prompt_text ' 状态:未安装\n'
|
||||||
|
fi
|
||||||
|
prompt_text '--------------------------------------------------\n'
|
||||||
|
prompt_text ' 1. 安装 / 重新安装(旧数据自动备份)\n'
|
||||||
|
prompt_text ' 2. 更新系统(数据库自动备份)\n'
|
||||||
|
prompt_text ' 3. 修复现有安装\n'
|
||||||
|
prompt_text ' 4. 查看运行状态\n'
|
||||||
|
prompt_text ' 5. 重启服务\n'
|
||||||
|
prompt_text ' 6. 查看实时日志\n'
|
||||||
|
prompt_text ' 7. 申请或续期 SSL 证书\n'
|
||||||
|
prompt_text ' 8. 回滚上个命令行版本\n'
|
||||||
|
prompt_text ' 9. 卸载服务(保留数据)\n'
|
||||||
|
prompt_text ' 0. 退出\n'
|
||||||
|
prompt_text '==================================================\n'
|
||||||
|
|
||||||
|
choice="$(prompt_menu_choice "${default_choice}")"
|
||||||
|
if [[ "${choice}" != "0" && "${choice}" != "1" && "${installed}" != "true" ]]; then
|
||||||
|
fail "尚未安装,请先选择 1。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${choice}" in
|
||||||
|
0) success "已退出,未作任何修改。" ;;
|
||||||
|
1) do_install ;;
|
||||||
|
2) do_update ;;
|
||||||
|
3) do_repair_install ;;
|
||||||
|
4) ensure_docker; do_status ;;
|
||||||
|
5) do_restart ;;
|
||||||
|
6) ensure_docker; compose logs -f --tail=200 lanqin-email updater ;;
|
||||||
|
7) do_certificate ;;
|
||||||
|
8) ensure_docker; do_rollback ;;
|
||||||
|
9) ensure_docker; do_uninstall ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
if [[ "${LANQIN_SOURCE_ONLY:-false}" == "true" ]]; then
|
if [[ "${LANQIN_SOURCE_ONLY:-false}" == "true" ]]; then
|
||||||
if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
|
if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
|
||||||
return 0
|
return 0
|
||||||
@@ -758,6 +806,7 @@ fi
|
|||||||
|
|
||||||
case "${COMMAND}" in
|
case "${COMMAND}" in
|
||||||
help|-h|--help) usage ;;
|
help|-h|--help) usage ;;
|
||||||
|
menu) require_root; require_curl; do_menu ;;
|
||||||
install) require_root; require_curl; do_install ;;
|
install) require_root; require_curl; do_install ;;
|
||||||
update) require_root; require_curl; do_update ;;
|
update) require_root; require_curl; do_update ;;
|
||||||
status) require_root; require_curl; ensure_docker; do_status ;;
|
status) require_root; require_curl; ensure_docker; do_status ;;
|
||||||
|
|||||||
+9
-17
@@ -109,22 +109,14 @@ test_legacy_configuration_is_preserved() {
|
|||||||
assert_eq "127.0.0.1:9090" "$(env_value LANQIN_HTTP_BIND)" "legacy HTTP bind"
|
assert_eq "127.0.0.1:9090" "$(env_value LANQIN_HTTP_BIND)" "legacy HTTP bind"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_existing_install_action() {
|
test_menu_choice() {
|
||||||
local temp_dir
|
export LANQIN_MENU_ACTION=0
|
||||||
temp_dir="$(mktemp -d)"
|
assert_eq "0" "$(prompt_menu_choice 1)" "menu exit action"
|
||||||
cp "${ROOT_DIR}/deploy/.env.example" "${temp_dir}/.env"
|
export LANQIN_MENU_ACTION=1
|
||||||
export INSTALL_DIR="${temp_dir}"
|
assert_eq "1" "$(prompt_menu_choice 2)" "menu install action"
|
||||||
set_env LANQIN_PUBLIC_BASE_URL "https://mail.example.com"
|
export LANQIN_MENU_ACTION=9
|
||||||
|
assert_eq "9" "$(prompt_menu_choice 1)" "menu uninstall action"
|
||||||
export LANQIN_EXISTING_ACTION=1
|
unset LANQIN_MENU_ACTION
|
||||||
assert_eq "1" "$(prompt_existing_install_action)" "existing install update action"
|
|
||||||
export LANQIN_EXISTING_ACTION=2
|
|
||||||
assert_eq "2" "$(prompt_existing_install_action)" "existing install repair action"
|
|
||||||
export LANQIN_EXISTING_ACTION=3
|
|
||||||
assert_eq "3" "$(prompt_existing_install_action)" "existing install exit action"
|
|
||||||
export LANQIN_EXISTING_ACTION=4
|
|
||||||
assert_eq "4" "$(prompt_existing_install_action)" "existing install fresh action"
|
|
||||||
unset LANQIN_EXISTING_ACTION
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test_backup_reinstall_preserves_existing_directory() (
|
test_backup_reinstall_preserves_existing_directory() (
|
||||||
@@ -153,7 +145,7 @@ test_install_configuration 3 3 "80" "http://mail.example.com" "true"
|
|||||||
test_nginx_configuration
|
test_nginx_configuration
|
||||||
test_compose_configuration
|
test_compose_configuration
|
||||||
test_legacy_configuration_is_preserved
|
test_legacy_configuration_is_preserved
|
||||||
test_existing_install_action
|
test_menu_choice
|
||||||
test_backup_reinstall_preserves_existing_directory
|
test_backup_reinstall_preserves_existing_directory
|
||||||
|
|
||||||
printf 'install.sh tests passed\n'
|
printf 'install.sh tests passed\n'
|
||||||
|
|||||||
Reference in New Issue
Block a user