Add automated install and stable updates

This commit is contained in:
Codex
2026-03-16 18:52:51 +08:00
parent 39f4066d85
commit f73e401748
5 changed files with 314 additions and 0 deletions
Executable
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname -- "$SCRIPT_PATH")" && pwd -P)"
INSTALL_MODE="system"
INSTALL_USER="root"
SYSTEMD_DIR="/etc/systemd/system"
DRY_RUN=false
usage() {
cat <<'USAGE'
用法:
./install.sh [--user=NAME] [--mode=system|user] [--dry-run]
说明:
- system 模式会安装到 /etc/systemd/system
- user 模式会安装到 ~/.config/systemd/user
- 不会覆盖已有 env.conf 和 exclude.user.list
- dry-run 只打印将执行的动作,不实际写入 systemd
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--user=*) INSTALL_USER="${1#*=}"; shift;;
--mode=*) INSTALL_MODE="${1#*=}"; shift;;
--dry-run) DRY_RUN=true; shift;;
-h|--help) usage; exit 0;;
*) echo "未知参数:$1" >&2; usage; exit 2;;
esac
done
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "缺少命令:$1" >&2
exit 2
}
}
need_cmd systemctl
need_cmd install
need_cmd sed
if [[ "$INSTALL_MODE" != "system" && "$INSTALL_MODE" != "user" ]]; then
echo "无效 --mode$INSTALL_MODE" >&2
exit 2
fi
if [[ "$INSTALL_MODE" == "system" && "$(id -u)" -ne 0 ]]; then
echo "system 模式需要 root 权限" >&2
exit 2
fi
if [[ "$INSTALL_MODE" == "user" ]]; then
HOME_DIR="$(getent passwd "$INSTALL_USER" | cut -d: -f6)"
if [[ -z "$HOME_DIR" ]]; then
echo "无法找到用户:$INSTALL_USER" >&2
exit 2
fi
SYSTEMD_DIR="${HOME_DIR}/.config/systemd/user"
fi
mkdir -p "${SCRIPT_DIR}/systemd"
if [[ ! -f "${SCRIPT_DIR}/env.conf" ]]; then
if $DRY_RUN; then
echo "[dry-run] 将创建 ${SCRIPT_DIR}/env.conf"
else
cp "${SCRIPT_DIR}/env.conf.example" "${SCRIPT_DIR}/env.conf"
echo "已创建 ${SCRIPT_DIR}/env.conf"
fi
fi
if [[ ! -f "${SCRIPT_DIR}/exclude.user.list" ]]; then
if $DRY_RUN; then
echo "[dry-run] 将创建 ${SCRIPT_DIR}/exclude.user.list"
else
cp "${SCRIPT_DIR}/exclude.user.list.example" "${SCRIPT_DIR}/exclude.user.list"
echo "已创建 ${SCRIPT_DIR}/exclude.user.list"
fi
fi
chmod 755 \
"${SCRIPT_DIR}/backup.sh" \
"${SCRIPT_DIR}/clean_backups.sh" \
"${SCRIPT_DIR}/lib/telegram.sh" \
"${SCRIPT_DIR}/install.sh" \
"${SCRIPT_DIR}/update.sh"
if $DRY_RUN; then
echo "[dry-run] 目标 systemd 目录:$SYSTEMD_DIR"
else
mkdir -p "$SYSTEMD_DIR"
fi
render_unit() {
local src="$1"
local dst="$2"
if $DRY_RUN; then
echo "[dry-run] 将渲染 $(basename "$src") -> $dst"
return 0
fi
sed \
-e "s|__WORKDIR__|${SCRIPT_DIR}|g" \
-e "s|__RUN_USER__|${INSTALL_USER}|g" \
"$src" > "$dst"
if [[ "$INSTALL_MODE" == "user" ]]; then
sed -i '/^User=__RUN_USER__$/d;/^User=/d' "$dst"
fi
}
render_unit "${SCRIPT_DIR}/systemd/backup-obs-update.service" "${SYSTEMD_DIR}/backup-obs-update.service"
render_unit "${SCRIPT_DIR}/systemd/backup-obs-update.timer" "${SYSTEMD_DIR}/backup-obs-update.timer"
if $DRY_RUN; then
echo "[dry-run] 将执行 systemctl daemon-reload"
echo "[dry-run] 将启用 backup-obs-update.timer"
elif [[ "$INSTALL_MODE" == "system" ]]; then
systemctl daemon-reload
systemctl enable --now backup-obs-update.timer
echo "已启用 system timerbackup-obs-update.timer"
echo "查看状态:systemctl status backup-obs-update.timer"
echo "查看日志:journalctl -u backup-obs-update.service -n 100"
else
systemctl --user daemon-reload
systemctl --user enable --now backup-obs-update.timer
echo "已启用 user timerbackup-obs-update.timer"
echo "查看状态:systemctl --user status backup-obs-update.timer"
echo "查看日志:journalctl --user -u backup-obs-update.service -n 100"
fi
+105
View File
@@ -61,6 +61,111 @@ EOF
./clean_backups.sh --retain-days=5
```
## 首次部署
新机器首次部署推荐流程:
```bash
git clone <你的仓库地址> /root/backup_OBS
cd /root/backup_OBS
./install.sh
```
`install.sh` 会自动完成:
- 如果不存在,则创建 `env.conf`
- 如果不存在,则创建 `exclude.user.list`
- 修正脚本执行权限
- 安装 `systemd` 更新任务
- 启用 `backup-obs-update.timer`
默认使用 system 模式,也就是安装到 `/etc/systemd/system`
可选参数:
```bash
./install.sh --mode=system
./install.sh --mode=user --user=root
```
说明:
- `system` 模式需要 root 权限
- `user` 模式会安装到 `~/.config/systemd/user`
- 安装脚本不会覆盖已有的 `env.conf``exclude.user.list`
常用查看命令:
```bash
systemctl status backup-obs-update.timer
journalctl -u backup-obs-update.service -n 100
```
## 自动更新
仓库内提供了一个统一更新脚本:
```bash
./update.sh
```
它会执行:
- `git fetch --tags origin`
- 默认更新 `stable` 分支,或切换到你指定的 tag / 分支
- 修正脚本执行权限
- 自动执行一次 `./backup.sh --dry-run` 自检
也可以手动指定版本:
```bash
./update.sh
./update.sh stable
./update.sh main
./update.sh v1.2.0
```
配合 `systemd timer` 后,机器会定时自动执行 `update.sh`
## GitHub 多机发布流程
推荐流程:
1. 在一台测试机或开发环境修改脚本并提交到 GitHub。
2. 在测试机手动运行:
- `./update.sh main`
- `./backup.sh --dry-run`
- `./backup.sh`
- `./clean_backups.sh --retain-days=100000`
3. 确认备份、清理、Telegram 通知都正常。
4. 打稳定版本标签,例如:
```bash
git tag v1.2.0
git push origin v1.2.0
```
5. 生产机器可以手动执行:
```bash
./update.sh v1.2.0
```
或者让 `systemd` 定时器长期跟随 `stable` 分支。
更稳的做法是:
- `main` 用来持续迭代
- `stable` 用来给其他机器自动更新
- tag 用来留档和回滚
推荐的发布方式:
1. 日常修改提交到 `main`
2. 测试机验证 `main`
3. 验证通过后,把 `main` 合并到 `stable`
4. 其他机器的 `systemd timer` 自动执行 `./update.sh stable`
## 排除规则
脚本会同时读取两个排除文件:
+10
View File
@@ -0,0 +1,10 @@
[Unit]
Description=Update backup_OBS scripts from Git
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=__RUN_USER__
WorkingDirectory=__WORKDIR__
ExecStart=__WORKDIR__/update.sh stable
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Run backup_OBS updater periodically
[Timer]
OnBootSec=10m
OnUnitActiveSec=1h
Persistent=true
Unit=backup-obs-update.service
[Install]
WantedBy=timers.target
Executable
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname -- "$SCRIPT_PATH")" && pwd -P)"
cd "$SCRIPT_DIR"
usage() {
cat <<'USAGE'
用法:
./update.sh [branch-or-tag]
说明:
- 不带参数时,默认更新 stable 分支
- 带参数时,可以切换到指定分支或 tag
- 更新后会自动执行一次 ./backup.sh --dry-run 自检
USAGE
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "缺少命令:$1" >&2
exit 2
}
}
need_cmd git
need_cmd bash
TARGET_REF="${1:-}"
if [[ -z "$TARGET_REF" ]]; then
TARGET_REF="stable"
fi
git fetch --tags origin
if git show-ref --verify --quiet "refs/tags/${TARGET_REF}"; then
git checkout "${TARGET_REF}"
else
git checkout "${TARGET_REF}"
git pull --ff-only origin "${TARGET_REF}"
fi
chmod 755 \
"${SCRIPT_DIR}/backup.sh" \
"${SCRIPT_DIR}/clean_backups.sh" \
"${SCRIPT_DIR}/lib/telegram.sh" \
"${SCRIPT_DIR}/install.sh" \
"${SCRIPT_DIR}/update.sh"
bash "${SCRIPT_DIR}/backup.sh" --dry-run