release: sync public installer asset install.sh
This commit is contained in:
+195
-43
@@ -287,8 +287,75 @@ persist_installer_log() {
|
||||
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; }
|
||||
component_cache_test_mode() {
|
||||
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"
|
||||
for component in tmm title; do
|
||||
if [[ $component == tmm ]]; then platform=linux-any
|
||||
elif [[ -n ${XYMEDIA_INSTALL_TEST_PLATFORM:-} ]]; then platform=$XYMEDIA_INSTALL_TEST_PLATFORM
|
||||
else case "$(uname -m)" in x86_64|amd64) platform=linux-amd64;; aarch64|arm64) platform=linux-arm64;; *) die "unsupported host architecture: $(uname -m)";; esac
|
||||
fi
|
||||
IFS=$'\t' read -r version url sha < <(python3 - "$catalog" "$component" "$platform" <<'PY'
|
||||
import json, re, sys
|
||||
from urllib.parse import urlsplit
|
||||
c = json.load(open(sys.argv[1])); name, platform = sys.argv[2:]
|
||||
e = c['components'][name]['artifacts'].get(platform) or c['components'][name]['artifacts'].get('linux-any')
|
||||
if not re.fullmatch(r'[0-9a-fA-F]{64}', e.get('sha256', '')): raise SystemExit(1)
|
||||
url = e.get('asset_url', '')
|
||||
parsed = urlsplit(url)
|
||||
try: port = parsed.port
|
||||
except ValueError: raise SystemExit(1)
|
||||
if (parsed.scheme != 'https' or parsed.netloc.lower() != 'git.keeper.work' or
|
||||
parsed.username is not None or parsed.password is not None or port is not None or
|
||||
parsed.query or parsed.fragment or '%' in (parsed.path or '') or
|
||||
re.fullmatch(r'/api/packages/[^/]+/generic/[^/]+/[^/]+/[^/]+', parsed.path or '') is None):
|
||||
raise SystemExit(1)
|
||||
print(e['version'], e['asset_url'], e['sha256'].lower(), sep='\t')
|
||||
PY
|
||||
) || die '公开目录缺少带 SHA-256 的组件制品'
|
||||
archive="$INSTALL_DIR/components/$component.tar.zst"; marker_version="$INSTALL_DIR/components/$component.version"; marker_sha="$INSTALL_DIR/components/$component.sha256"
|
||||
if [[ -s $archive && -f $marker_version && -f $marker_sha && $(<"$marker_version") == "$version" && $(<"$marker_sha") == "$sha" && $(sha256sum "$archive" | cut -d' ' -f1) == "$sha" ]]; then
|
||||
printf '%s %s 已安装且完整,跳过下载\n' "$([[ $component == tmm ]] && printf TMM || printf Title)" "$version"; continue
|
||||
fi
|
||||
stage=$(mktemp -d "$INSTALL_DIR/state/.$component.XXXXXX")
|
||||
downloaded="$stage/$component.tar.zst"; tarball="$stage/$component.tar"
|
||||
curl --connect-timeout 10 --max-time 300 --fail --silent --show-error --location --proto '=https' --tlsv1.2 -o "$downloaded" "$url" || die "$component 下载失败"
|
||||
actual=$(sha256sum "$downloaded" | cut -d' ' -f1); [[ $actual == "$sha" ]] || die "$component SHA256 校验失败"
|
||||
zstd -dc "$downloaded" >"$tarball" || die "$component 解压失败"
|
||||
python3 - "$tarball" "$stage/root" <<'PY'
|
||||
import pathlib, sys, tarfile
|
||||
archive, target = sys.argv[1:]; pathlib.Path(target).mkdir()
|
||||
with tarfile.open(archive) as tf:
|
||||
members = tf.getmembers()
|
||||
for member in members:
|
||||
name = member.name.lstrip('./')
|
||||
if not name or name.startswith('/') or '..' in pathlib.PurePosixPath(name).parts or member.issym() or member.islnk() or not (member.isfile() or member.isdir()): raise SystemExit(1)
|
||||
member.name = name
|
||||
tf.extractall(target, members=members, filter='data')
|
||||
PY
|
||||
cp "$downloaded" "$archive.tmp"; printf '%s\n' "$version" >"$marker_version.tmp"; printf '%s\n' "$sha" >"$marker_sha.tmp"
|
||||
mv -f "$archive.tmp" "$archive"; mv -f "$marker_version.tmp" "$marker_version"; mv -f "$marker_sha.tmp" "$marker_sha"; rm -rf "$stage"
|
||||
done
|
||||
exit 0
|
||||
}
|
||||
if [[ ${XYMEDIA_INSTALL_TEST_COMPONENT_CACHE_ONLY:-0} == 1 ]]; then
|
||||
INSTALL_DIR=${XYMEDIA_INSTALL_DIR:?XYMEDIA_INSTALL_DIR is required}; component_cache_test_mode
|
||||
fi
|
||||
INSTALL_TMP_DIR=
|
||||
cleanup_installer_tmp() { persist_installer_log; [[ -z ${INSTALL_TMP_DIR:-} ]] || rm -rf -- "$INSTALL_TMP_DIR"; }
|
||||
RELEASE_ROLLBACK_ACTIVE=0
|
||||
RELEASE_TARGET=
|
||||
RELEASE_BACKUP=
|
||||
cleanup_installer_tmp() {
|
||||
if (( RELEASE_ROLLBACK_ACTIVE )) && [[ -n $RELEASE_BACKUP && -d $RELEASE_BACKUP ]]; then
|
||||
rm -rf -- "$RELEASE_TARGET" 2>/dev/null || true
|
||||
mv -- "$RELEASE_BACKUP" "$RELEASE_TARGET" 2>/dev/null || true
|
||||
ln -sfn "releases/$(basename "$RELEASE_TARGET")" "$INSTALL_DIR/releases/current" 2>/dev/null || true
|
||||
printf '%s\n' '应用 release 失败,已尝试恢复旧 release' >>"${INSTALL_LOG:-/dev/null}"
|
||||
"${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" stop app >/dev/null 2>&1 || true
|
||||
"${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" up -d app >/dev/null 2>&1 || true
|
||||
fi
|
||||
persist_installer_log; [[ -z ${INSTALL_TMP_DIR:-} ]] || rm -rf -- "$INSTALL_TMP_DIR"
|
||||
}
|
||||
trap cleanup_installer_tmp EXIT
|
||||
init_installer_log() {
|
||||
local tmp_parent=${TMPDIR:-/tmp} mode
|
||||
@@ -356,7 +423,6 @@ tty_out=${XYMEDIA_INSTALL_TEST_TTY_OUTPUT:-/dev/tty}
|
||||
emit() {
|
||||
printf '%s\n' "$1"
|
||||
printf '%s\n' "$1" >>"$install_log" 2>/dev/null || true
|
||||
printf '%s\n' "$1" >>"$tty_out" 2>/dev/null || true
|
||||
}
|
||||
|
||||
emit '正在启动 XyMediaVault 应用...'
|
||||
@@ -390,8 +456,13 @@ if [[ ${XYMEDIA_INSTALL_TEST_POST_MIGRATION_ONLY:-0} == 1 ]]; then
|
||||
printf '[安装流程] 已完成数据库迁移,继续启动应用\n' >>"$INSTALL_LOG"
|
||||
printf '数据库初始化完成\n'
|
||||
printf '数据库初始化完成\n' >>"$INSTALL_LOG"
|
||||
if [[ $MENU_PROFILES == *xiaoya-control* ]]; then
|
||||
printf '正在将本机小雅 Controller 同步到管理平台数据库...\n'
|
||||
printf '正在将本机小雅 Controller 同步到管理平台数据库...\n' >>"$INSTALL_LOG"
|
||||
run_visible_logged "${COMPOSE[@]}" --profile migration --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" run --rm -T --no-deps app-migrate bootstrap-controller --config /app/config.yaml </dev/null
|
||||
fi
|
||||
progress '启动 XyMediaVault 服务' || true
|
||||
start_app_after_migration "${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" up -d app
|
||||
start_app_after_migration "${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" up -d --force-recreate app
|
||||
app_start_rc=$?
|
||||
if (( app_start_rc != 0 )); then
|
||||
persist_installer_log || true
|
||||
@@ -954,13 +1025,16 @@ mv -f "$env_tmp" "$INSTALL_DIR/.env"
|
||||
progress '下载公开版本目录(读取 App、TMM、Title 当前版本)'
|
||||
catalog_sep='?'
|
||||
case "$CATALOG_URL" in *\?*) catalog_sep='&';; esac
|
||||
curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 "${CATALOG_URL}${catalog_sep}installer=$INSTALL_NONCE" -o "$INSTALL_DIR/catalog-v1.json"
|
||||
curl --connect-timeout 10 --max-time 60 --fail --silent --show-error --location --proto '=https' --tlsv1.2 "${CATALOG_URL}${catalog_sep}installer=$INSTALL_NONCE" -o "$INSTALL_DIR/catalog-v1.json"
|
||||
python3 - "$INSTALL_DIR/catalog-v1.json" <<'PY' || die 'invalid public catalog'
|
||||
import json, sys
|
||||
import re
|
||||
catalog = json.load(open(sys.argv[1]))
|
||||
assert catalog.get("schema_version") == 1
|
||||
for component in ("app", "tmm", "title", "controller"):
|
||||
assert isinstance(catalog.get("components", {}).get(component, {}).get("artifacts"), dict)
|
||||
for entry in catalog["components"][component]["artifacts"].values():
|
||||
assert isinstance(entry, dict) and re.fullmatch(r"[0-9a-fA-F]{64}", entry.get("sha256", ""))
|
||||
PY
|
||||
case "$(uname -m)" in x86_64|amd64) PLATFORM=linux-amd64;; aarch64|arm64) PLATFORM=linux-arm64;; *) die "unsupported host architecture: $(uname -m)";; esac
|
||||
artifact() {
|
||||
@@ -969,19 +1043,66 @@ import json, sys
|
||||
catalog, component, platform = sys.argv[1:]
|
||||
artifacts = json.load(open(catalog))["components"][component]["artifacts"]
|
||||
entry = artifacts.get(platform) or artifacts.get("linux-any")
|
||||
if not isinstance(entry, dict) or not isinstance(entry.get("version"), str) or not isinstance(entry.get("asset_url"), str):
|
||||
import re
|
||||
if not isinstance(entry, dict) or not isinstance(entry.get("version"), str) or not isinstance(entry.get("asset_url"), str) or not isinstance(entry.get("sha256"), str) or re.fullmatch(r"[0-9a-fA-F]{64}", entry["sha256"]) is None:
|
||||
raise SystemExit(1)
|
||||
print(entry["version"] + "\t" + entry["asset_url"])
|
||||
url = entry["asset_url"]
|
||||
from urllib.parse import urlsplit
|
||||
parsed = urlsplit(url)
|
||||
try:
|
||||
port = parsed.port
|
||||
except ValueError:
|
||||
raise SystemExit(1)
|
||||
if (
|
||||
parsed.scheme != "https"
|
||||
or parsed.netloc.lower() != "git.keeper.work"
|
||||
or parsed.username is not None
|
||||
or parsed.password is not None
|
||||
or parsed.query
|
||||
or parsed.fragment
|
||||
or port is not None
|
||||
or "%" in (parsed.path or "")
|
||||
or re.fullmatch(r"/api/packages/[^/]+/generic/[^/]+/[^/]+/[^/]+", parsed.path or "") is None
|
||||
):
|
||||
raise SystemExit(1)
|
||||
print(entry["version"] + "\t" + url + "\t" + entry["sha256"].lower())
|
||||
PY
|
||||
}
|
||||
download_extract() {
|
||||
local component=$1
|
||||
local version=$2
|
||||
local url=$3
|
||||
local target=$4
|
||||
local archive="$INSTALL_DIR/state/$component-$version.archive"
|
||||
local expected_sha=$4
|
||||
local target=$5
|
||||
local work archive tarball result effective status actual
|
||||
work=$(mktemp -d "$INSTALL_TMP_DIR/${component}.XXXXXX")
|
||||
archive="$work/$component.archive"
|
||||
printf ' 正在下载 %s %s(%s)\n' "$component" "$version" "${url##*/}"
|
||||
curl --fail --show-error --location --proto '=https' --tlsv1.2 --progress-bar "$url" -o "$archive"
|
||||
result=$(curl --connect-timeout 10 --max-time 300 --fail --show-error --location --proto '=https' --tlsv1.2 --progress-bar -o "$archive" -w '%{url_effective}' "$url") || die "$component 下载失败"
|
||||
effective=$result
|
||||
python3 - "$effective" <<'PY' || die "$component 下载重定向不在 canonical Generic Package URL"
|
||||
import re, sys
|
||||
from urllib.parse import urlsplit
|
||||
url = sys.argv[1]
|
||||
parsed = urlsplit(url)
|
||||
try:
|
||||
port = parsed.port
|
||||
except ValueError:
|
||||
raise SystemExit(1)
|
||||
if (
|
||||
parsed.scheme != "https"
|
||||
or parsed.netloc.lower() != "git.keeper.work"
|
||||
or parsed.username is not None
|
||||
or parsed.password is not None
|
||||
or parsed.query
|
||||
or parsed.fragment
|
||||
or port is not None
|
||||
or "%" in (parsed.path or "")
|
||||
or re.fullmatch(r"/api/packages/[^/]+/generic/[^/]+/[^/]+/[^/]+", parsed.path or "") is None
|
||||
):
|
||||
raise SystemExit(1)
|
||||
PY
|
||||
actual=$(sha256sum "$archive" | cut -d' ' -f1); [[ $actual == "$expected_sha" ]] || die "$component SHA256 校验失败"
|
||||
printf ' 正在解压 %s %s\n' "$component" "$version"
|
||||
local tarball="$archive.tar"
|
||||
if [[ $url == *.tar.gz || $url == *.tgz ]]; then gzip -dc "$archive" >"$tarball"; else zstd -dc "$archive" >"$tarball"; fi
|
||||
@@ -998,9 +1119,11 @@ with tarfile.open(archive, 'r:*') as tf:
|
||||
if m.issym() or m.islnk() or not (m.isfile() or m.isdir()):
|
||||
raise SystemExit('archive contains link or special file')
|
||||
m.name = name
|
||||
tf.extractall(target, members=members)
|
||||
tf.extractall(target, members=members, filter='data')
|
||||
PY
|
||||
cp "$archive" "$target/.download.archive"
|
||||
rm -f "$tarball"
|
||||
rm -rf "$work"
|
||||
}
|
||||
install_controller_binary() {
|
||||
local source=$1 target="$INSTALL_DIR/controller/xymedia-edge" staged
|
||||
@@ -1017,9 +1140,9 @@ install_controller_binary() {
|
||||
chmod 755 "$target"
|
||||
}
|
||||
if (( CONTROLLER_ONLY )); then
|
||||
IFS=$'\t' read -r controller_version controller_url < <(artifact controller "$PLATFORM") || die '公开目录没有当前架构的 controller 制品'
|
||||
IFS=$'\t' read -r controller_version controller_url controller_sha < <(artifact controller "$PLATFORM") || die '公开目录没有当前架构的 controller 制品'
|
||||
progress "下载小雅控制器 $controller_version ($PLATFORM)"
|
||||
download_extract controller "$controller_version" "$controller_url" "$INSTALL_DIR/controller-stage"
|
||||
download_extract controller "$controller_version" "$controller_url" "$controller_sha" "$INSTALL_DIR/controller-stage"
|
||||
edge=$(find "$INSTALL_DIR/controller-stage" -type f -name xymedia-edge -perm -u+x -print -quit)
|
||||
[[ -n $edge ]] || die 'controller archive lacks executable xymedia-edge'
|
||||
install_controller_binary "$edge"
|
||||
@@ -1030,27 +1153,50 @@ if (( CONTROLLER_ONLY )); then
|
||||
printf '小雅控制器已安装,监听地址:%s:%s;请按防火墙配置访问,控制器密钥不会显示。\n' "$CONTROLLER_BIND_ADDRESS" "$CONTROLLER_PORT"
|
||||
exit 0
|
||||
fi
|
||||
IFS=$'\t' read -r APP_VERSION APP_URL < <(artifact app "$PLATFORM")
|
||||
APP_STAGE="$INSTALL_DIR/state/app-$APP_VERSION"
|
||||
IFS=$'\t' read -r APP_VERSION APP_URL APP_SHA < <(artifact app "$PLATFORM")
|
||||
APP_STAGE=$(mktemp -d "$INSTALL_TMP_DIR/app.XXXXXX")
|
||||
progress "下载应用包 $APP_VERSION ($PLATFORM)"
|
||||
download_extract app "$APP_VERSION" "$APP_URL" "$APP_STAGE"
|
||||
download_extract app "$APP_VERSION" "$APP_URL" "$APP_SHA" "$APP_STAGE"
|
||||
APP_ROOT="$APP_STAGE/xymediavault-$APP_VERSION-$PLATFORM"
|
||||
[[ -x $APP_ROOT/bin/xymediavault && -x $APP_ROOT/bin/xymedia-supervisor && -d $APP_ROOT/web/dist && -f $APP_ROOT/release.json ]] || die "app package $APP_VERSION lacks the required xymedia-supervisor; use a newer public app package"
|
||||
if [[ -x $APP_ROOT/bin/xymedia-edge ]]; then
|
||||
install_controller_binary "$APP_ROOT/bin/xymedia-edge"
|
||||
fi
|
||||
mkdir -p "$INSTALL_DIR/releases/releases"
|
||||
[[ ! -e "$INSTALL_DIR/releases/releases/$APP_VERSION" ]] && mv "$APP_ROOT" "$INSTALL_DIR/releases/releases/$APP_VERSION"
|
||||
if [[ -e "$INSTALL_DIR/releases/releases/$APP_VERSION" ]]; then
|
||||
progress '停止旧版本应用以替换同版本 release'
|
||||
run_logged "${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" stop app || die '无法停止旧版本应用'
|
||||
fi
|
||||
release_target="$INSTALL_DIR/releases/releases/$APP_VERSION"
|
||||
release_backup="$INSTALL_DIR/releases/.${APP_VERSION}.old.$$"
|
||||
RELEASE_TARGET=$release_target
|
||||
RELEASE_BACKUP=$release_backup
|
||||
[[ ! -L "$release_target" ]] || die 'release 目录不能是符号链接'
|
||||
mv "$APP_ROOT" "$release_target.new.$$" || die '无法准备 release 替换'
|
||||
if [[ -e "$release_target" ]]; then
|
||||
mv "$release_target" "$release_backup" || die '无法备份旧 release'
|
||||
fi
|
||||
mv "$release_target.new.$$" "$release_target" || { mv "$release_backup" "$release_target" 2>/dev/null || true; die '无法安装新 release'; }
|
||||
RELEASE_ROLLBACK_ACTIVE=1
|
||||
ln -sfn "releases/$APP_VERSION" "$INSTALL_DIR/releases/current"
|
||||
if (( ! SKIP_COMPONENTS )); then
|
||||
progress '下载 TMM 与 Title 组件包'
|
||||
for component in tmm title; do
|
||||
platform=$([[ $component == tmm ]] && printf linux-any || printf "$PLATFORM")
|
||||
IFS=$'\t' read -r version url < <(artifact "$component" "$platform")
|
||||
download_extract "$component" "$version" "$url" "$INSTALL_DIR/state/$component-$version"
|
||||
archive="$INSTALL_DIR/state/$component-$version.archive"
|
||||
[[ -s $archive ]] || die "$component archive was not downloaded"
|
||||
component_root="$INSTALL_DIR/state/$component-$version"
|
||||
IFS=$'\t' read -r version url sha < <(artifact "$component" "$platform")
|
||||
archive="$INSTALL_DIR/components/$component.tar.zst"
|
||||
marker_version="$INSTALL_DIR/components/$component.version"
|
||||
marker_sha="$INSTALL_DIR/components/$component.sha256"
|
||||
if [[ -s $archive && -f $marker_version && -f $marker_sha ]] && [[ $(<"$marker_version") == "$version" ]] && [[ $(<"$marker_sha") == "$sha" ]] && [[ $(sha256sum "$archive" | cut -d' ' -f1) == "$sha" ]]; then
|
||||
printf '%s %s 已安装且完整,跳过下载\n' "$([[ $component == tmm ]] && printf TMM || printf Title)" "$version"
|
||||
continue
|
||||
fi
|
||||
component_stage=$(mktemp -d "$INSTALL_TMP_DIR/$component.XXXXXX")
|
||||
download_extract "$component" "$version" "$url" "$sha" "$component_stage"
|
||||
archive_tmp="$INSTALL_TMP_DIR/$component.archive"
|
||||
cp "$component_stage/.download.archive" "$archive_tmp"
|
||||
[[ -s $archive_tmp ]] || die "$component archive was not retained"
|
||||
component_root="$component_stage"
|
||||
if [[ ! -d "$component_root/payload" ]]; then
|
||||
component_root=$(find "$component_root" -mindepth 1 -maxdepth 1 -type d | head -n 1)
|
||||
[[ -n $component_root && -d "$component_root/payload" ]] || die "$component archive has no payload directory"
|
||||
@@ -1061,7 +1207,10 @@ if (( ! SKIP_COMPONENTS )); then
|
||||
else
|
||||
for required in payload/python/bin/python payload/service/entrypoint.py payload/service/app.py payload/service/engine.json payload/NOTICE payload/licenses/guessit-LICENSE.txt payload/licenses/flask-LICENSE.txt payload/licenses/gunicorn-LICENSE.txt; do [[ -f "$component_root/$required" ]] || die "Title archive is missing $required"; done
|
||||
fi
|
||||
cp "$archive" "$INSTALL_DIR/components/$component.tar.zst"
|
||||
cp "$archive_tmp" "$archive.tmp"
|
||||
printf '%s\n' "$version" >"$marker_version.tmp"
|
||||
printf '%s\n' "$sha" >"$marker_sha.tmp"
|
||||
mv -f "$archive.tmp" "$archive"; mv -f "$marker_version.tmp" "$marker_version"; mv -f "$marker_sha.tmp" "$marker_sha"
|
||||
done
|
||||
fi
|
||||
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'
|
||||
@@ -1245,10 +1394,6 @@ run_migration() {
|
||||
set +e
|
||||
run_migration
|
||||
migration_rc=$?
|
||||
printf '数据库迁移退出码:%s\n' "$migration_rc"
|
||||
printf '数据库迁移退出码:%s\n' "$migration_rc" >>"$INSTALL_LOG"
|
||||
printf '[安装流程] 已完成数据库迁移,继续启动应用\n'
|
||||
printf '[安装流程] 已完成数据库迁移,继续启动应用\n' >>"$INSTALL_LOG"
|
||||
if [[ $migration_rc -ne 0 ]]; then
|
||||
exit_code=1
|
||||
persist_installer_log || true
|
||||
@@ -1259,10 +1404,28 @@ if [[ $migration_rc -ne 0 ]]; then
|
||||
fi
|
||||
exit "$exit_code"
|
||||
fi
|
||||
printf '[安装流程] 已完成数据库迁移,继续启动应用\n'
|
||||
printf '[安装流程] 已完成数据库迁移,继续启动应用\n' >>"$INSTALL_LOG"
|
||||
printf '数据库初始化完成\n'
|
||||
printf '数据库初始化完成\n' >>"$INSTALL_LOG"
|
||||
bootstrap_local_controller() {
|
||||
[[ $MENU_PROFILES == *xiaoya-control* ]] || return 0
|
||||
(( REMOTE_MODE == 0 )) || return 0
|
||||
printf '正在将本机小雅 Controller 同步到管理平台数据库...\n'
|
||||
printf '正在将本机小雅 Controller 同步到管理平台数据库...\n' >>"$INSTALL_LOG"
|
||||
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 -T --no-deps app-migrate bootstrap-controller --config /app/config.yaml </dev/null; then
|
||||
printf '本机小雅 Controller 数据库同步失败,安装未完成。\n' >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
if bootstrap_local_controller; then
|
||||
:
|
||||
else
|
||||
persist_installer_log || true
|
||||
exit 1
|
||||
fi
|
||||
progress '启动 XyMediaVault 服务' || true
|
||||
start_app_after_migration "${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" up -d app
|
||||
start_app_after_migration "${COMPOSE[@]}" --project-directory "$INSTALL_DIR" --env-file "$INSTALL_DIR/.env" -f "$INSTALL_DIR/compose.yaml" "${COMPOSE_FUSE[@]}" up -d --force-recreate app
|
||||
app_start_rc=$?
|
||||
if (( app_start_rc != 0 )); then
|
||||
exit_code=1
|
||||
@@ -1305,24 +1468,13 @@ else
|
||||
persist_installer_log || true
|
||||
exit 1
|
||||
fi
|
||||
bootstrap_local_controller() {
|
||||
[[ $MENU_PROFILES == *xiaoya-control* ]] || return 0
|
||||
(( REMOTE_MODE == 0 )) || return 0
|
||||
printf '正在将本机小雅 Controller 同步到管理平台数据库...\n'
|
||||
if ! run_visible_logged docker exec xymedia-app /releases/current/bin/xymediavault bootstrap-controller --config /app/config.yaml; then
|
||||
printf '本机小雅 Controller 数据库同步失败,安装未完成。\n' >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
if bootstrap_local_controller; then
|
||||
:
|
||||
else
|
||||
persist_installer_log || true
|
||||
exit 1
|
||||
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
|
||||
printf '\033[2K\r[%d/%d] 安装完成:XyMediaVault 已就绪\n' "$TOTAL_STEPS" "$TOTAL_STEPS"
|
||||
printf '管理地址:http://127.0.0.1:%s\n' "$API_PORT"
|
||||
management_address=$(printf '%s\n' "$HOST_ADDRESSES_INITIAL" | head -n 1)
|
||||
[[ -n $management_address ]] || management_address=127.0.0.1
|
||||
if [[ $management_address == *:* ]]; then management_address="[$management_address]"; fi
|
||||
printf '管理地址:http://%s:%s\n' "$management_address" "$API_PORT"
|
||||
if [[ $MENU_PROFILES == *xiaoya-control* ]]; then
|
||||
if print_controller_info; then
|
||||
:
|
||||
|
||||
Reference in New Issue
Block a user