Files
ociflab-backup/ociflab-backup.sh
2026-05-07 21:33:36 +08:00

193 lines
5.7 KiB
Bash
Raw 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 拉取仓库列表,克隆/更新仓库,压缩备份
# ============================================================
# ---------- 配置区 ----------
WHITELIST_URL=""
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
}
fetch_whitelist() {
log "正在拉取 whitelist.md ..."
local http_code
http_code=$(curl -s -o "${WHITELIST_CACHE}" -w "%{http_code}" --connect-timeout 10 --max-time 30 "${WHITELIST_URL}")
if [[ "${http_code}" == "200" ]] && [[ -s "${WHITELIST_CACHE}" ]]; then
log "whitelist.md 拉取成功 (HTTP ${http_code})"
return 0
fi
log "whitelist.md 拉取失败 (HTTP ${http_code}),尝试使用前一天缓存..."
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 -C "${repo_path}" pull --ff-only 2>&1; then
log " 更新失败: ${repo_url},尝试重新克隆..."
rm -rf "${repo_path}"
if ! git clone --depth 1 "${repo_url}" "${repo_path}" 2>&1; then
log " 重新克隆也失败: ${repo_url}"
return 1
fi
fi
else
log " 克隆: ${repo_url}"
rm -rf "${repo_path}"
if ! git clone --depth 1 "${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 "$@"