ACCC1380's picture
download
raw
5.25 kB
#!/usr/bin/env bash
set -euo pipefail
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
echo "用法:bash restore.sh [目录] [--dry-run]"
echo "默认目录:脚本所在目录;默认 bucket:ACCC1380/molab-checkpoints"
echo "可通过 HF_BUCKET 指定其他 bucket;HF_TOKEN 或目录中的 .env 提供认证。"
echo "--dry-run 只预览,不传输文件。"
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" - restore "$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 = [
"codex-oneclick-kaggle.sh", "**/codex-oneclick-kaggle.sh",
# 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/**",
"notebook.py", "**/notebook.py",
"comfyui.log", "comfyui.pid", "comfyui-install.log", "qwen-download.log",
"ComfyUI/temp/**", "ComfyUI/user/*.db*", "ComfyUI/user/*.log",
".env", ".env.*", "**/.env", "**/.env.*",
"**/__pycache__/**", "__pycache__/**", "__marimo__/**",
"**/.ipynb_checkpoints/**", ".ipynb_checkpoints/**",
".venv/**", "venv/**", "**/.venv/**", "**/venv/**",
".cache/**", "**/.cache/**", "*.part", "**/*.part",
"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/**",
]
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 link.is_dir() and not any(link.iterdir()):
link.rmdir()
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("备份完成。目标中其他文件保留;.env、Forge 出图和运行缓存未上传;本地文件未删除。")
BUCKET_PY

Xet Storage Details

Size:
5.25 kB
·
Xet hash:
6120337ffc47a35fa69a3aee6b5304822a461061300ca12158f773475955ce1b

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