Welcome, guest | Sign In | My Account | Store | Cart
'''
    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()

History

  • revision 4 (15 years ago)
  • previous revisions are not available