This is an exemple to show how to use the inotify module, it could be very usefull unchanged though.
A Watcher instance let you define callbacks for any event that occur on any file or directory and subdirectories.
The inotify module is from Recipe 576375
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | '''
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()
|
If you run this module, you will see "ALL" the events that occur in the "/etc" directory (and subdirs). You will also see the last five lines of any file in "/var/log" (and subdirs) on which a "MODIFY" event occurs. (like "tail -f")