feat(deployer): sync 前备份远程服务目录
rsync --delete 会清掉目标目录里的多余文件;先拷到 $HOME/bakeup/deployer-skill,失败则中止同步。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,12 +12,16 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
BAKEUP_KEEP = 5
|
||||
BAKEUP_ROOT = "deployer-skill"
|
||||
|
||||
_SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPT_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPT_DIR))
|
||||
@@ -25,7 +29,60 @@ if str(_SCRIPT_DIR) not in sys.path:
|
||||
from lib import DEFAULT_BASE_PATH, rsync_ssh_args, scp_base_args, service_info, ssh_cmd # noqa: E402
|
||||
|
||||
|
||||
def _safe_bakeup_name(name: str) -> str:
|
||||
cleaned = re.sub(r"[^A-Za-z0-9._-]+", "-", name).strip("-.")
|
||||
return cleaned or "service"
|
||||
|
||||
|
||||
def _backup_remote(info: dict) -> int:
|
||||
"""把远程服务目录拷到 $HOME/bakeup/deployer-skill/<name>/<timestamp>/,失败则中止 sync。"""
|
||||
name = _safe_bakeup_name(info["name"])
|
||||
remote_dir = info["remote_dir"]
|
||||
script = f"""
|
||||
set -eu
|
||||
remote_dir={shlex.quote(remote_dir)}
|
||||
name={shlex.quote(name)}
|
||||
root={shlex.quote(BAKEUP_ROOT)}
|
||||
keep={BAKEUP_KEEP}
|
||||
if [ ! -d "$remote_dir" ]; then
|
||||
echo "跳过备份: 远程目录不存在 $remote_dir"
|
||||
exit 0
|
||||
fi
|
||||
if [ -z "$(find "$remote_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]; then
|
||||
echo "跳过备份: 远程目录为空 $remote_dir"
|
||||
exit 0
|
||||
fi
|
||||
stamp=$(date +%Y%m%d-%H%M%S)
|
||||
base="$HOME/bakeup/$root/$name"
|
||||
dest="$base/$stamp"
|
||||
mkdir -p "$dest"
|
||||
chmod 700 "$HOME/bakeup" "$HOME/bakeup/$root" "$base" "$dest"
|
||||
cp -a "$remote_dir"/. "$dest"/
|
||||
ls -1d "$base"/[0-9][0-9][0-9][0-9]* 2>/dev/null | sort -r | tail -n +"$((keep + 1))" | while IFS= read -r old; do
|
||||
rm -rf "$old"
|
||||
done
|
||||
echo "已备份到 $dest (保留最近 $keep 份)"
|
||||
"""
|
||||
cmd = ssh_cmd(info, script)
|
||||
print(f"备份远程目录 {info['node']}:{remote_dir}")
|
||||
print(f"备份位置: $HOME/bakeup/{BAKEUP_ROOT}/{name}/<时间戳>/")
|
||||
print("-" * 60)
|
||||
try:
|
||||
completed = subprocess.run(cmd, check=False)
|
||||
except FileNotFoundError:
|
||||
print("错误: ssh 命令未找到,无法备份")
|
||||
return 1
|
||||
if completed.returncode:
|
||||
print(f"错误: 远程备份失败,退出码: {completed.returncode};已中止同步")
|
||||
return completed.returncode
|
||||
print("-" * 60)
|
||||
return 0
|
||||
|
||||
|
||||
def sync_directory(info: dict) -> int:
|
||||
backup_rc = _backup_remote(info)
|
||||
if backup_rc:
|
||||
return backup_rc
|
||||
if shutil.which("rsync"):
|
||||
return _sync_rsync(info)
|
||||
print("本机没有 rsync,改用 scp(不会删除远程多余文件)")
|
||||
|
||||
Reference in New Issue
Block a user