feat: add friendly installer progress logs

This commit is contained in:
Qiufeng
2026-09-01 11:42:25 +08:00
parent 4b9c80cc3a
commit 4395317651
4 changed files with 101 additions and 6 deletions
+28
View File
@@ -59,6 +59,34 @@ curl --proto '=https' --tlsv1.2 -fsSL https://git.awaioi.com/awaioi/TallyNote/ra
脚本会从公开仓库的 latest Release 获取当前架构归档和 `SHA256SUMS`,并在安装前始终校验 SHA-256。也可以通过 `TALLYNOTE_REPOSITORY_URL`、`TALLYNOTE_RELEASE_API_URL`、`TALLYNOTE_RELEASE_ALLOWED_HOSTS` 和 `--release-base-url` 指向自己的仓库或受信 CDN。需要固定版本或预览时,仍可使用 `TALLYNOTE_VERSION`、`--version` 或 `--dry-run` 等高级选项。 脚本会从公开仓库的 latest Release 获取当前架构归档和 `SHA256SUMS`,并在安装前始终校验 SHA-256。也可以通过 `TALLYNOTE_REPOSITORY_URL`、`TALLYNOTE_RELEASE_API_URL`、`TALLYNOTE_RELEASE_ALLOWED_HOSTS` 和 `--release-base-url` 指向自己的仓库或受信 CDN。需要固定版本或预览时,仍可使用 `TALLYNOTE_VERSION`、`--version` 或 `--dry-run` 等高级选项。
安装过程会持续输出带统一前缀的阶段日志,不会在下载、校验或启动服务时静默等待。交互式 SSH/终端中下载还会显示 curl 进度条;非交互式运行(例如 CI)只输出干净的阶段日志。典型输出如下(版本号、架构和耗时会按实际环境变化):
```text
tallynote installer: [阶段] 检查运行环境、权限和目标架构
tallynote installer: [完成] 运行环境可用:x64/glibc
tallynote installer: [阶段] 从 Release API 获取最新版本
tallynote installer: [完成] 已解析最新版本:1.1.2
tallynote installer: [完成] Release 下载地址已准备
tallynote installer: [阶段] 获取发布包:tallynote-1.1.2-linux-x64-glibc.tar.gz
tallynote installer: [完成] 发布包已下载并通过大小限制
tallynote installer: [阶段] 获取 SHA-256 校验清单
tallynote installer: [完成] SHA-256 校验清单已准备
tallynote installer: [阶段] 校验 SHA-256 和发布签名
tallynote installer: [完成] 发布包校验通过
tallynote installer: [阶段] 解包、校验包结构并原子切换到版本 1.1.2
tallynote installer: [完成] 版本 1.1.2 已切换为当前版本
tallynote installer: [阶段] 安装 systemd 单元、更新辅助程序和卸载器
tallynote installer: [完成] systemd 单元、更新辅助程序和卸载器已安装
tallynote installer: [阶段] 重新加载 systemd 并启动 TallyNote
tallynote installer: [完成] TallyNote 服务已启用并启动
tallynote installer: [阶段] 清理旧版本并完成安装
tallynote installer: [完成] 旧版本清理完成
tallynote installer: [完成] 安装完成:TallyNote 1.1.2
tallynote installer: 查看服务状态:systemctl status tallynote.service
```
任何阶段失败都会以 `tallynote installer:` 前缀写出原因并立即停止;不会把不完整版本切换为当前版本。
如需额外启用签名校验,在环境中设置 `TALLYNOTE_INSTALL_REQUIRE_SIGNATURE=true` 并提供 `--signing-key`;不设置时不会要求公钥或 `SHA256SUMS.sig`。 如需额外启用签名校验,在环境中设置 `TALLYNOTE_INSTALL_REQUIRE_SIGNATURE=true` 并提供 `--signing-key`;不设置时不会要求公钥或 `SHA256SUMS.sig`。
已有安装默认拒绝降级到不高于当前版本;确需回退时显式使用 `--allow-downgrade`,正常更新不会覆盖当前或更高版本。 已有安装默认拒绝降级到不高于当前版本;确需回退时显式使用 `--allow-downgrade`,正常更新不会覆盖当前或更高版本。
+21
View File
@@ -40,6 +40,27 @@ curl --proto '=https' --tlsv1.2 -fsSL https://git.awaioi.com/awaioi/TallyNote/ra
脚本会从 `https://git.awaioi.com/awaioi/TallyNote/releases/download/v<版本>/` 下载当前架构归档和 `SHA256SUMS`,限制 HTTPS 重定向只能落在配置的受信主机,校验压缩/展开大小、条目数量、路径和特殊文件,再原子切换 `/opt/tallynote/current`。自定义仓库时同时设置 `TALLYNOTE_REPOSITORY_URL`、`TALLYNOTE_RELEASE_API_URL` 和 `TALLYNOTE_RELEASE_ALLOWED_HOSTS`;若使用独立 CDN,必须把 CDN 主机显式加入白名单。需要预览时显式加 `--dry-run`,需要固定版本时使用 `--version`。 脚本会从 `https://git.awaioi.com/awaioi/TallyNote/releases/download/v<版本>/` 下载当前架构归档和 `SHA256SUMS`,限制 HTTPS 重定向只能落在配置的受信主机,校验压缩/展开大小、条目数量、路径和特殊文件,再原子切换 `/opt/tallynote/current`。自定义仓库时同时设置 `TALLYNOTE_REPOSITORY_URL`、`TALLYNOTE_RELEASE_API_URL` 和 `TALLYNOTE_RELEASE_ALLOWED_HOSTS`;若使用独立 CDN,必须把 CDN 主机显式加入白名单。需要预览时显式加 `--dry-run`,需要固定版本时使用 `--version`。
安装器会在每个关键阶段输出统一格式的日志,便于在 SSH 或 systemd 安装会话中确认进度;交互式终端下载时还会显示 curl 进度条,CI 或日志重定向时则保持纯文本输出:
```text
tallynote installer: [阶段] 检查运行环境、权限和目标架构
tallynote installer: [阶段] 从 Release API 获取最新版本
tallynote installer: [阶段] 获取发布包:tallynote-<版本>-linux-x64-glibc.tar.gz
tallynote installer: [阶段] 获取 SHA-256 校验清单
tallynote installer: [阶段] 校验 SHA-256 和发布签名
tallynote installer: [阶段] 解包、校验包结构并原子切换到版本 <版本>
tallynote installer: [完成] 版本 <版本> 已切换为当前版本
tallynote installer: [阶段] 安装 systemd 单元、更新辅助程序和卸载器
tallynote installer: [完成] systemd 单元、更新辅助程序和卸载器已安装
tallynote installer: [阶段] 重新加载 systemd 并启动 TallyNote
tallynote installer: [完成] TallyNote 服务已启用并启动
tallynote installer: [阶段] 清理旧版本并完成安装
tallynote installer: [完成] 旧版本清理完成
tallynote installer: [完成] 安装完成:TallyNote <版本>
```
每个阶段完成时会输出 `[完成]`;错误会立即以 `tallynote installer:` 前缀输出,不会静默等待或切换半成品版本。
如需启用签名校验,设置 `TALLYNOTE_INSTALL_REQUIRE_SIGNATURE=true` 并提供 `--signing-key`;后台更新同样可通过 `TALLYNOTE_UPDATE_REQUIRE_SIGNATURE=true` 和 `TALLYNOTE_UPDATE_PUBLIC_KEY_FILE` 开启。默认关闭签名要求,方便公开自维护仓库直接更新。 如需启用签名校验,设置 `TALLYNOTE_INSTALL_REQUIRE_SIGNATURE=true` 并提供 `--signing-key`;后台更新同样可通过 `TALLYNOTE_UPDATE_REQUIRE_SIGNATURE=true` 和 `TALLYNOTE_UPDATE_PUBLIC_KEY_FILE` 开启。默认关闭签名要求,方便公开自维护仓库直接更新。
已有安装默认拒绝安装不高于当前版本的 release;只有在明确执行 `--allow-downgrade`(或设置 `TALLYNOTE_ALLOW_DOWNGRADE=true`)时才允许回退版本。 已有安装默认拒绝安装不高于当前版本的 release;只有在明确执行 `--allow-downgrade`(或设置 `TALLYNOTE_ALLOW_DOWNGRADE=true`)时才允许回退版本。
+49 -6
View File
@@ -69,6 +69,8 @@ EOF
} }
die() { printf 'tallynote installer: %s\n' "$*" >&2; exit 1; } die() { printf 'tallynote installer: %s\n' "$*" >&2; exit 1; }
log() { printf 'tallynote installer: %s\n' "$*"; } log() { printf 'tallynote installer: %s\n' "$*"; }
stage() { log "[阶段] $*"; }
stage_done() { log "[完成] $*"; }
[[ "$REQUIRE_SIGNATURE" == true || "$REQUIRE_SIGNATURE" == false ]] || die 'TALLYNOTE_INSTALL_REQUIRE_SIGNATURE 必须是 true 或 false' [[ "$REQUIRE_SIGNATURE" == true || "$REQUIRE_SIGNATURE" == false ]] || die 'TALLYNOTE_INSTALL_REQUIRE_SIGNATURE 必须是 true 或 false'
[[ "$ALLOW_DOWNGRADE" == true || "$ALLOW_DOWNGRADE" == false ]] || die 'TALLYNOTE_ALLOW_DOWNGRADE 必须是 true 或 false' [[ "$ALLOW_DOWNGRADE" == true || "$ALLOW_DOWNGRADE" == false ]] || die 'TALLYNOTE_ALLOW_DOWNGRADE 必须是 true 或 false'
@@ -197,15 +199,23 @@ assert_allowed_url() {
download() { download() {
local url=$1 out=$2 max_bytes=${3:-$((MAX_RELEASE_MB * 1024 * 1024))} local url=$1 out=$2 max_bytes=${3:-$((MAX_RELEASE_MB * 1024 * 1024))}
local current="$url" headers status location actual origin scheme authority local current="$url" headers status location actual origin scheme authority
local -a curl_args=(--proto '=https' --tlsv1.2 --fail --show-error --max-redirs 0
--connect-timeout "$CONNECT_TIMEOUT" --max-time "$MAX_TIME" --max-filesize "$max_bytes"
--retry 2 --retry-connrefused)
# Keep CI and journal output clean, while showing curl's standard progress
# bar during an interactive SSH/terminal installation.
if [[ -t 2 ]]; then
curl_args+=(--progress-bar)
else
curl_args+=(--silent)
fi
require_https "$url" require_https "$url"
assert_allowed_url "$url" assert_allowed_url "$url"
[[ ! -L "$out" && ! -e "$out" ]] || die "download destination already exists: $out" [[ ! -L "$out" && ! -e "$out" ]] || die "download destination already exists: $out"
for _redirect in 0 1 2 3; do for _redirect in 0 1 2 3; do
headers="${out}.headers-${RANDOM}-$$" headers="${out}.headers-${RANDOM}-$$"
status=$(curl --proto '=https' --tlsv1.2 --fail --silent --show-error --max-redirs 0 \ status=$(curl "${curl_args[@]}" --output "$out" --dump-header "$headers" \
--connect-timeout "$CONNECT_TIMEOUT" --max-time "$MAX_TIME" --max-filesize "$max_bytes" \ --write-out '%{http_code}' "$current") || status=000
--retry 2 --retry-connrefused --output "$out" --dump-header "$headers" \
--write-out '%{http_code}' "$current" 2>/dev/null) || status=000
if [[ "$status" =~ ^2[0-9][0-9]$ ]]; then if [[ "$status" =~ ^2[0-9][0-9]$ ]]; then
rm -f -- "$headers" rm -f -- "$headers"
break break
@@ -715,6 +725,7 @@ prune_releases() {
} }
main() { main() {
stage '检查运行环境、权限和目标架构'
# These variables are useful for isolated tests, but a root install must # These variables are useful for isolated tests, but a root install must
# never execute an untrusted PATH entry supplied through sudo's environment. # never execute an untrusted PATH entry supplied through sudo's environment.
if (( APPLY )) || [[ -n "${TALLYNOTE_UNAME_BIN+x}" ]]; then if (( APPLY )) || [[ -n "${TALLYNOTE_UNAME_BIN+x}" ]]; then
@@ -737,14 +748,21 @@ main() {
# TALLYNOTE_RELEASE_ALLOWED_HOSTS when the operator has reviewed it. # TALLYNOTE_RELEASE_ALLOWED_HOSTS when the operator has reviewed it.
append_allowed_host "$(url_host "$RELEASE_API_URL")" append_allowed_host "$(url_host "$RELEASE_API_URL")"
append_allowed_host "$(url_host "$REPOSITORY_URL")" append_allowed_host "$(url_host "$REPOSITORY_URL")"
stage_done "运行环境可用:${TALLYNOTE_ARCH}/${TALLYNOTE_LIBC}"
if [[ "$VERSION" == "latest" ]]; then if [[ "$VERSION" == "latest" ]]; then
if (( ! APPLY )); then if (( ! APPLY )); then
[[ -z "$RELEASE_BASE_URL" ]] || require_https "$RELEASE_BASE_URL" [[ -z "$RELEASE_BASE_URL" ]] || require_https "$RELEASE_BASE_URL"
stage '预览最新版本解析(dry-run 不访问 Release)'
log 'version: latest (release lookup skipped in dry-run)' log 'version: latest (release lookup skipped in dry-run)'
log 'dry-run: pass --version VERSION to preview an exact artifact' log 'dry-run: pass --version VERSION to preview an exact artifact'
stage_done 'dry-run 预览完成:不会下载、解包或修改 systemd'
return 0 return 0
fi fi
stage '从 Release API 获取最新版本'
resolve_latest_version resolve_latest_version
stage_done "已解析最新版本:${VERSION#v}"
else
stage "使用指定版本:${VERSION#v}"
fi fi
validate_semver "$VERSION" || die 'version must be a semantic version (for example 1.2.3)' validate_semver "$VERSION" || die 'version must be a semantic version (for example 1.2.3)'
VERSION=${VERSION#v} VERSION=${VERSION#v}
@@ -755,15 +773,21 @@ main() {
die "拒绝安装不高于当前版本的 release:当前 $current_version,候选 $VERSION(如确需降级请使用 --allow-downgrade)" die "拒绝安装不高于当前版本的 release:当前 $current_version,候选 $VERSION(如确需降级请使用 --allow-downgrade)"
fi fi
fi fi
stage '准备 Release 下载地址和发布包'
release_urls release_urls
local artifact archive checksum signature artifact_url work release_dir local artifact archive checksum signature artifact_url work release_dir
artifact=${RELEASE_FILE:+$(basename -- "$RELEASE_FILE")} artifact=${RELEASE_FILE:+$(basename -- "$RELEASE_FILE")}
artifact=${artifact:-tallynote-${VERSION}-linux-${TALLYNOTE_ARCH}-${TALLYNOTE_LIBC}.tar.gz} artifact=${artifact:-tallynote-${VERSION}-linux-${TALLYNOTE_ARCH}-${TALLYNOTE_LIBC}.tar.gz}
[[ "$artifact" =~ ^[A-Za-z0-9][A-Za-z0-9._+\-]*\.(tar\.gz|tgz|tar)$ ]] || die 'release 文件名无效' [[ "$artifact" =~ ^[A-Za-z0-9][A-Za-z0-9._+\-]*\.(tar\.gz|tgz|tar)$ ]] || die 'release 文件名无效'
artifact_url="$RELEASE_BASE_URL/$artifact" artifact_url="$RELEASE_BASE_URL/$artifact"
stage_done 'Release 下载地址已准备'
log "platform: ${TALLYNOTE_ARCH}/${TALLYNOTE_LIBC}; release: ${VERSION#v}" log "platform: ${TALLYNOTE_ARCH}/${TALLYNOTE_LIBC}; release: ${VERSION#v}"
log "layout: $PREFIX/releases + atomic $PREFIX/current; data: $DATA_DIR" log "layout: $PREFIX/releases + atomic $PREFIX/current; data: $DATA_DIR"
if (( ! APPLY )); then log 'dry-run: no download, extraction, or systemd changes'; return 0; fi if (( ! APPLY )); then
log 'dry-run: no download, extraction, or systemd changes'
stage_done 'dry-run 预览完成:不会下载、解包或修改 systemd'
return 0
fi
[[ "$("$UNAME_BIN" -s)" == Linux ]] || die '安装器只允许在 Linux 上执行' [[ "$("$UNAME_BIN" -s)" == Linux ]] || die '安装器只允许在 Linux 上执行'
[[ $EUID -eq 0 ]] || die '安装必须以 root 运行' [[ $EUID -eq 0 ]] || die '安装必须以 root 运行'
for command_name in curl sha256sum tar install sed awk find systemctl; do for command_name in curl sha256sum tar install sed awk find systemctl; do
@@ -777,6 +801,7 @@ main() {
INSTALL_BACKUP_DIR="$work/original" INSTALL_BACKUP_DIR="$work/original"
trap rollback_install_if_needed EXIT trap rollback_install_if_needed EXIT
archive="$work/$artifact" archive="$work/$artifact"
stage "获取发布包:$artifact"
if [[ -n "$RELEASE_FILE" && -f "$RELEASE_FILE" && ! -L "$RELEASE_FILE" ]]; then if [[ -n "$RELEASE_FILE" && -f "$RELEASE_FILE" && ! -L "$RELEASE_FILE" ]]; then
cp -- "$RELEASE_FILE" "$archive" cp -- "$RELEASE_FILE" "$archive"
chmod 600 "$archive" chmod 600 "$archive"
@@ -785,8 +810,10 @@ main() {
[[ -z "$RELEASE_FILE" ]] || die '本地 release 文件不存在或是符号链接' [[ -z "$RELEASE_FILE" ]] || die '本地 release 文件不存在或是符号链接'
download "$artifact_url" "$archive" download "$artifact_url" "$archive"
fi fi
stage_done '发布包已下载并通过大小限制'
checksum="$work/SHA256SUMS" checksum="$work/SHA256SUMS"
SHA256_URL=${SHA256_URL:-$RELEASE_BASE_URL/SHA256SUMS} SHA256_URL=${SHA256_URL:-$RELEASE_BASE_URL/SHA256SUMS}
stage '获取 SHA-256 校验清单'
if [[ -n "$SHA256_FILE" && -f "$SHA256_FILE" && ! -L "$SHA256_FILE" ]]; then if [[ -n "$SHA256_FILE" && -f "$SHA256_FILE" && ! -L "$SHA256_FILE" ]]; then
cp -- "$SHA256_FILE" "$checksum" cp -- "$SHA256_FILE" "$checksum"
chmod 600 "$checksum" chmod 600 "$checksum"
@@ -795,9 +822,11 @@ main() {
[[ -z "$SHA256_FILE" ]] || die '本地 SHA256SUMS 文件不存在或是符号链接' [[ -z "$SHA256_FILE" ]] || die '本地 SHA256SUMS 文件不存在或是符号链接'
download "$SHA256_URL" "$checksum" $((2 * 1024 * 1024)) download "$SHA256_URL" "$checksum" $((2 * 1024 * 1024))
fi fi
stage_done 'SHA-256 校验清单已准备'
SIGNING_KEY=${SIGNING_KEY:-$UPDATE_PUBLIC_KEY_FILE} SIGNING_KEY=${SIGNING_KEY:-$UPDATE_PUBLIC_KEY_FILE}
signature='' signature=''
if [[ "$REQUIRE_SIGNATURE" == true || -n "$SIGNATURE_URL" || -n "$SIGNING_KEY" ]]; then if [[ "$REQUIRE_SIGNATURE" == true || -n "$SIGNATURE_URL" || -n "$SIGNING_KEY" ]]; then
stage '获取发布签名'
if [[ "$SIGNATURE_FORMAT" == gpg ]]; then if [[ "$SIGNATURE_FORMAT" == gpg ]]; then
SIGNATURE_URL=${SIGNATURE_URL:-$RELEASE_BASE_URL/$artifact.asc} SIGNATURE_URL=${SIGNATURE_URL:-$RELEASE_BASE_URL/$artifact.asc}
signature="$work/$artifact.asc" signature="$work/$artifact.asc"
@@ -806,10 +835,14 @@ main() {
signature="$work/SHA256SUMS.sig" signature="$work/SHA256SUMS.sig"
fi fi
download "$SIGNATURE_URL" "$signature" $((64 * 1024)) download "$SIGNATURE_URL" "$signature" $((64 * 1024))
stage_done '发布签名已准备'
fi fi
stage '校验 SHA-256 和发布签名'
verify_archive "$archive" "$checksum" "$signature" "$SIGNING_KEY" verify_archive "$archive" "$checksum" "$signature" "$SIGNING_KEY"
stage_done '发布包校验通过'
[[ "$PREFIX" = /* && "$DATA_DIR" = /* && "$CONFIG_DIR" = /* ]] || die '安装、数据和配置目录必须是绝对路径' [[ "$PREFIX" = /* && "$DATA_DIR" = /* && "$CONFIG_DIR" = /* ]] || die '安装、数据和配置目录必须是绝对路径'
[[ ! -L "$DATA_DIR" && ! -L "$PREFIX" && ! -L "$CONFIG_DIR" ]] || die 'installation/data/config paths must not be symlinks' [[ ! -L "$DATA_DIR" && ! -L "$PREFIX" && ! -L "$CONFIG_DIR" ]] || die 'installation/data/config paths must not be symlinks'
stage '停止旧服务并准备安装、配置和数据目录'
id tallynote >/dev/null 2>&1 || useradd --system --user-group --home-dir "$DATA_DIR" --shell /usr/sbin/nologin tallynote id tallynote >/dev/null 2>&1 || useradd --system --user-group --home-dir "$DATA_DIR" --shell /usr/sbin/nologin tallynote
backup_install_files "$INSTALL_BACKUP_DIR" backup_install_files "$INSTALL_BACKUP_DIR"
stop_existing_services stop_existing_services
@@ -821,10 +854,14 @@ main() {
if [[ -e "$CONFIG_DIR/tallynote.env" ]]; then if [[ -e "$CONFIG_DIR/tallynote.env" ]]; then
validate_existing_env "$CONFIG_DIR/tallynote.env" validate_existing_env "$CONFIG_DIR/tallynote.env"
fi fi
stage_done '目录、权限和旧服务状态已准备'
stage "解包、校验包结构并原子切换到版本 ${VERSION#v}"
install_release "$archive" "$VERSION" install_release "$archive" "$VERSION"
stage_done "版本 ${VERSION#v} 已切换为当前版本"
release_dir="$PREFIX/releases/$VERSION" release_dir="$PREFIX/releases/$VERSION"
[[ -f "$release_dir/systemd/tallynote.service" && -f "$release_dir/systemd/tallynote-update.service" && -f "$release_dir/systemd/tallynote-update.path" ]] || die 'release package is missing systemd unit files' [[ -f "$release_dir/systemd/tallynote.service" && -f "$release_dir/systemd/tallynote-update.service" && -f "$release_dir/systemd/tallynote-update.path" ]] || die 'release package is missing systemd unit files'
[[ -f "$release_dir/systemd/tallynote.env.example" && -f "$release_dir/scripts/tallynote-update-runner.sh" && -x "$release_dir/uninstall.sh" ]] || die 'release package is missing update/uninstall support files' [[ -f "$release_dir/systemd/tallynote.env.example" && -f "$release_dir/scripts/tallynote-update-runner.sh" && -x "$release_dir/uninstall.sh" ]] || die 'release package is missing update/uninstall support files'
stage '安装 systemd 单元、更新辅助程序和卸载器'
install -d -m 755 /usr/local/libexec /etc/systemd/system install -d -m 755 /usr/local/libexec /etc/systemd/system
local unit_tmp local unit_tmp
unit_tmp=$(mktemp -d) unit_tmp=$(mktemp -d)
@@ -879,15 +916,21 @@ main() {
printf 'TALLYNOTE_UPDATE_PUBLIC_KEY_FILE=%s\n' "$CONFIG_DIR/update-signing-key.pub" >> "$CONFIG_DIR/tallynote.env" printf 'TALLYNOTE_UPDATE_PUBLIC_KEY_FILE=%s\n' "$CONFIG_DIR/update-signing-key.pub" >> "$CONFIG_DIR/tallynote.env"
fi fi
fi fi
stage_done 'systemd 单元、更新辅助程序和卸载器已安装'
stage '重新加载 systemd 并启动 TallyNote'
chown root:root "$CONFIG_DIR/tallynote.env" chown root:root "$CONFIG_DIR/tallynote.env"
chmod 640 "$CONFIG_DIR/tallynote.env" chmod 640 "$CONFIG_DIR/tallynote.env"
systemctl daemon-reload systemctl daemon-reload
systemctl enable --now tallynote.service tallynote-update.path systemctl enable --now tallynote.service tallynote-update.path
stage_done 'TallyNote 服务已启用并启动'
stage '清理旧版本并完成安装'
prune_releases prune_releases
stage_done '旧版本清理完成'
INSTALL_COMMITTED=1 INSTALL_COMMITTED=1
trap - EXIT trap - EXIT
rm -rf -- "$INSTALL_WORK_DIR" 2>/dev/null || true rm -rf -- "$INSTALL_WORK_DIR" 2>/dev/null || true
INSTALL_WORK_DIR='' INSTALL_WORK_DIR=''
log 'installed; inspect with systemctl status tallynote.service' stage_done "安装完成:TallyNote ${VERSION#v}"
log '查看服务状态:systemctl status tallynote.service'
} }
main "$@" main "$@"
+3
View File
@@ -4,8 +4,11 @@ root=$(cd "$(dirname "$0")/.." && pwd)
bash -n "$root/install.sh" "$root/scripts/tallynote-update.sh" bash -n "$root/install.sh" "$root/scripts/tallynote-update.sh"
output=$(bash "$root/install.sh" --dry-run --release-base-url https://releases.example.test/releases) output=$(bash "$root/install.sh" --dry-run --release-base-url https://releases.example.test/releases)
grep -q 'dry-run' <<<"$output" grep -q 'dry-run' <<<"$output"
grep -q '\[阶段\] 检查运行环境' <<<"$output"
grep -q '\[完成\] dry-run 预览完成' <<<"$output"
output=$(bash "$root/install.sh" --dry-run --version 1.2.3 --release-base-url https://releases.example.test/releases) output=$(bash "$root/install.sh" --dry-run --version 1.2.3 --release-base-url https://releases.example.test/releases)
grep -q 'release: 1.2.3' <<<"$output" grep -q 'release: 1.2.3' <<<"$output"
grep -q '\[阶段\] 使用指定版本:1.2.3' <<<"$output"
if bash "$root/install.sh" --dry-run --release-base-url http://insecure.example.test/releases >/dev/null 2>&1; then if bash "$root/install.sh" --dry-run --release-base-url http://insecure.example.test/releases >/dev/null 2>&1; then
echo 'expected non-HTTPS URL to fail' >&2 echo 'expected non-HTTPS URL to fail' >&2
exit 1 exit 1