Files
ociflab-backup/ociflab-backup.sh
2026-05-07 22:15:58 +08:00

218 lines
6.6 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -euo pipefail
# ============================================================
# OCIFLAB 仓库备份脚本
# 每天从 whitelist.md 拉取仓库列表,克隆/更新仓库,压缩备份
# 需要使用 Access Token 进行认证
# ============================================================
# ---------- 配置区 ----------
GIT_ACCESS_TOKEN="" # 填写你的 Git 访问令牌
WHITELIST_REPO_URL="" # 白名单所在仓库地址 (例: https://git.ociflab.icu/user/repo.git)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKUP_DIR="${SCRIPT_DIR}/backup"
WORK_DIR="${SCRIPT_DIR}/work"
ARCHIVE_DIR="${SCRIPT_DIR}/archives"
WHITELIST_CACHE="${SCRIPT_DIR}/whitelist_cache.md"
RETENTION_DAYS=7
DATE_STAMP="$(date +%Y%m%d)"
# server酱3 配置
SERVERCHAN_UID="" # 填写你的 UID
SERVERCHAN_SENDKEY="" # 填写你的 SendKey
# ---------- 函数区 ----------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
send_warning() {
local title="$1"
local desp="$2"
if [[ -z "${SERVERCHAN_UID}" ]] || [[ -z "${SERVERCHAN_SENDKEY}" ]]; then
log "server酱未配置跳过推送: ${title}"
return 0
fi
local resp
resp=$(curl -s -o /dev/null -w "%{http_code}" --data-urlencode "title=${title}" --data-urlencode "desp=${desp}" "https://${SERVERCHAN_UID}.push.ft07.com/send/${SERVERCHAN_SENDKEY}.send")
if [[ "${resp}" == "200" ]]; then
log "警告推送成功: ${title}"
else
log "警告推送失败(HTTP ${resp}): ${title}"
fi
}
git_with_auth() {
if [[ -n "${GIT_ACCESS_TOKEN}" ]]; then
git -c "http.https://git.ociflab.icu/.extraHeader=Authorization: Bearer ${GIT_ACCESS_TOKEN}" "$@"
else
git "$@"
fi
}
fetch_whitelist() {
local whitelist_repo_dir="${SCRIPT_DIR}/whitelist_repo"
log "正在更新白名单仓库..."
if [[ -d "${whitelist_repo_dir}/.git" ]]; then
# 更新
if ! git_with_auth -C "${whitelist_repo_dir}" pull --ff-only --quiet 2>&1; then
log "更新白名单仓库失败,尝试重新克隆..."
rm -rf "${whitelist_repo_dir}"
fi
fi
if [[ ! -d "${whitelist_repo_dir}/.git" ]]; then
if ! git_with_auth clone --depth 1 --quiet "${WHITELIST_REPO_URL}" "${whitelist_repo_dir}" 2>&1; then
log "克隆白名单仓库失败"
fi
fi
# 读取 whitelist.md 到缓存
if [[ -f "${whitelist_repo_dir}/whitelist.md" ]]; then
cp "${whitelist_repo_dir}/whitelist.md" "${WHITELIST_CACHE}"
log "whitelist.md 已更新"
return 0
fi
log "whitelist.md 获取失败,尝试使用前一天缓存..."
if [[ -f "${SCRIPT_DIR}/whitelist_cache.md.yesterday" ]]; then
cp "${SCRIPT_DIR}/whitelist_cache.md.yesterday" "${WHITELIST_CACHE}"
log "已使用前一天缓存"
return 0
fi
log "前一天缓存也不存在,无法继续"
return 1
}
parse_whitelist() {
grep -Eo 'https://git\.ociflab\.icu/[^[:space:]]+' "${WHITELIST_CACHE}" | sed 's/[[:space:]]*$//'
}
clone_or_pull_repo() {
local repo_url="$1"
local repo_name
repo_name=$(echo "${repo_url}" | sed 's|https://git\.ociflab\.icu/||' | tr '/' '_')
local repo_path="${WORK_DIR}/${repo_name}"
if [[ -d "${repo_path}/.git" ]]; then
log " 更新: ${repo_url}"
if ! git_with_auth -C "${repo_path}" pull --ff-only --quiet 2>&1; then
log " 更新失败: ${repo_url},尝试重新克隆..."
rm -rf "${repo_path}"
if ! git_with_auth clone --depth 1 --quiet "${repo_url}" "${repo_path}" 2>&1; then
log " 重新克隆也失败: ${repo_url}"
return 1
fi
fi
else
log " 克隆: ${repo_url}"
rm -rf "${repo_path}"
if ! git_with_auth clone --depth 1 --quiet "${repo_url}" "${repo_path}" 2>&1; then
log " 克隆失败: ${repo_url}"
return 1
fi
fi
return 0
}
backup_repos() {
local whitelist=("$@")
local total=${#whitelist[@]}
local failed=0
local failed_list=""
log "${total} 个仓库待备份"
for repo_url in "${whitelist[@]}"; do
[[ -z "${repo_url}" ]] && continue
if ! clone_or_pull_repo "${repo_url}"; then
failed=$((failed + 1))
failed_list="${failed_list}${repo_url}\n"
fi
done
# 检查错误率:超过三分之一则发送警告
if [[ ${total} -gt 0 ]]; then
local threshold=$((total / 3))
if [[ ${failed} -gt ${threshold} ]]; then
local warn_desp="备份失败 ${failed}/${total} 个仓库,超过三分之一。\n失败列表:\n${failed_list}"
send_warning "OCIFLAB备份异常 - ${failed}/${total} 仓库失败" "${warn_desp}"
fi
fi
log "备份完成: 成功 $((total - failed)) 个, 失败 ${failed}"
}
create_archive() {
log "正在压缩备份..."
mkdir -p "${ARCHIVE_DIR}"
local archive_name="ociflab-backup-${DATE_STAMP}.zip"
local archive_path="${ARCHIVE_DIR}/${archive_name}"
if [[ -d "${WORK_DIR}" ]] && [[ -n "$(ls -A "${WORK_DIR}" 2>/dev/null)" ]]; then
cd "${WORK_DIR}"
zip -r "${archive_path}" . -q
cd "${SCRIPT_DIR}"
log "压缩完成: ${archive_path}"
else
log "工作目录为空,跳过压缩"
fi
}
cleanup_old_archives() {
log "清理 ${RETENTION_DAYS} 天前的备份..."
find "${ARCHIVE_DIR}" -name "ociflab-backup-*.zip" -type f -mtime +${RETENTION_DAYS} -delete 2>/dev/null || true
log "清理完成"
}
persist_yesterday_whitelist() {
if [[ -f "${WHITELIST_CACHE}" ]]; then
cp "${WHITELIST_CACHE}" "${SCRIPT_DIR}/whitelist_cache.md.yesterday"
fi
}
# ---------- 主流程 ----------
main() {
log "========== OCIFLAB 备份开始 =========="
mkdir -p "${WORK_DIR}" "${ARCHIVE_DIR}"
# 1. 拉取白名单
if ! fetch_whitelist; then
log "无法获取白名单,退出"
send_warning "OCIFLAB备份失败" "无法拉取 whitelist.md 且无前一天缓存"
exit 1
fi
# 2. 解析仓库列表
mapfile -t repos < <(parse_whitelist)
if [[ ${#repos[@]} -eq 0 ]]; then
log "白名单为空,退出"
send_warning "OCIFLAB备份失败" "whitelist.md 中无有效仓库地址"
exit 1
fi
# 3. 克隆/更新仓库
backup_repos "${repos[@]}"
# 4. 压缩归档
create_archive
# 5. 清理旧备份
cleanup_old_archives
# 6. 保存今天的白名单供明天备用
persist_yesterday_whitelist
log "========== OCIFLAB 备份完成 =========="
}
main "$@"