#!/usr/bin/env python3
|
|
|
|
import os
|
|
import logging
|
|
import string
|
|
import hashlib
|
|
import time
|
|
import shutil
|
|
|
|
|
|
class Cloner:
|
|
def __init__(self, targetDir: str, backupDir: str):
|
|
self.targetDir = targetDir
|
|
self.backupDir = backupDir
|
|
self.interval = 1
|
|
|
|
def handleDir(self, dirPath: str):
|
|
backupDirPath = dirPath.replace(self.targetDir, self.backupDir)
|
|
if not os.path.isdir(backupDirPath):
|
|
os.mkdir(backupDirPath)
|
|
with os.scandir(dirPath) as it:
|
|
for entry in it:
|
|
if entry.is_dir():
|
|
self.handleDir(entry.path)
|
|
elif entry.is_file():
|
|
self.handleFile(entry.path)
|
|
|
|
def handleFile(self, targetFileName: str):
|
|
cloneFileName = targetFileName.replace(self.targetDir, self.backupDir)
|
|
cloneHashFileName = cloneFileName + '.md5'
|
|
|
|
if os.path.exists(cloneFileName):
|
|
with open(cloneHashFileName, 'r') as cloneHashFile, open(targetFileName, 'rb') as targetFile:
|
|
cloneHashFileContent = cloneHashFile.read()
|
|
targetFileContent = targetFile.read()
|
|
realHash = hashlib.md5(targetFileContent).hexdigest()
|
|
if realHash != cloneHashFileContent:
|
|
shutil.copyfile(cloneFileName, targetFileName)
|
|
logging.warning(
|
|
'{file} failed check, restoring...'.format(file=targetFileName))
|
|
else:
|
|
logging.info('{file} is fine'.format(file=targetFileName))
|
|
else:
|
|
logging.warning(
|
|
'{file} is a new file, added to backup dir'.format(file=targetFileName))
|
|
shutil.copyfile(targetFileName, cloneFileName)
|
|
with open(cloneHashFileName, 'w') as cloneHashFile, open(targetFileName, 'rb') as targetFile:
|
|
targetFileContent = targetFile.read()
|
|
cloneHashFile.write(hashlib.md5(targetFileContent).hexdigest())
|
|
|
|
def setLog(self, logFileName: str):
|
|
logFormatter = logging.Formatter(
|
|
fmt="[%(asctime)s][%(levelname)s] %(message)s",
|
|
datefmt='%d-%b-%y %H:%M:%S')
|
|
|
|
rootLogger = logging.getLogger()
|
|
|
|
fileHandler = logging.FileHandler(logFileName, mode='a')
|
|
fileHandler.setFormatter(logFormatter)
|
|
rootLogger.addHandler(fileHandler)
|
|
|
|
# # uncomment this to enable console logging
|
|
# consoleHandler = logging.StreamHandler()
|
|
# consoleHandler.setFormatter(logFormatter)
|
|
# rootLogger.addHandler(consoleHandler)
|
|
|
|
rootLogger.setLevel(logging.WARNING)
|
|
|
|
def setInterval(self, interval: int):
|
|
self.interval = interval
|
|
|
|
def start(self):
|
|
while True:
|
|
self.handleDir(self.targetDir)
|
|
time.sleep(5)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'--target',
|
|
metavar='PATH',
|
|
type=str,
|
|
required=True,
|
|
help='directory to clone and monitor')
|
|
parser.add_argument(
|
|
'--backup',
|
|
metavar='PATH',
|
|
type=str,
|
|
required=True,
|
|
help='backup directory to store clone'
|
|
)
|
|
parser.add_argument(
|
|
'--interval',
|
|
metavar='SECOND',
|
|
type=int,
|
|
default=1,
|
|
help='interval in second(s) which the scripts run, default is 1'
|
|
)
|
|
parser.add_argument(
|
|
'--log',
|
|
metavar='LOGFILE',
|
|
type=str,
|
|
default='/var/log/py-dir-watcher/log.txt',
|
|
help='specify custom logfile target, default is \'/var/log/py-dir-watcher/log.txt\' '
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
app = Cloner(args.target, args.backup)
|
|
app.setLog(args.log)
|
|
app.setInterval(args.interval)
|
|
app.start()
|