release: sync public installer asset install.sh

This commit is contained in:
2026-09-02 02:35:55 +00:00
parent d085d4fd2c
commit 218574d2d2
+34 -17
View File
@@ -27,7 +27,7 @@ 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
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:-xiaoya-alist} XIAOYA_CONTAINER=${XYMEDIA_XIAOYA_CONTAINER:-xymedia-xiaoya}
CONTROLLER_ONLY=0 CONTROLLER_ONLY=0
MENU_PROFILES= MENU_PROFILES=
CONTROLLER_URL=${XYMEDIA_XIAOYA_CONTROLLER_URL:-} CONTROLLER_URL=${XYMEDIA_XIAOYA_CONTROLLER_URL:-}
@@ -106,7 +106,7 @@ done
die() { printf '\n\033[31mxymediavault installer: %s\033[0m\n' "$*" >&2; [[ -n $INSTALL_LOG ]] && printf '详情日志:%s\n' "$INSTALL_LOG" >&2; exit 1; } die() { printf '\n\033[31mxymediavault installer: %s\033[0m\n' "$*" >&2; [[ -n $INSTALL_LOG ]] && printf '详情日志:%s\n' "$INSTALL_LOG" >&2; exit 1; }
INSTALL_TMP_DIR= INSTALL_TMP_DIR=
cleanup_installer_tmp() { [[ -z ${INSTALL_TMP_DIR:-} ]] || rm -rf -- "$INSTALL_TMP_DIR"; } cleanup_installer_tmp() { [[ -z ${INSTALL_TMP_DIR:-} ]] || rm -rf -- "$INSTALL_TMP_DIR"; }
trap cleanup_installer_tmp EXIT INT TERM trap cleanup_installer_tmp EXIT
init_installer_log() { init_installer_log() {
local tmp_parent=${TMPDIR:-/tmp} mode local tmp_parent=${TMPDIR:-/tmp} mode
[[ -d $tmp_parent && ! -L $tmp_parent ]] || die 'TMPDIR must be an existing non-symlink directory' [[ -d $tmp_parent && ! -L $tmp_parent ]] || die 'TMPDIR must be an existing non-symlink directory'
@@ -184,7 +184,7 @@ menu() {
read_tty choice || die 'unable to read terminal input' read_tty choice || die 'unable to read terminal input'
case "$choice" in case "$choice" in
1) return 0;; 1) return 0;;
2) ensure_xiaoya_dir; printf '小雅目录已准备:%s;将安装小雅和小雅控制器。\n' "$XIAOYA_DIR" >>$TTY_OUT; write_controller_token; CONTROLLER_URL='http://xymedia-edge-controller:19090'; MENU_PROFILES='xiaoya xiaoya-control'; return 0;; 2) ensure_xiaoya_dir; printf '小雅目录已准备:%s;将安装小雅和小雅控制器。\n' "$XIAOYA_DIR" >>$TTY_OUT; write_controller_token; CONTROLLER_URL='http://xymedia-controller:19090'; MENU_PROFILES='xiaoya xiaoya-control'; 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;; 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
@@ -614,7 +614,7 @@ if (( ! SKIP_COMPONENTS )); then
cp "$archive" "$INSTALL_DIR/components/$component.tar.zst" cp "$archive" "$INSTALL_DIR/components/$component.tar.zst"
done done
fi fi
CONTROLLER_URL="$CONTROLLER_URL" PG_HOST="$PG_HOST" PG_PORT="$PG_PORT" PG_DB="$PG_DB" PG_USER="$PG_USER" python3 - "$CONFIG_TEMPLATE" "$INSTALL_DIR/config.yaml" <<'PY' CONTROLLER_URL="$CONTROLLER_URL" XIAOYA_CONTAINER="$XIAOYA_CONTAINER" PG_HOST="$PG_HOST" PG_PORT="$PG_PORT" PG_DB="$PG_DB" PG_USER="$PG_USER" python3 - "$CONFIG_TEMPLATE" "$INSTALL_DIR/config.yaml" <<'PY'
import os, pathlib, sys import os, pathlib, sys
template, output = map(pathlib.Path, sys.argv[1:]) template, output = map(pathlib.Path, sys.argv[1:])
values = { values = {
@@ -623,6 +623,7 @@ values = {
"${XYMEDIA_POSTGRES_DATABASE}": os.environ["PG_DB"], "${XYMEDIA_POSTGRES_DATABASE}": os.environ["PG_DB"],
"${XYMEDIA_POSTGRES_USER}": os.environ["PG_USER"], "${XYMEDIA_POSTGRES_USER}": os.environ["PG_USER"],
"${XYMEDIA_XIAOYA_CONTROLLER_URL}": os.environ["CONTROLLER_URL"], "${XYMEDIA_XIAOYA_CONTROLLER_URL}": os.environ["CONTROLLER_URL"],
"${XYMEDIA_XIAOYA_CONTAINER}": os.environ["XIAOYA_CONTAINER"],
} }
content = template.read_text() content = template.read_text()
for placeholder, value in values.items(): for placeholder, value in values.items():
@@ -662,35 +663,51 @@ if [[ $PG_HOST == postgres ]]; then
fi fi
fi fi
if [[ $PG_HOST == postgres ]]; then if [[ $PG_HOST == postgres ]]; then
ready=0 wait_for_postgres() {
for elapsed in $(seq 0 298 2); do local started_at elapsed container_id health
local previous_int previous_term
postgres_wait_interrupted=0
started_at=$(date +%s)
previous_int=$(trap -p INT || true)
previous_term=$(trap -p TERM || true)
trap 'postgres_wait_interrupted=1' INT TERM
while :; do
if (( postgres_wait_interrupted )); then
printf '\n已收到中断信号,正在停止 PostgreSQL 等待。\n'
printf '%s\n' 'PostgreSQL wait interrupted by signal' >>"$INSTALL_LOG"
printf '\n--- PostgreSQL 容器日志 ---\n' >>"$INSTALL_LOG"
"${COMPOSE[@]}" --profile local-db --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" logs postgres >>"$INSTALL_LOG" 2>&1 || true
[[ -n $previous_int ]] && eval "$previous_int" || trap - INT
[[ -n $previous_term ]] && eval "$previous_term" || trap - TERM
return 130
fi
elapsed=$(( $(date +%s) - started_at ))
container_id=$("${COMPOSE[@]}" --profile local-db --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" ps -q postgres 2>>"$INSTALL_LOG" || true) container_id=$("${COMPOSE[@]}" --profile local-db --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" ps -q postgres 2>>"$INSTALL_LOG" || true)
health= health=
if [[ -n $container_id ]]; then if [[ -n $container_id ]]; 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
ready=1 printf '\033[2K\r[%d/%d] PostgreSQL 已就绪(%s 秒)\n' "$STEP" "$TOTAL_STEPS" "$elapsed"
break [[ -n $previous_int ]] && eval "$previous_int" || trap - INT
[[ -n $previous_term ]] && eval "$previous_term" || trap - TERM
return 0
fi fi
printf '\033[2K\r[%d/%d] 等待 PostgreSQL 就绪(%s 秒)' "$STEP" "$TOTAL_STEPS" "$elapsed" printf '\033[2K\r[%d/%d] 等待 PostgreSQL 就绪(已用 %s 秒,状态:%s' "$STEP" "$TOTAL_STEPS" "$elapsed" "${health:-unknown}"
printf 'PostgreSQL status: elapsed=%s health=%s\n' "$elapsed" "${health:-unknown}" >>"$INSTALL_LOG"
sleep 2 sleep 2
done done
printf '\n' }
if [[ $ready != 1 ]]; then wait_for_postgres || die 'PostgreSQL 等待被中断,安装未完成'
printf '\n--- PostgreSQL 容器日志 ---\n' >>"$INSTALL_LOG"
"${COMPOSE[@]}" --profile local-db --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" logs postgres >>"$INSTALL_LOG" 2>&1 || true
die 'PostgreSQL 未在限定时间内就绪'
fi
fi fi
progress '初始化数据库结构' progress '初始化数据库结构'
if (( EXISTING_DB )); then if (( EXISTING_DB )); then
export XYMEDIA_EXTERNAL_MIGRATION_CONFIRM=YES export XYMEDIA_EXTERNAL_MIGRATION_CONFIRM=YES
if ! run_visible_logged "${COMPOSE[@]}" --profile migration --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" run --rm --no-deps app-migrate migrate --config /app/config.yaml; then if ! run_visible_logged "${COMPOSE[@]}" --profile migration --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" run --rm --name "xymedia-app-migrate-${INSTALL_NONCE}" --no-deps app-migrate migrate --config /app/config.yaml; then
die '已有数据库迁移失败' die '已有数据库迁移失败'
fi fi
else else
if ! run_visible_logged "${COMPOSE[@]}" --profile migration --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" run --rm --no-deps app-migrate migrate --new --config /app/config.yaml; then if ! run_visible_logged "${COMPOSE[@]}" --profile migration --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" run --rm --name "xymedia-app-migrate-${INSTALL_NONCE}" --no-deps app-migrate migrate --new --config /app/config.yaml; then
die '数据库初始化失败' die '数据库初始化失败'
fi fi
fi fi