|
|
#!/bin/sh |
|
|
|
|
|
|
|
|
set -e |
|
|
|
|
|
TS(){ date "+%Y-%m-%d %H:%M:%S"; } |
|
|
log(){ echo "[$(TS)] [hf-backup] $*" >&2; } |
|
|
|
|
|
HF_TOKEN="${HF_TOKEN:-}" |
|
|
DATASET_ID="${DATASET_ID:-}" |
|
|
|
|
|
|
|
|
SYNC_INTERVAL="${SYNC_INTERVAL:-3600}" |
|
|
MAX_BACKUPS="${MAX_BACKUPS:-10}" |
|
|
BACKUP_PREFIX="${BACKUP_PREFIX:-crs_backup}" |
|
|
|
|
|
|
|
|
BACKUP_PATHS="${BACKUP_PATHS:-app/data,app/data/redis}" |
|
|
|
|
|
BACKUP_EXCLUDE="${BACKUP_EXCLUDE:-app/data/init.json,app/data/users.json,*.tmp,*.cache,**/.DS_Store}" |
|
|
|
|
|
HF_PY="/app/tools/hf_backup.py" |
|
|
TMP_DIR="/tmp/crs_backup" |
|
|
mkdir -p "${TMP_DIR}" |
|
|
|
|
|
need_hf() { |
|
|
if [ -z "$HF_TOKEN" ] || [ -z "$DATASET_ID" ]; then |
|
|
log "HF_TOKEN/DATASET_ID 缺失,无法使用备份功能"; exit 1 |
|
|
fi |
|
|
} |
|
|
|
|
|
mk_archive() { |
|
|
ts="$(date +%Y%m%d_%H%M%S)" |
|
|
archive="${TMP_DIR}/${BACKUP_PREFIX}_${ts}.tar.gz" |
|
|
|
|
|
|
|
|
set -- -czf "$archive" |
|
|
|
|
|
|
|
|
IFS=','; for x in $BACKUP_EXCLUDE; do |
|
|
[ -z "$x" ] && continue |
|
|
case "$x" in /*) x=${x#/} ;; esac |
|
|
set -- "$@" --exclude="$x" |
|
|
done; unset IFS |
|
|
|
|
|
|
|
|
set -- "$@" -C / |
|
|
|
|
|
|
|
|
IFS=','; for p in $BACKUP_PATHS; do |
|
|
[ -z "$p" ] && continue |
|
|
case "$p" in /*) p=${p#/} ;; esac |
|
|
set -- "$@" "$p" |
|
|
done; unset IFS |
|
|
|
|
|
log "创建归档:$archive" |
|
|
tar "$@" |
|
|
echo "$archive" |
|
|
} |
|
|
|
|
|
cmd_upload_once() { |
|
|
need_hf |
|
|
archive="$(mk_archive)" |
|
|
[ -f "$archive" ] || { log "归档不存在:$archive"; return 1; } |
|
|
log "上传:$archive" |
|
|
python3 "$HF_PY" upload \ |
|
|
--token "$HF_TOKEN" \ |
|
|
--repo "$DATASET_ID" \ |
|
|
--file "$archive" \ |
|
|
--prefix "$BACKUP_PREFIX" \ |
|
|
--max "$MAX_BACKUPS" |
|
|
rm -f "$archive" || true |
|
|
log "上传完成" |
|
|
} |
|
|
|
|
|
cmd_restore() { |
|
|
need_hf |
|
|
out="$(python3 "$HF_PY" restore --token "$HF_TOKEN" --repo "$DATASET_ID" --prefix "$BACKUP_PREFIX" 2>/dev/null || true)" |
|
|
if [ -z "$out" ]; then |
|
|
log "未找到可恢复的备份,跳过。" |
|
|
exit 0 |
|
|
fi |
|
|
latest_file="$out" |
|
|
if [ ! -f "$latest_file" ]; then |
|
|
log "本地文件不存在:$latest_file"; exit 1 |
|
|
fi |
|
|
log "解压:$latest_file -> /" |
|
|
tar -xzf "$latest_file" -C / |
|
|
log "恢复完成" |
|
|
} |
|
|
|
|
|
cmd_daemon() { |
|
|
need_hf |
|
|
while :; do |
|
|
log "开始周期备份(间隔 ${SYNC_INTERVAL}s,前缀 ${BACKUP_PREFIX},保留 ${MAX_BACKUPS})" |
|
|
if ! cmd_upload_once; then |
|
|
log "本轮备份失败(忽略,等待下次循环)" |
|
|
fi |
|
|
sleep "$SYNC_INTERVAL" |
|
|
done |
|
|
} |
|
|
|
|
|
case "${1:-}" in |
|
|
restore) cmd_restore ;; |
|
|
once) cmd_upload_once ;; |
|
|
daemon) cmd_daemon ;; |
|
|
*) echo "用法: $0 {restore|once|daemon}" >&2; exit 1 ;; |
|
|
esac |
|
|
|