Created
May 23, 2017 03:00
-
-
Save fengxsong/166e599856d65aedff21e2a0b24aa203 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding:utf-8 -*- | |
import os | |
import click | |
import logging | |
import re | |
import subprocess | |
import time | |
from watchdog.observers import Observer | |
from watchdog.events import FileSystemEventHandler | |
logging.basicConfig(level=logging.INFO, | |
format='%(asctime)s - %(message)s', | |
datefmt='%Y-%m-%d %H:%M:%S') | |
class COLORS(object): | |
PURPLE = '\033[95m' | |
BLUE = '\033[94m' | |
GREEN = '\033[92m' | |
YELLOW = '\033[93m' | |
RED = '\033[91m' | |
BOLD = '\033[1m' | |
UNDERLINE = '\033[4m' | |
END = '\033[0m' | |
class TestHandler(FileSystemEventHandler): | |
def __init__(self, source, dest, rsync_opts=''): | |
self.source = source | |
self.dest = dest | |
self.rsync_opts = rsync_opts.split() | |
self.rsync() | |
def filter_invalid(self, fn): | |
if re.match(r'\S+\.[sw\w+|tmp]', fn) or self.source == fn: | |
return True | |
return False | |
def dispatch(self, event): | |
if not self.filter_invalid(event.src_path): | |
super(TestHandler, self).dispatch(event) | |
@staticmethod | |
def log(log, color): | |
logging.info('{}{}{}'.format(color, log, COLORS.END)) | |
def event_type(self, event): | |
return 'directory' if event.is_directory else 'file' | |
def on_moved(self, event): | |
super(TestHandler, self).on_moved(event) | |
self.log('Moved {}: from {} to {}'.format( | |
event_type(event), event.src_path, event.dest_path), COLORS.BLUE) | |
self.rsync() | |
def on_created(self, event): | |
super(TestHandler, self).on_created(event) | |
self.log('Created {}: {}'.format( | |
event_type(event), event.src_path), COLORS.GREEN) | |
self.rsync() | |
def on_deleted(self, event): | |
super(TestHandler, self).on_deleted(event) | |
self.log('Deleted {}: {}'.format( | |
event_type(event), event.src_path), COLORS.RED) | |
self.rsync() | |
def on_modified(self, event): | |
super(TestHandler, self).on_modified(event) | |
self.log('Modified {}: {}'.format( | |
event_type(event), event.src_path), COLORS.YELLOW) | |
self.rsync() | |
def rsync(self, relative_path=None): | |
self.log('RSyncing', COLORS.PURPLE) | |
source = os.path.join( | |
self.source, relative_path) if relative_path else self.source | |
dest = os.path.join( | |
self.dest, relative_path) if relative_path else self.dest | |
cmd = 'rsync -avzP {} {} {}'.format( | |
' '.join(self.rsync_opts), source, dest | |
) | |
self.log(cmd, COLORS.BOLD) | |
with open(os.devnull, 'w') as DEVNULL: | |
subprocess.call(cmd, stdout=DEVNULL, stderr=subprocess.STDOUT) | |
@click.command() | |
@click.option('--source', default='.', help='monitor source path') | |
@click.option('--dest', help='destination') | |
@click.option('--rsync-opts', default='', help='rsync command options') | |
def main(source, dest, rsync_opts): | |
event_handler = TestHandler(source, dest, rsync_opts) | |
observer = Observer() | |
observer.schedule(event_handler, source, recursive=True) | |
observer.start() | |
try: | |
while True: | |
time.sleep(1) | |
except KeyboardInterrupt: | |
observer.stop() | |
observer.join() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment