| #!/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 |
|
|