release: sync public installer asset install.sh

This commit is contained in:
2026-09-09 02:47:04 +00:00
parent 558f43062a
commit 8f6402aeb0
+39 -11
View File
@@ -33,6 +33,26 @@ TTY_TEST_MODE=0
TTY_TEST_INDEX=0 TTY_TEST_INDEX=0
TTY_TEST_LINES=() TTY_TEST_LINES=()
if [[ -n ${XYMEDIA_INSTALL_TEST_TTY:-} ]]; then TTY_TEST_MODE=1; mapfile -t TTY_TEST_LINES <"$TTY_IN"; fi if [[ -n ${XYMEDIA_INSTALL_TEST_TTY:-} ]]; then TTY_TEST_MODE=1; mapfile -t TTY_TEST_LINES <"$TTY_IN"; fi
TERMINAL_CAPABLE=0
COLOR_ENABLED=0
TERMINAL_REDRAW=0
COLOR_RESET= COLOR_TITLE= COLOR_RECOMMENDED= COLOR_HINT= COLOR_SECTION= COLOR_WARNING=
ERROR_COLOR= ERROR_RESET=
if [[ -r $TTY_IN && -w $TTY_OUT && -c $TTY_OUT ]]; then
TERMINAL_CAPABLE=1
fi
if (( TERMINAL_CAPABLE && ! TTY_TEST_MODE )) && [[ -z ${NO_COLOR+x} && ${TERM:-} != dumb ]]; then
COLOR_ENABLED=1
TERMINAL_REDRAW=1
COLOR_RESET=$'\033[0m'
COLOR_TITLE=$'\033[1;36m'
COLOR_RECOMMENDED=$'\033[1;32m'
COLOR_HINT=$'\033[2;37m'
COLOR_SECTION=$'\033[1;34m'
COLOR_WARNING=$'\033[1;31m'
ERROR_COLOR=$'\033[31m'
ERROR_RESET=$'\033[0m'
fi
XIAOYA_DIR=${XYMEDIA_XIAOYA_DIR:-} XIAOYA_DIR=${XYMEDIA_XIAOYA_DIR:-}
XIAOYA_CONTAINER_EXPLICIT=${XYMEDIA_XIAOYA_CONTAINER:+1} XIAOYA_CONTAINER_EXPLICIT=${XYMEDIA_XIAOYA_CONTAINER:+1}
XIAOYA_CONTAINER=${XYMEDIA_XIAOYA_CONTAINER:-xymedia-xiaoya} XIAOYA_CONTAINER=${XYMEDIA_XIAOYA_CONTAINER:-xymedia-xiaoya}
@@ -301,7 +321,7 @@ persist_installer_log() {
cp "$INSTALL_LOG" "$INSTALL_DIR/install.log" 2>/dev/null || true cp "$INSTALL_LOG" "$INSTALL_DIR/install.log" 2>/dev/null || true
chmod 600 "$INSTALL_DIR/install.log" 2>/dev/null || true chmod 600 "$INSTALL_DIR/install.log" 2>/dev/null || true
} }
die() { printf '\n\033[31mxymediavault installer: %s\033[0m\n' "$*" >&2; persist_installer_log; [[ -f ${INSTALL_DIR:-}/install.log ]] && printf '详情日志:%s/install.log\n' "$INSTALL_DIR" >&2 || { [[ -n $INSTALL_LOG ]] && printf '详情日志:%s\n' "$INSTALL_LOG" >&2; }; exit 1; } die() { printf '\n%sxymediavault installer: %s%s\n' "$ERROR_COLOR" "$*" "$ERROR_RESET" >&2; persist_installer_log; [[ -f ${INSTALL_DIR:-}/install.log ]] && printf '详情日志:%s/install.log\n' "$INSTALL_DIR" >&2 || { [[ -n $INSTALL_LOG ]] && printf '详情日志:%s\n' "$INSTALL_LOG" >&2; }; exit 1; }
component_cache_test_mode() { component_cache_test_mode() {
local catalog=${XYMEDIA_INSTALL_TEST_CATALOG:?} component platform version url sha archive marker_version marker_sha stage downloaded tarball actual local catalog=${XYMEDIA_INSTALL_TEST_CATALOG:?} component platform version url sha archive marker_version marker_sha stage downloaded tarball actual
mkdir -p "$INSTALL_DIR/components" "$INSTALL_DIR/state" mkdir -p "$INSTALL_DIR/components" "$INSTALL_DIR/state"
@@ -413,11 +433,19 @@ ensure_instance_id() {
} }
progress() { progress() {
STEP=$((STEP + 1)) STEP=$((STEP + 1))
printf '\033[2K\r[%d/%d] %s\n' "$STEP" "$TOTAL_STEPS" "$1" terminal_status "[$STEP/$TOTAL_STEPS] $1" 1
if [[ -n $INSTALL_LOG ]]; then if [[ -n $INSTALL_LOG ]]; then
printf '[%d/%d] %s\n' "$STEP" "$TOTAL_STEPS" "$1" >>"$INSTALL_LOG" printf '[%d/%d] %s\n' "$STEP" "$TOTAL_STEPS" "$1" >>"$INSTALL_LOG"
fi fi
} }
terminal_status() {
if (( TERMINAL_REDRAW )); then
printf '\033[2K\r%s' "$1"
[[ ${2:-0} == 1 ]] && printf '\n'
else
printf '%s\n' "$1"
fi
}
run_logged() { run_logged() {
if "$@" >>"$INSTALL_LOG" 2>&1; then if "$@" >>"$INSTALL_LOG" 2>&1; then
return 0 return 0
@@ -571,7 +599,7 @@ menu() {
[[ $# -eq 0 ]] || return 0 [[ $# -eq 0 ]] || return 0
[[ -r $TTY_IN && -w $TTY_OUT ]] || die '没有可用终端:安装菜单不能通过非交互管道运行' [[ -r $TTY_IN && -w $TTY_OUT ]] || die '没有可用终端:安装菜单不能通过非交互管道运行'
while :; do while :; do
printf '\nXyMediaVault 安装器\n1) 推荐安装:管理平台和本机小雅(新用户、单机部署、默认推荐)\n2) 仅安装管理平台(只需要平台,暂不接入小雅)\n3) 安装管理平台并连接远程小雅控制器(小雅在另一台机器)\n4) 仅安装小雅控制器(这台机器只负责运行小雅控制器)\n5) 状态/诊断/维护\n6) 查看小雅控制器地址和密钥\n7) 查看数据库连接信息\n0) 退出\n提示:首次本机部署请选择 1;已有本机 Alist/小雅可在 1 中选择复用或独立安装。\n选择:' >>$TTY_OUT printf '\n%sXyMediaVault 安装器%s\n%s----------------------------------------%s\n%s1) 推荐安装:管理平台和本机小雅(新用户、单机部署、默认推荐)%s\n2) 仅安装管理平台(只需要平台,暂不接入小雅)\n3) 安装管理平台并连接远程小雅控制器(小雅在另一台机器)\n4) 仅安装小雅控制器(这台机器只负责运行小雅控制器)\n%s----------------------------------------%s\n%s5) 状态/诊断/维护%s\n6) 查看小雅控制器地址和密钥\n7) 查看数据库连接信息\n0) 退出\n%s提示:首次本机部署请选择 1;已有本机 Alist/小雅可在 1 中选择复用或独立安装。%s\n选择:' "$COLOR_TITLE" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_RECOMMENDED" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_HINT" "$COLOR_RESET" >>$TTY_OUT
read_tty choice || die '无法读取终端输入' read_tty choice || die '无法读取终端输入'
case "$choice" in case "$choice" in
1) write_controller_token; CONTROLLER_URL='http://xymedia-controller:19090'; OPTION2_XIAOYA_PENDING=1; return 0;; 1) write_controller_token; CONTROLLER_URL='http://xymedia-controller:19090'; OPTION2_XIAOYA_PENDING=1; return 0;;
@@ -579,14 +607,14 @@ menu() {
3) local url name key; url=$(prompt_tty '控制器地址:'); key=$(prompt_tty '控制器密钥:'); name=$(prompt_tty '显示名称:'); [[ $url == https://* || ${ALLOW_HTTP:-0} == 1 ]] || die '远程连接默认要求 HTTPS;设置 ALLOW_HTTP=1 后才允许 HTTP'; curl --fail --silent --show-error --location --max-time 10 -H "X-XyMedia-Controller-Token: $key" "${url%/}/health" >/dev/null || die '控制器健康检查失败,未保存连接'; REMOTE_MODE=1; REMOTE_TOKEN=$key; CONTROLLER_URL="${url%/}"; printf '远程连接 %s (%s) 校验成功,配置已保存;控制器密钥不会显示。\n' "$name" "$CONTROLLER_URL" >>$TTY_OUT; return 0;; 3) local url name key; url=$(prompt_tty '控制器地址:'); key=$(prompt_tty '控制器密钥:'); name=$(prompt_tty '显示名称:'); [[ $url == https://* || ${ALLOW_HTTP:-0} == 1 ]] || die '远程连接默认要求 HTTPS;设置 ALLOW_HTTP=1 后才允许 HTTP'; curl --fail --silent --show-error --location --max-time 10 -H "X-XyMedia-Controller-Token: $key" "${url%/}/health" >/dev/null || die '控制器健康检查失败,未保存连接'; REMOTE_MODE=1; REMOTE_TOKEN=$key; CONTROLLER_URL="${url%/}"; printf '远程连接 %s (%s) 校验成功,配置已保存;控制器密钥不会显示。\n' "$name" "$CONTROLLER_URL" >>$TTY_OUT; return 0;;
4) ensure_xiaoya_dir 1; if [[ ${XYMEDIA_INSTALL_TEST_DISCOVERY_ONLY:-0} != 1 && -z $CONTROLLER_BIND_EXPLICIT ]]; then prompt_tty_into CONTROLLER_BIND_ADDRESS "控制器监听地址 [${CONTROLLER_BIND_ADDRESS}]: "; CONTROLLER_BIND_ADDRESS=${CONTROLLER_BIND_ADDRESS:-0.0.0.0}; fi; if [[ ${XYMEDIA_INSTALL_TEST_DISCOVERY_ONLY:-0} != 1 && -z $CONTROLLER_PORT_EXPLICIT ]]; then prompt_tty_into CONTROLLER_PORT "控制器端口 [${CONTROLLER_PORT}]: "; CONTROLLER_PORT=${CONTROLLER_PORT:-19090}; fi; write_controller_token; CONTROLLER_ONLY=1; printf '小雅控制器安装目录已准备。\n' >>$TTY_OUT; MENU_PROFILES='xiaoya-control'; return 0;; 4) ensure_xiaoya_dir 1; if [[ ${XYMEDIA_INSTALL_TEST_DISCOVERY_ONLY:-0} != 1 && -z $CONTROLLER_BIND_EXPLICIT ]]; then prompt_tty_into CONTROLLER_BIND_ADDRESS "控制器监听地址 [${CONTROLLER_BIND_ADDRESS}]: "; CONTROLLER_BIND_ADDRESS=${CONTROLLER_BIND_ADDRESS:-0.0.0.0}; fi; if [[ ${XYMEDIA_INSTALL_TEST_DISCOVERY_ONLY:-0} != 1 && -z $CONTROLLER_PORT_EXPLICIT ]]; then prompt_tty_into CONTROLLER_PORT "控制器端口 [${CONTROLLER_PORT}]: "; CONTROLLER_PORT=${CONTROLLER_PORT:-19090}; fi; write_controller_token; CONTROLLER_ONLY=1; printf '小雅控制器安装目录已准备。\n' >>$TTY_OUT; MENU_PROFILES='xiaoya-control'; return 0;;
5) while :; do 5) while :; do
printf '\n维护菜单\n1) 查看状态\n2) 一键挂载本地媒体库\n3) 启动/重启已配置挂载\n4) 停用本地媒体库挂载\n5) 清理 XyMediaVault 容器及数据\n0) 返回\n选择:' >>$TTY_OUT printf '\n%s维护菜单%s\n%s----------------------------------------%s\n1) 查看状态\n2) 一键挂载本地媒体库\n3) 启动/重启已配置挂载\n4) 停用本地媒体库挂载\n%s[!] 清理 XyMediaVault 容器及数据%s\n%s----------------------------------------%s\n0) 返回\n选择:' "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_WARNING" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" >>$TTY_OUT
read_tty maintenance_choice || die '无法读取终端输入' read_tty maintenance_choice || die '无法读取终端输入'
case "$maintenance_choice" in case "$maintenance_choice" in
1) require_public_app_installation || continue; print_fuse_status;; 1) require_public_app_installation || continue; print_fuse_status;;
2) require_public_app_installation || continue; prompt_tty_into FUSE_PATH_INPUT '宿主机媒体库目录(必须为空):'; confirm_fuse_action; MAINTENANCE_ACTION=configure; return 0;; 2) require_public_app_installation || continue; prompt_tty_into FUSE_PATH_INPUT '宿主机媒体库目录(必须为空):'; confirm_fuse_action; MAINTENANCE_ACTION=configure; return 0;;
3) require_public_app_installation || continue; confirm_fuse_action; MAINTENANCE_ACTION=restart; return 0;; 3) require_public_app_installation || continue; confirm_fuse_action; MAINTENANCE_ACTION=restart; return 0;;
4) require_public_app_installation || continue; confirm_fuse_action; MAINTENANCE_ACTION=disable; return 0;; 4) require_public_app_installation || continue; confirm_fuse_action; MAINTENANCE_ACTION=disable; return 0;;
5) printf '清理选项:\n1) 只清理 XyMediaVault\n2) 清理 XyMediaVault 和本机安装的小雅\n0) 取消\n选择:' >>$TTY_OUT; read_tty cleanup_choice || die '无法读取终端输入'; case "$cleanup_choice" in 1) CLEANUP_CHOICE=1; return 0;; 2) CLEANUP_CHOICE=2; return 0;; 0) continue;; *) printf '无效选择\n' >>$TTY_OUT;; esac;; 5) printf '%s清理选项:%s\n%s----------------------------------------%s\n%s1) 只清理 XyMediaVault%s\n%s2) 清理 XyMediaVault 和本机安装的小雅%s\n0) 取消\n选择:' "$COLOR_WARNING" "$COLOR_RESET" "$COLOR_SECTION" "$COLOR_RESET" "$COLOR_WARNING" "$COLOR_RESET" "$COLOR_WARNING" "$COLOR_RESET" >>$TTY_OUT; read_tty cleanup_choice || die '无法读取终端输入'; case "$cleanup_choice" in 1) CLEANUP_CHOICE=1; return 0;; 2) CLEANUP_CHOICE=2; return 0;; 0) continue;; *) printf '无效选择\n' >>$TTY_OUT;; esac;;
0) continue 2;; *) printf '无效选择\n' >>$TTY_OUT;; 0) continue 2;; *) printf '无效选择\n' >>$TTY_OUT;;
esac esac
done;; done;;
@@ -1483,12 +1511,12 @@ if (( LOCAL_DB )); then
health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>>"$INSTALL_LOG" || true) health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>>"$INSTALL_LOG" || true)
fi fi
if [[ $health == healthy ]]; then if [[ $health == healthy ]]; then
printf '\033[2K\r[%d/%d] PostgreSQL 已就绪(%s 秒)\n' "$STEP" "$TOTAL_STEPS" "$elapsed" terminal_status "[$STEP/$TOTAL_STEPS] PostgreSQL 已就绪($elapsed 秒)" 1
[[ -n $previous_int ]] && eval "$previous_int" || trap - INT [[ -n $previous_int ]] && eval "$previous_int" || trap - INT
[[ -n $previous_term ]] && eval "$previous_term" || trap - TERM [[ -n $previous_term ]] && eval "$previous_term" || trap - TERM
return 0 return 0
fi fi
printf '\033[2K\r[%d/%d] 等待 PostgreSQL 就绪(已用 %s 秒,状态:%s' "$STEP" "$TOTAL_STEPS" "$elapsed" "${health:-unknown}" terminal_status "[$STEP/$TOTAL_STEPS] 等待 PostgreSQL 就绪(已用 $elapsed 秒,状态:${health:-unknown}"
printf 'PostgreSQL status: elapsed=%s health=%s\n' "$elapsed" "${health:-unknown}" >>"$INSTALL_LOG" printf 'PostgreSQL status: elapsed=%s health=%s\n' "$elapsed" "${health:-unknown}" >>"$INSTALL_LOG"
sleep 2 sleep 2
done done
@@ -1517,11 +1545,11 @@ wait_postgres_external() {
client_command=(docker run --rm --network "$db_network" -e "PGPASSWORD=$PG_PASSWORD" postgres:17-bookworm psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -c 'SELECT 1') client_command=(docker run --rm --network "$db_network" -e "PGPASSWORD=$PG_PASSWORD" postgres:17-bookworm psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -c 'SELECT 1')
if "${client_command[@]}" >>"$INSTALL_LOG" 2>&1; then if "${client_command[@]}" >>"$INSTALL_LOG" 2>&1; then
elapsed=$(( $(date +%s) - started_at )) elapsed=$(( $(date +%s) - started_at ))
printf '\033[2K\r[%d/%d] PostgreSQL 外部连接已验证(%s 秒)\n' "$STEP" "$TOTAL_STEPS" "$elapsed" terminal_status "[$STEP/$TOTAL_STEPS] PostgreSQL 外部连接已验证($elapsed 秒)" 1
return 0 return 0
fi fi
elapsed=$(( $(date +%s) - started_at )) elapsed=$(( $(date +%s) - started_at ))
printf '\033[2K\r[%d/%d] 数据库外部连接仍在等待(%s秒)' "$STEP" "$TOTAL_STEPS" "$elapsed" terminal_status "[$STEP/$TOTAL_STEPS] 数据库外部连接仍在等待(${elapsed}秒)"
printf 'PostgreSQL external status: elapsed=%s host=%s port=%s\n' "$elapsed" "$PG_HOST" "$PG_PORT" >>"$INSTALL_LOG" printf 'PostgreSQL external status: elapsed=%s host=%s port=%s\n' "$elapsed" "$PG_HOST" "$PG_PORT" >>"$INSTALL_LOG"
sleep 2 sleep 2
done done
@@ -1618,7 +1646,7 @@ wait_for_app_health() {
[[ -n $previous_term ]] && eval "$previous_term" || trap - TERM [[ -n $previous_term ]] && eval "$previous_term" || trap - TERM
return 0 return 0
fi fi
printf '\033[2K\r[%d/%d] 等待 XyMediaVault 健康检查(已用 %s 秒)' "$STEP" "$TOTAL_STEPS" "$elapsed" terminal_status "[$STEP/$TOTAL_STEPS] 等待 XyMediaVault 健康检查(已用 $elapsed 秒)"
printf 'XyMediaVault health status: elapsed=%s\n' "$elapsed" >>"$INSTALL_LOG" printf 'XyMediaVault health status: elapsed=%s\n' "$elapsed" >>"$INSTALL_LOG"
sleep 2 sleep 2
done done
@@ -1632,7 +1660,7 @@ else
fi fi
if (( RELEASE_ROLLBACK_ACTIVE )); then rm -rf -- "$release_backup"; RELEASE_ROLLBACK_ACTIVE=0; fi if (( RELEASE_ROLLBACK_ACTIVE )); then rm -rf -- "$release_backup"; RELEASE_ROLLBACK_ACTIVE=0; fi
cp "$INSTALL_LOG" "$INSTALL_DIR/install.log" 2>/dev/null || true cp "$INSTALL_LOG" "$INSTALL_DIR/install.log" 2>/dev/null || true
printf '\033[2K\r[%d/%d] 安装完成:XyMediaVault 已就绪\n' "$TOTAL_STEPS" "$TOTAL_STEPS" terminal_status "[$TOTAL_STEPS/$TOTAL_STEPS] 安装完成:XyMediaVault 已就绪" 1
management_address=$(printf '%s\n' "$HOST_ADDRESSES_INITIAL" | head -n 1) management_address=$(printf '%s\n' "$HOST_ADDRESSES_INITIAL" | head -n 1)
[[ -n $management_address ]] || management_address=127.0.0.1 [[ -n $management_address ]] || management_address=127.0.0.1
if [[ $management_address == *:* ]]; then management_address="[$management_address]"; fi if [[ $management_address == *:* ]]; then management_address="[$management_address]"; fi