Skip to content

Instantly share code, notes, and snippets.

@fengxsong
Created May 23, 2017 03:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fengxsong/166e599856d65aedff21e2a0b24aa203 to your computer and use it in GitHub Desktop.
Save fengxsong/166e599856d65aedff21e2a0b24aa203 to your computer and use it in GitHub Desktop.
#!/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