''' High level inotify wrapper ''' from os import listdir from os.path import join as opj, normpath, isdir from threading import Thread, RLock from Queue import Queue from time import sleep from inotify import Inotify, FLAGS, mask_str globals().update(FLAGS) ALL = ACCESS|MODIFY|ATTRIB|WRITE|CLOSE|OPEN|CREATE|DELETE class Event(object): def __init__(self, wd, watcher, mask, cookie, name): self.wd=wd self.watcher=watcher self.mask=mask self.cookie=cookie self.name=name @property def watch(self): return self.watcher.watches[self.wd] @property def path(self): path=self.watch.path return opj(path, self.name) if self.name else path def __str__(self): return '%s -> %s' % (mask_str(self.mask), self.path) class Watch(object): def __init__(self, wd, watcher, mask, path, callback, auto, _parent=None): self.wd=wd self.watcher=watcher self.mask=mask self.path=normpath(path) self.callback=callback self.auto=auto self._parent=_parent if isdir(self.path) and self.auto: for name in listdir(self.path): path = opj(self.path, name) if isdir(path): self.watcher.add( path, mask, callback, auto=True, _parent=self) def __str__(self): return 'Watch %i %s %s -> %s' % ( self.wd, self.path, mask_str(self.mask), self.callback.__name__) def default(event): if event.mask not in (ISDIR|OPEN, ISDIR|CLOSE): print event class Watcher(object): def __init__(self): self.inotify=Inotify() self.watches={} self.queue=Queue() self.lock=RLock() for t in (self._push, self._pull): t=Thread(target=t) t.setDaemon(True) t.start() def _push(self): while True: for wd, mask, cookie, name in self.inotify.read(): self.queue.put(Event(wd, self, mask, cookie, name)) def _pull(self): while True: event = self.queue.get() mask=event.mask self.lock.acquire() watch = self.watches.get(event.wd) self.lock.release() watch.callback(event) if mask&ISDIR and mask&CREATE and watch.auto: self.add(event.path, watch.mask, watch.callback, auto=True, _parent=watch) if mask&IGNORED: self.rem(watch) def add(self, path, mask=ALL, callback=default, auto=True, _parent=None): self.lock.acquire() wd=self.inotify.add_watch(path, mask) watch = Watch(wd, self, mask, path, callback, auto, _parent) self.watches[wd] = watch self.lock.release() return watch def rem(self, watch): self.lock.acquire() for w in list(self.watches.values()): if w._parent==watch: self.rem(w) wd=watch.wd self.watches.pop(wd) self.lock.release() def close(self): self.inotify.close() if __name__ == '__main__': def tail(event): fil, mask = event.path, mask_str(event.mask) print '%s %s\n\t%s\n' % ( fil, mask, '\t'.join(open(fil).readlines()[-5:]) ) watcher = Watcher() watcher.add('/etc') watcher.add('/var/log', MODIFY, tail) try: while True: sleep(11) except KeyboardInterrupt: print finally: watcher.close()