File size: 4,831 Bytes
b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 b79920e 420e831 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | import os
import time
import subprocess
import datetime
import threading
import tarfile
import tempfile
from pathlib import Path
# =========================
# ENV VARIABLES
# =========================
BACKUP_REPO = os.environ.get("BACKUP_REPO")
HF_TOKEN = os.environ.get("HF_TOKEN")
BACKUP_INTERVAL = int(os.environ.get("BACKUP_INTERVAL", "5")) * 60
CONFIG_BACKUP_INTERVAL = int(os.environ.get("CONFIG_BACKUP_INTERVAL", "60")) * 60
CONFIG_KEEP_LIMIT = int(os.environ.get("CONFIG_KEEP_LIMIT", "5"))
# =========================
# PATHS
# =========================
WORKSPACE_PATH = "/home/vscode/workspace"
CONFIG_PATHS = [
"/home/vscode/.claude",
"/home/vscode/.config/code-server/config.yaml",
"/home/vscode/.local/share/code-server/extensions",
"/home/vscode/.local/share/code-server/User",
"/home/vscode/.local/share/code-server/Machine",
"/home/vscode/.local/share/code-server/coder.json"
]
WORKSPACE_EXCLUDES = ["__pycache__", ".git", "node_modules", ".DS_Store"]
# =========================
# HELPERS
# =========================
def hf_env():
env = os.environ.copy()
env["HF_HOME"] = "/tmp/hf_cache"
env["XDG_CACHE_HOME"] = "/tmp/xdg_cache"
env["TMPDIR"] = "/tmp"
env["HF_TOKEN"] = HF_TOKEN
os.makedirs(env["HF_HOME"], exist_ok=True)
os.makedirs(env["XDG_CACHE_HOME"], exist_ok=True)
os.makedirs(env["TMPDIR"], exist_ok=True)
return env
def upload_folder(local_path, remote_path, excludes=None):
env = hf_env()
cmd = ["hf", "upload", BACKUP_REPO, local_path, remote_path, "--repo-type", "dataset"]
if excludes:
for e in excludes:
cmd += ["--exclude", e]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=env)
for line in iter(process.stdout.readline, ""):
print("[Backup]", line.strip())
process.wait()
def cleanup_old_backups():
try:
env = hf_env()
result = subprocess.run(
["hf", "repo-files", "list", BACKUP_REPO, "--repo-type", "dataset"],
stdout=subprocess.PIPE, text=True, env=env
)
lines = result.stdout.splitlines()
configs = [l.strip() for l in lines if l.startswith("configs/configs_") and l.endswith(".tar.gz")]
if len(configs) > CONFIG_KEEP_LIMIT:
configs.sort(reverse=True)
old = configs[CONFIG_KEEP_LIMIT:]
print(f"[Cleanup] Found {len(old)} old config backups to delete.")
for f in old:
print(f"[Cleanup] Deleting {f}")
subprocess.run(["hf", "repo-files", "delete", BACKUP_REPO, f, "--repo-type", "dataset"],
env=env, check=False)
else:
print(f"[Cleanup] No cleanup needed. Total configs: {len(configs)}")
except Exception as e:
print("[Cleanup] Failed:", e)
# =========================
# BACKUP ROUTINES
# =========================
def run_workspace_backup():
while True:
print("[Backup] Workspace backup started.")
try:
upload_folder(WORKSPACE_PATH, "workspace/", excludes=WORKSPACE_EXCLUDES)
print("[Backup] Workspace backup completed at", datetime.datetime.utcnow().isoformat(), "UTC")
except Exception as e:
print("[Backup] Workspace backup failed:", e)
time.sleep(BACKUP_INTERVAL)
def run_config_backup():
while True:
print("[Backup] Config backup started.")
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=".tar.gz") as tmp:
tar_path = tmp.name
with tarfile.open(tar_path, "w:gz") as tar:
for path in CONFIG_PATHS:
if os.path.exists(path):
arcname = os.path.relpath(path, "/home/vscode")
tar.add(path, arcname=arcname)
print(f"[Backup] Added {arcname}")
timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H-%M-%SZ")
remote_path = f"configs/configs_{timestamp}.tar.gz"
upload_folder(tar_path, remote_path)
os.remove(tar_path)
print("[Backup] Config backup completed at", timestamp)
cleanup_old_backups()
except Exception as e:
print("[Backup] Config backup failed:", e)
time.sleep(CONFIG_BACKUP_INTERVAL)
# =========================
# MAIN ENTRY
# =========================
if __name__ == "__main__":
if not BACKUP_REPO or not HF_TOKEN:
print("[Backup] BACKUP_REPO or HF_TOKEN not set! Exiting.")
exit(0)
print("[Backup] Starting dual backup threads...")
threading.Thread(target=run_workspace_backup, daemon=True).start()
threading.Thread(target=run_config_backup, daemon=True).start()
while True:
time.sleep(3600)
|