frank0957's picture
Update backup.sh
c6d42cc verified
Raw
History Blame Contribute Delete
6.76 kB
#!/bin/bash
#
# Backup Script for Hugging Face Space β†’ GitHub
# ===============================================
# Periodically copies data files and the wiki directory
# to a private GitHub repository.
#
# Required environment variables:
# GITHUB_TOKEN – personal access token with write access
# GITHUB_BACKUP_REPO – full URL of the repo (e.g. https://github.com/user/repo)
# Optional (for Telegram alerts):
# TELEGRAM_BOT_TOKEN
# TELEGRAM_CHAT_ID
# BACKUP_INTERVAL_HOURS – default 6, can be overridden via file /app/backup_interval_hours.txt
#
# Status written to /app/backup_status.txt : status | UTC timestamp
# History appended to /app/backup_history.txt : timestamp | status
# Last restore time stored in /app/last_restore.txt
# ── Configuration ────────────────────────────────────────────────
GITHUB_TOKEN=${GITHUB_TOKEN}
GITHUB_REPO=${GITHUB_BACKUP_REPO}
BACKUP_DIR=/app/backup_repo
STATUS_FILE=/app/backup_status.txt
HISTORY_FILE=/app/backup_history.txt
RESTORE_MARKER=/app/last_restore.txt
INTERVAL_FILE=/app/backup_interval_hours.txt
DEFAULT_INTERVAL_HOURS="${BACKUP_INTERVAL_HOURS:-6}"
# ── Early exit if credentials missing ────────────────────────────
if [ -z "$GITHUB_TOKEN" ] || [ -z "$GITHUB_REPO" ]; then
echo "[Backup] Missing credentials. Backup disabled."
echo "disabled|$(date -u +'%Y-%m-%d %H:%M UTC')" > "$STATUS_FILE"
exit 0
fi
REPO_URL="${GITHUB_REPO#https://}"
# ── Telegram alert helper ────────────────────────────────────────
send_telegram_alert() {
local msg="$1"
local token="${TELEGRAM_BOT_TOKEN}"
local chat_id="${TELEGRAM_CHAT_ID}"
if [ -z "$token" ] || [ -z "$chat_id" ]; then
echo "[Backup] Telegram alert skipped – missing token/chat_id."
return 1
fi
curl -s -X POST "https://api.telegram.org/bot${token}/sendMessage" \
-d "chat_id=${chat_id}" -d "text=${msg}" -d "parse_mode=HTML" >/dev/null
}
# ── Clone or pull the backup repository ──────────────────────────
if [ ! -d "$BACKUP_DIR" ]; then
echo "[Backup] Cloning backup repository..."
git clone "https://${GITHUB_TOKEN}@${REPO_URL}" "$BACKUP_DIR"
cd "$BACKUP_DIR" || exit 1
# If empty repo, create main branch
if ! git rev-parse --verify HEAD >/dev/null 2>&1; then
echo "[Backup] Repository is empty – creating 'main' branch."
git checkout -b main
fi
else
echo "[Backup] Pulling latest backup..."
cd "$BACKUP_DIR" && git pull origin main
fi
# ── Set Git identity ─────────────────────────────────────────────
if ! git config user.name >/dev/null 2>&1; then
git config user.name "HuggingFace Backup Bot"
fi
if ! git config user.email >/dev/null 2>&1; then
git config user.email "backup@example.com"
fi
# ── Restore local files if missing (after clone/pull) ────────────
RESTORED_ANY=false
if [ ! -d /app/wiki ] || [ -z "$(ls -A /app/wiki 2>/dev/null)" ]; then
echo "[Backup] Wiki empty – restoring from backup..."
mkdir -p /app/wiki
if [ -d "$BACKUP_DIR/wiki" ]; then
cp -r "$BACKUP_DIR/wiki/"* /app/wiki/ 2>/dev/null
RESTORED_ANY=true
fi
fi
for f in notes.txt flags.json virtual_positions.json capital_state.json dashboard_report.json llm_error_types.txt; do
if [ ! -f "/app/$f" ] && [ -f "$BACKUP_DIR/$f" ]; then
cp "$BACKUP_DIR/$f" "/app/$f"
RESTORED_ANY=true
fi
done
if [ "$RESTORED_ANY" = true ]; then
date -u +'%Y-%m-%d %H:%M UTC' > "$RESTORE_MARKER"
echo "[Backup] Restore completed at $(cat $RESTORE_MARKER)"
fi
# ── Function: do_backup ──────────────────────────────────────────
do_backup() {
echo "[Backup] Copying data files..."
cd "$BACKUP_DIR" || return
cp /app/notes.txt . 2>/dev/null
cp /app/flags.json . 2>/dev/null
cp /app/virtual_positions.json . 2>/dev/null
cp /app/capital_state.json . 2>/dev/null
cp /app/virtual_capital_state.json . 2>/dev/null
cp /app/dashboard_report.json . 2>/dev/null
cp /app/llm_error_types.txt . 2>/dev/null
if [ -d /app/wiki ]; then
rm -rf wiki
cp -r /app/wiki wiki
echo "[Backup] Wiki directory copied ($(ls -A wiki | wc -l) files)."
fi
echo "[Backup] Current Git branch:"
git branch
git add -A
if git commit -m "Auto backup $(date -u +'%Y-%m-%d %H:%M UTC')" 2>/dev/null; then
echo "[Backup] Committed. Pushing to main..."
if git push origin HEAD:main 2>&1; then
now_utc=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "[Backup] Backup completed at $now_utc"
echo "success|$now_utc" > "$STATUS_FILE"
echo "$now_utc | success" >> "$HISTORY_FILE"
else
now_utc=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "[Backup] Push failed"
echo "failed|$now_utc" > "$STATUS_FILE"
echo "$now_utc | failed" >> "$HISTORY_FILE"
send_telegram_alert "❌ <b>Backup FAILED</b> at $now_utc"
fi
else
now_utc=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "[Backup] No changes to commit"
echo "no_changes|$now_utc" > "$STATUS_FILE"
echo "$now_utc | no_changes" >> "$HISTORY_FILE"
fi
}
# ── Wait for first data before initial backup ────────────────────
echo "[Backup] Waiting for data files to be written..."
while true; do
if [ -s /app/notes.txt ] || [ -s /app/flags.json ] || [ -s /app/virtual_positions.json ] ||
([ -d /app/wiki ] && [ -n "$(ls -A /app/wiki)" ]); then
echo "[Backup] Valid data detected. Proceeding."
break
fi
sleep 30
done
do_backup
# ── Loop with adjustable interval ─────────────────────────────────
while true; do
if [ -f "$INTERVAL_FILE" ]; then
interval_hours=$(cat "$INTERVAL_FILE" | tr -d '[:space:]')
interval_hours="${interval_hours:-$DEFAULT_INTERVAL_HOURS}"
else
interval_hours="$DEFAULT_INTERVAL_HOURS"
fi
sleep_seconds=$(( 3600 * interval_hours ))
[ "$sleep_seconds" -lt 3600 ] && sleep_seconds=3600 # minimum 1 hour
echo "[Backup] Next backup in ${interval_hours}h ($sleep_seconds s)."
sleep "$sleep_seconds"
do_backup
done