ACCC1380's picture
download
raw
6.83 kB
#!/usr/bin/env bash
set -euo pipefail
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
echo "用法:bash backup.sh [目录] [--dry-run]"
echo "默认目录:脚本所在目录;默认 bucket:ACCC1380/molab-checkpoints"
echo "可通过 HF_BUCKET 指定其他 bucket;HF_TOKEN 或目录中的 .env 提供认证。"
echo "--dry-run 只预览,不传输文件。"
echo "所有目录中的图片文件均不上传(扩展名不区分大小写)。"
exit 0
fi
script_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
transfer_python="${SYSTEM_PYTHON:-/usr/local/bin/python}"
if ! env -u PYTHONPATH "$transfer_python" -c 'from huggingface_hub import sync_bucket' >/dev/null 2>&1; then
env -u PYTHONPATH "$transfer_python" -m pip install 'huggingface_hub>=1.9,<2'
fi
env -u PYTHONPATH "$transfer_python" - backup "$script_root" "$@" <<'BUCKET_PY'
import argparse
import os
import re
import stat
import sys
from pathlib import Path
from huggingface_hub import HfApi, get_token, sync_bucket
mode, default_root = sys.argv[1:3]
parser = argparse.ArgumentParser()
parser.add_argument("directory", nargs="?", default=default_root)
parser.add_argument("--dry-run", action="store_true")
args = parser.parse_args(sys.argv[3:])
root = Path(args.directory).expanduser().resolve()
if mode == "backup" and not root.is_dir():
parser.error(f"备份目录不存在:{root}")
bucket = os.environ.get("HF_BUCKET", "ACCC1380/molab-checkpoints")
bucket = bucket.removeprefix("hf://buckets/").removeprefix("buckets/").rstrip("/")
if len(bucket.split("/")) != 2:
parser.error("HF_BUCKET 格式必须为 namespace/bucket")
uri = "hf://buckets/" + bucket
# Read credentials without executing .env as shell code or printing the token.
token = get_token()
if not token and (root / ".env").is_file():
for line in (root / ".env").read_text().splitlines():
match = re.match(r"(?:export\s+)?(?:HF_TOKEN|HUGGING_FACE_HUB_TOKEN)\s*=\s*['\"]?(hf_[A-Za-z0-9]+)", line.strip())
if match:
token = match.group(1)
break
api = HfApi(token=token)
# Check access before deleting any local generated files.
api.bucket_info(bucket)
if mode == "backup":
if not token:
raise SystemExit("上传需要认证:设置 HF_TOKEN,或在目录 .env 中设置 HF_TOKEN。")
api.whoami()
exclude = [
# Authentication state is recreated on the restored machine.
"ComfyUI/login", "ComfyUI/login/**",
"PASSWORD", "**/PASSWORD", "PASSWORD.*", "**/PASSWORD.*",
".secret-key.txt", "**/.secret-key.txt", ".secret-key.txt.*", "**/.secret-key.txt.*",
"login.txt", "**/login.txt", "credentials.txt", "**/credentials.txt",
"credentials.json", "**/credentials.json",
"comfyui-login", "comfyui-login/**", "**/comfyui-login", "**/comfyui-login/**",
"comfyui-admin", "comfyui-admin/**", "**/comfyui-admin", "**/comfyui-admin/**",
".ssh", ".ssh/**", "**/.ssh", "**/.ssh/**",
".git", ".git/**", "**/.git", "**/.git/**",
"ComfyUI/input/**", "ComfyUI/output/**", "comfyui-output/**",
"ComfyUI/models/SEEDVR2", "ComfyUI/models/SEEDVR2/**",
"ComfyUI/models/text_encoders/text_encoder", "ComfyUI/models/text_encoders/text_encoder/**",
"ComfyUI/models/vae/VAE", "ComfyUI/models/vae/VAE/**",
# Shared models are already backed up from their top-level directories.
"ComfyUI/models/loras/Lora", "ComfyUI/models/loras/Lora/**",
"ComfyUI/models/checkpoints/Stable-diffusion", "ComfyUI/models/checkpoints/Stable-diffusion/**",
"ComfyUI/models/diffusion_models/Stable-diffusion", "ComfyUI/models/diffusion_models/Stable-diffusion/**",
# Krea weights live in /tmp; do not upload through model symlinks.
"Stable-diffusion/krea2_turbo_bf16.safetensors",
"sd-webui-forge-neo/models/Stable-diffusion/krea2_turbo_bf16.safetensors",
"sd-webui-forge-neo/models/text_encoder/qwen3vl_4b_bf16.safetensors",
"sd-webui-forge-neo/models/VAE/krea2_vae_fp32.safetensors",
"ComfyUI/models/vae/qwen_image_vae.safetensors",
"ComfyUI/models/diffusion_models/krea2_turbo_bf16.safetensors",
"ComfyUI/models/text_encoders/qwen3vl_4b_bf16.safetensors",
"ComfyUI/models/vae/krea2_vae_fp32.safetensors",
"comfyui.log", "comfyui.pid", "comfyui-install.log", "qwen-download.log",
"ComfyUI/temp/**", "ComfyUI/user/*.db*", "ComfyUI/user/*.log",
"notebook.py", "**/notebook.py",
".env", ".env.*", "**/.env", "**/.env.*",
"**/__pycache__/**", "__pycache__/**", "__marimo__/**",
"**/.ipynb_checkpoints/**", ".ipynb_checkpoints/**",
".venv/**", "venv/**", "**/.venv/**", "**/venv/**",
".cache/**", "**/.cache/**", "*.part", "**/*.part",
"**/.uv-cache/**",
"sd-webui-forge-neo/cache/**",
"sd-webui-forge-neo/extensions/sd-webui-infinite-image-browsing/iib.db*",
"sd-webui-forge-neo/tmp/**", "sd-webui-forge-neo/output/**",
"sd-webui-forge-neo/outputs/**",
]
# fnmatch patterns match nested paths too; character classes cover mixed case.
image_extensions = (
"png apng jpg jpeg jpe jfif webp gif bmp dib tif tiff avif heic heif "
"svg svgz ico icns jxl exr hdr psd psb dng raw cr2 cr3 nef arw raf orf rw2 "
"ppm pgm pbm pnm tga dds ktx ktx2"
).split()
exclude.extend("*." + "".join(f"[{c}{c.upper()}]" if c.isalpha() else c for c in ext)
for ext in image_extensions)
source, dest = (str(root), uri) if mode == "backup" else (uri, str(root))
print(f"{source} -> {dest}", flush=True)
result = sync_bucket(source, dest, token=token, exclude=exclude, dry_run=args.dry_run)
print(result.summary(), flush=True)
if args.dry_run:
print("预览完成;未传输文件。")
raise SystemExit(0)
if mode == "restore":
models = root / "sd-webui-forge-neo" / "models"
models.mkdir(parents=True, exist_ok=True)
for kind in ("Stable-diffusion", "Lora"):
link = models / kind
if link.is_symlink():
link.unlink()
if not link.exists():
link.symlink_to("../../" + kind, target_is_directory=True)
else:
print(f"保留已有目录:{link}")
for relative in ("backup.sh", "restore.sh", "restore-model-links.sh", "start.sh", "comfyui.sh",
"sd-webui-forge-neo/start.sh",
"sd-webui-forge-neo/webui.sh", "sd-webui-forge-neo/webui-user.sh"):
file = root / relative
if file.is_file():
file.chmod(file.stat().st_mode | stat.S_IXUSR)
print("恢复完成。先以 root 运行 bash comfyui.sh --setup-only 安装依赖并生成新登录密码,再运行 bash comfyui.sh。密码查看:sudo cat /var/lib/comfyui-admin/login.txt。")
else:
print("备份完成。登录凭据、会话密钥、图片、上传目录和运行缓存未上传;云端已有文件保留,本地文件未删除。")
BUCKET_PY

Xet Storage Details

Size:
6.83 kB
·
Xet hash:
ad8e39c975ef36f4a77c73e3b056bae2ac6559c517f6647d0ddc217e28dbdd99

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.