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

Source Code for Module buildbot.changes.dnotify

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