This commit is contained in:
okxlin
2026-11-06 01:24:50 +08:00
9 changed files with 118 additions and 7 deletions
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
exec "$SCRIPT_DIR/init.sh"
@@ -1,6 +1,6 @@
services:
bichon:
image: "rustmailer/bichon:1.6.2"
image: "rustmailer/bichon:2.3.0"
container_name: ${CONTAINER_NAME}
restart: always
user: "1000:1000"
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
APP_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$APP_DIR/.env}"
ADMIN_IMAGE="rustmailer/bichon:2.3.0"
read_env_value() {
local key="$1"
local value
[[ -f "$ENV_FILE" ]] || return 0
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
value="${value%$'\r'}"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
"$SCRIPT_DIR/init.sh"
APP_DATA_DIR="${APP_DATA_DIR:-$(read_env_value APP_DATA_DIR)}"
APP_DATA_DIR="${APP_DATA_DIR:-./data}"
if [[ "$APP_DATA_DIR" = /* ]]; then
RESOLVED_DATA_DIR="$(realpath -m -- "$APP_DATA_DIR")"
else
RESOLVED_DATA_DIR="$(realpath -m -- "$APP_DIR/${APP_DATA_DIR#./}")"
case "$RESOLVED_DATA_DIR" in
"$APP_DIR"/*) ;;
*)
printf 'Relative APP_DATA_DIR must remain inside the application directory\n' >&2
exit 1
;;
esac
fi
[[ -d "$RESOLVED_DATA_DIR" ]] || {
printf 'APP_DATA_DIR does not exist: %s\n' "$RESOLVED_DATA_DIR" >&2
exit 1
}
docker_args=(docker run --rm --network none --user 1000:1000 --mount "type=bind,source=$RESOLVED_DATA_DIR,target=/data" --env BICHON_ROOT_DIR=/data)
if [[ -n "${BICHON_INDEX_DIR:-$(read_env_value BICHON_INDEX_DIR)}" ]]; then
docker_args+=(--env "BICHON_INDEX_DIR=${BICHON_INDEX_DIR:-$(read_env_value BICHON_INDEX_DIR)}")
fi
storage_state() {
"${docker_args[@]}" --entrypoint sh "$ADMIN_IMAGE" -c '
set -eu
root=/data
storage="$root/bichon-storage"
version=0
if [ -f "$root/STORAGE_VERSION" ]; then
version="$(cat "$root/STORAGE_VERSION")"
fi
case "$version" in
""|*[!0-9]*) echo INVALID; exit 0 ;;
esac
if [ -d "$storage/blobs" ]; then
if [ "$version" -ge 2 ]; then echo CURRENT; else echo PARTIAL; fi
elif [ -d "$storage" ]; then
if [ "$version" -lt 2 ]; then echo LEGACY; else echo INVALID; fi
elif [ "$version" -eq 0 ]; then
echo CLEAN
else
echo INVALID
fi
'
}
state="$(storage_state)"
case "$state" in
CLEAN|CURRENT)
;;
LEGACY)
if ! command -v script >/dev/null 2>&1; then
printf 'The util-linux script command is required for the Bichon v1 storage migration\n' >&2
exit 1
fi
printf -v admin_command '%q ' "${docker_args[@]}" --interactive --tty --entrypoint bichon-admin "$ADMIN_IMAGE"
{
sleep 0.2
printf '\033[B\033[B\r'
sleep 0.2
printf '/data\r'
sleep 0.2
printf '\r'
sleep 0.2
printf '\r'
sleep 0.2
printf '\r'
} | script -qefc "$admin_command" /dev/null
state="$(storage_state)"
if [[ "$state" != CURRENT ]]; then
printf 'Bichon v1 storage migration did not reach storage version 2 (state: %s)\n' "$state" >&2
exit 1
fi
;;
*)
printf 'Unrecognized or incomplete Bichon storage layout (state: %s); refusing to start the upgraded app\n' "$state" >&2
exit 1
;;
esac
+11 -1
View File
@@ -49,7 +49,17 @@ Bichon is a self-hosted email archiving service written in Rust. It downloads ma
升级或迁移前,应停止 Bichon 并备份 `APP_DATA_DIR` 指向的完整目录以及安装时使用的加密口令。默认 `./data` 位于 1Panel 应用版本目录内,卸载时会随应用目录移除;若需要跨卸载保留归档,请选择独立绝对路径,并预先保证其所有权为 UID/GID `1000:1000`。
本应用只打包稳定版 `1.6.2`。截至本批次适配时,上游 `latest` 已指向 `2.0.0-alpha.1` 预发布镜像,因此没有将 `latest` 作为稳定版本交付。
从 `1.6.2` 升级到 `2.x` 时,升级脚本会调用上游管理工具将 Fjall 邮件对象存储迁移到新格式;现有索引和元数据保持不变。迁移会保留旧存储供验证;确认新版运行正常前,不要手动删除旧数据。`APP_DATA_DIR` 挂载路径保持不变,也支持自定义绝对路径。
本应用提供固定版本 `1.6.2` 和 `2.3.0`。上游 `latest` 可能先于稳定版指向预发布镜像,因此不作为固定稳定版本交付。
## Backup and upgrades
Before upgrading or migrating, stop Bichon and back up the full `APP_DATA_DIR` directory and the encryption password used at installation. The default `./data` is inside the 1Panel app directory and is removed when the app is uninstalled; choose a separate absolute path to retain archives across uninstall, owned by UID/GID `1000:1000`.
When upgrading from `1.6.2` to `2.x`, the upgrade script runs the upstream admin migration from Fjall blob storage to the new format; existing indexes and metadata are left unchanged. The migration keeps the old storage for verification; do not remove it until the upgraded app works. The `APP_DATA_DIR` mount remains unchanged, including custom absolute paths.
The app provides fixed versions `1.6.2` and `2.3.0`. Upstream `latest` may point to a prerelease before a stable release, so it is not used as a fixed stable version.
## 参考资料