#!/usr/bin/env python
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from subprocess import Popen, PIPE
from argparse import ArgumentParser, REMAINDER
from time import time, sleep
import re

parser = ArgumentParser(description='''
Allows to start a program, and to monitor changes in a folder, when changes are
detected in the folder, the command is restarted.

This can be useful to test a software you are developping and having immediate
feedback.
Or to restart a daemon when configuration or data changes.
Or any other use, the sky is the limit :)
''')
parser.add_argument('-p', '--path', type=str, default='.', help='set the path to monitor for changes')
parser.add_argument('-a', '--action', type=str, default='restart', help='what action to perform when changes are detected')
parser.add_argument('-i', '--ignorelist', type=str, default='', nargs='*', help='files to ignore')
parser.add_argument('-f', '--focus', type=int, default=0, help='save focus and restore it for the next n seconds after restarting application, require xdotool (linux only)')
parser.add_argument('command', type=str, nargs=REMAINDER)


class RestartHandler(FileSystemEventHandler):
    def __init__(self, command, path, ignorelist, focus, **kwargs):
        super(RestartHandler, self).__init__(**kwargs)
        self.command = command
        self.ignorelist = ignorelist
        self.focus = focus
        self.start()

    def stop(self):
        self._process.terminate()
        print 'TERMINATED'

    def start(self):
        if self.focus:
            t = time()
            wid = int(Popen(['/usr/bin/env', 'xdotool', 'getwindowfocus'], stdout=PIPE).communicate()[0])

        self._process = Popen(self.command)
        print 'STARTED', self._process

        if self.focus:
            while time() < t + self.focus:
                Popen(['/usr/bin/env', 'xdotool', 'windowfocus', str(wid)])
                sleep(.01)

    def on_any_event(self, event):
        for i in self.ignorelist:
            if re.compile('^' + i.replace('*', '.*') + '$').match(event.src_path):
                return

        print 'terminating', self
        self.stop()
        self.start()


def monitor(command, path, action, focus, ignorelist=None):
        if action == 'restart':
            ev = RestartHandler(command, path=path, focus=focus, ignorelist=ignorelist)
        else:
            raise NotImplementedError('action %s not implemented' % action)

        ob = Observer()
        ob.schedule(ev, path=path, recursive=True)
        ob.start()
        try:
            while True:
                sleep(1)
        except KeyboardInterrupt:
            ob.stop()
        ob.join()

if __name__ == '__main__':
    args = parser.parse_args()
    print args
    monitor(args.command, args.path, args.action, args.focus, args.ignorelist)

@@ -105,16 +105,32 @@
 tHandler
+, FileMovedEvent
 %0Afrom su
@@ -244,16 +244,181 @@
 ort re%0A%0A
+try:%0A    import colorama%0A    colorama.init()%0Aexcept ImportError:%0A    colorama = None%0A%0Atry:%0A    from termcolor import colored%0Aexcept ImportError:%0A    colored = None%0A%0A
 parser =
@@ -1300,44 +1300,271 @@
 nt('
-command', type=str, nargs=REMAINDER)
+-s', '--sleep', type=int, default=0, help='ignore events for n seconds after the last restart')%0Aparser.add_argument('command', type=str, nargs=REMAINDER)%0A%0A%0Adef log(color, string):%0A    if colored:%0A        print colored(string, color)%0A    else:%0A        print string
 %0A%0A%0Ac
@@ -1664,16 +1664,27 @@
 , focus,
+ sleeptime,
  **kwarg
@@ -1837,16 +1837,47 @@
 = focus%0A
+        self.sleep = sleeptime%0A
         
@@ -1952,21 +1952,26 @@
         
-print
+log('red',
  'TERMIN
@@ -1975,16 +1975,17 @@
 MINATED'
+)
 %0A%0A    de
@@ -1991,32 +1991,68 @@
 ef start(self):%0A
+        self._last_restart = time()%0A
         if self.
@@ -2240,21 +2240,28 @@
         
-print
+log('green',
  'STARTE
@@ -2261,18 +2261,22 @@
 'STARTED
-',
+ %25s' %25
  self._p
@@ -2281,16 +2281,17 @@
 _process
+)
 %0A%0A      
@@ -2489,16 +2489,104 @@
 event):%0A
+        if self.sleep and time() %3C self._last_restart + self.sleep:%0A            return%0A%0A
         
@@ -2623,18 +2623,19 @@
         
-if
+r =
  re.comp
@@ -2671,16 +2671,33 @@
 ) + '$')
+%0A            if r
 .match(e
@@ -2735,25 +2735,28 @@
  return%0A
-%0A
+    
         
 print 't
@@ -2751,33 +2751,144 @@
     
-print 'terminating', self
+if isinstance(event, FileMovedEvent) and r.match(event.dest_path):%0A                return%0A%0A        log('blue', '%25s RESTARTING' %25 event)%0A
 %0A   
@@ -2964,24 +2964,35 @@
 tion, focus,
+ sleeptime,
  ignorelist=
@@ -3094,16 +3094,37 @@
 s=focus,
+ sleeptime=sleeptime,
  ignorel
@@ -3527,18 +3527,30 @@
     
-print 
+log('blue', str(
 args
+))
 %0A   
@@ -3607,16 +3607,28 @@
 s.focus,
+ args.sleep,
  args.ig

use colors if available, add sleep option to ignore evnts for n seconds