Skip to content

Instantly share code, notes, and snippets.

@d3flex
Created July 16, 2025 18:09
Show Gist options
  • Select an option

  • Save d3flex/1d364c56ab42f5080c0da5befe381948 to your computer and use it in GitHub Desktop.

Select an option

Save d3flex/1d364c56ab42f5080c0da5befe381948 to your computer and use it in GitHub Desktop.
import logging
import argparse
import pathlib
import os
import shutil
import time
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
def init_log(logname):
console_logger = logging.StreamHandler()
console_logger.setLevel(logging.INFO)
file_logger = logging.FileHandler(logname)
file_logger.setLevel(logging.INFO)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_logger.setFormatter(formatter)
console_logger.setFormatter(formatter)
logger.addHandler(console_logger)
logger.addHandler(file_logger)
return logger
def add_or_update(src, dest):
pass
def remove(src, dest):
pass
def sync(src, dest, interval):
"""
Recursively copies a directory and its contents, preserving all metadata.
:param src: The path to the source directory to copy.
:param dest: The path to the destination directory.
:interval: duration before run again.
"""
logger.info(f"* Syncing {str(src)} directory to {str(dest)}.")
os.makedirs(dest, exist_ok=True)
shutil.copystat(src, dest)
import pdb
#pdb.set_trace()
src_context = {p for p in pathlib.Path(src).rglob('*')}
dst_context = {p for p in pathlib.Path(dest).rglob('*')}
diff_set = dst_context - src_context
# delete first
if len(diff_set) > 0:
for path in diff_set:
if path.is_dir():
path.rmdir()
if path.is_file():
path.unlink()
else:
logger.info("No deleted files.")
for item in src.iterdir():
filename = item.name
dst_fullpath = dest.joinpath(filename)
#print(dst_fullpath)
if item.is_dir():
sync(item, dst_fullpath, interval)
else:
shutil.copy2(item, dst_fullpath)
logger.info(f"{str(item)} -> {str(dest)} sync completed.")
time.sleep(interval)
def main():
parser = argparse.ArgumentParser(
prog='veeamsync',
description='synchronizes two folders')
parser.add_argument('source')
parser.add_argument('replica')
parser.add_argument('interval')
parser.add_argument('sync_times')
parser.add_argument('log_filename')
args = parser.parse_args()
logger = init_log(args.log_filename)
from_dir = pathlib.Path(args.source)
to_dir = pathlib.Path(args.replica)
interval = int(args.interval)
if (not from_dir.exists() or not from_dir.is_dir()):
logger.error(f"source dir {args.source} not found")
else:
sync_times_left = int(args.sync_times)
while (sync_times_left > 0):
logger.info(f"Sync {sync_times_left} starts!")
sync_times_left-=1
try:
sync(from_dir, to_dir, interval)
except Exception as e:
logger.error(e)
if __name__ == '__main__':
main()
# assuptions:
# - all the params are mandatory and will be given
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment