Package buildbot :: Module dnotify
[frames] | no frames]

Source Code for Module buildbot.dnotify

  1   
  2  # spiv wants this 
  3   
  4  import fcntl, signal 
  5   
6 -class DNotify_Handler:
7 - def __init__(self):
8 self.watchers = {} 9 self.installed = 0
10 - def install(self):
11 if self.installed: 12 return 13 signal.signal(signal.SIGIO, self.fire) 14 self.installed = 1
15 - def uninstall(self):
16 if not self.installed: 17 return 18 signal.signal(signal.SIGIO, signal.SIG_DFL) 19 self.installed = 0
20 - def add(self, watcher):
21 self.watchers[watcher.fd.fileno()] = watcher 22 self.install()
23 - def remove(self, watcher):
24 if self.watchers.has_key(watcher.fd.fileno()): 25 del(self.watchers[watcher.fd.fileno()]) 26 if not self.watchers: 27 self.uninstall()
28 - def fire(self, signum, frame):
29 # this is the signal handler 30 # without siginfo_t, we must fire them all 31 for watcher in self.watchers.values(): 32 watcher.callback()
33
34 -class DNotify:
35 DN_ACCESS = fcntl.DN_ACCESS # a file in the directory was read 36 DN_MODIFY = fcntl.DN_MODIFY # a file was modified (write,truncate) 37 DN_CREATE = fcntl.DN_CREATE # a file was created 38 DN_DELETE = fcntl.DN_DELETE # a file was unlinked 39 DN_RENAME = fcntl.DN_RENAME # a file was renamed 40 DN_ATTRIB = fcntl.DN_ATTRIB # a file had attributes changed (chmod,chown) 41 42 handler = [None] 43
44 - def __init__(self, dirname, callback=None, 45 flags=[DN_MODIFY,DN_CREATE,DN_DELETE,DN_RENAME]):
46 47 """This object watches a directory for changes. The .callback 48 attribute should be set to a function to be run every time something 49 happens to it. Be aware that it will be called more times than you 50 expect.""" 51 52 if callback: 53 self.callback = callback 54 else: 55 self.callback = self.fire 56 self.dirname = dirname 57 self.flags = reduce(lambda x, y: x | y, flags) | fcntl.DN_MULTISHOT 58 self.fd = open(dirname, "r") 59 # ideally we would move the notification to something like SIGRTMIN, 60 # (to free up SIGIO) and use sigaction to have the signal handler 61 # receive a structure with the fd number. But python doesn't offer 62 # either. 63 if not self.handler[0]: 64 self.handler[0] = DNotify_Handler() 65 self.handler[0].add(self) 66 fcntl.fcntl(self.fd, fcntl.F_NOTIFY, self.flags)
67 - def remove(self):
68 self.handler[0].remove(self) 69 self.fd.close()
70 - def fire(self):
71 print self.dirname, "changed!"
72
73 -def test_dnotify1():
74 d = DNotify(".") 75 while 1: 76 signal.pause()
77
78 -def test_dnotify2():
79 # create ./foo/, create/delete files in ./ and ./foo/ while this is 80 # running. Notice how both notifiers are fired when anything changes; 81 # this is an unfortunate side-effect of the lack of extended sigaction 82 # support in Python. 83 count = [0] 84 d1 = DNotify(".") 85 def fire1(count=count, d1=d1): 86 print "./ changed!", count[0] 87 count[0] += 1 88 if count[0] > 5: 89 d1.remove() 90 del(d1)
91 # change the callback, since we can't define it until after we have the 92 # dnotify object. Hmm, unless we give the dnotify to the callback. 93 d1.callback = fire1 94 def fire2(): print "foo/ changed!" 95 d2 = DNotify("foo", fire2) 96 while 1: 97 signal.pause() 98 99 100 if __name__ == '__main__': 101 test_dnotify2() 102