| #!/bin/bash |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| 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}" |
|
|
| |
| 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://}" |
|
|
| |
| 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 |
| } |
|
|
| |
| 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 ! 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 |
|
|
| |
| 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 |
|
|
| |
| 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 |
|
|
| |
| 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 |
| } |
|
|
| |
| 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 |
|
|
| |
| 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 |
| echo "[Backup] Next backup in ${interval_hours}h ($sleep_seconds s)." |
| sleep "$sleep_seconds" |
| do_backup |
| done |