Skip to content

Instantly share code, notes, and snippets.

@SuoXC
Created August 20, 2020 11:49
Show Gist options
  • Save SuoXC/a17c5dbce9f3b89091760cddb736a86e to your computer and use it in GitHub Desktop.
Save SuoXC/a17c5dbce9f3b89091760cddb736a86e to your computer and use it in GitHub Desktop.
rsync sometimes delete files with no backup, so this script is a solution to safely sync things
import filecmp
import os
import pathlib
import shutil
def no_change(src_file, dest_file):
equal = filecmp.cmp(src_file.resolve(), dest_file.resolve(), False)
return equal
def remove_file(dest_file):
return os.unlink(str(dest_file))
def copy_file(src_file, dest_file):
if not os.path.exists(dest_file.parent):
os.makedirs(dest_file.parent, exist_ok=True)
print('copyfile:', src_file, dest_file)
shutil.copyfile(src_file, dest_file, follow_symlinks=True)
def safe_backup(from_dir, to_dir, backup_dir):
src_path = pathlib.Path(from_dir)
dest_path = pathlib.Path(to_dir)
backup_path = pathlib.Path(backup_dir)
src_files = src_path.glob('**/*')
dest_files = dest_path.glob('**/*')
# 备份已删除文件
for dest_file in dest_files:
if dest_file.is_dir():
continue
relative_path = dest_file.relative_to(dest_path)
src_file = src_path / relative_path
backup_file = backup_path / relative_path
if not src_file.exists():
copy_file(dest_file, backup_file)
remove_file(dest_file)
# 备份修改的文件, 跳过新增的文件
for src_file in src_files:
if src_file.is_dir():
continue
relative_path = src_file.relative_to(src_path)
dest_file = dest_path / relative_path
if not dest_file.exists():
copy_file(src_file, dest_file)
else:
if not no_change(src_file, dest_file):
backup_file = backup_path / relative_path
copy_file(dest_file, backup_file)
copy_file(src_file, dest_file)
# 删除无用的文件夹
dest_files = dest_path.glob('**/*')
for dest_file in dest_files:
if dest_file.is_dir():
relative_path = dest_file.relative_to(dest_path)
src_file = src_path / relative_path
if not src_file.exists():
shutil.rmtree(dest_file)
def main():
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--src_dir')
parser.add_argument('--dest_dir')
parser.add_argument('--back_dir')
args = parser.parse_args()
safe_backup(args.src_dir, args.dest_dir, args.back_dir)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment