| Trees | Indices | Help | 
        
  | 
  
|---|
| 
       | 
  
  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16   
 17  # This is a class which watches a maildir for new messages. It uses the 
 18  # linux dirwatcher API (if available) to look for new files. The 
 19  # .messageReceived method is invoked with the filename of the new message, 
 20  # relative to the top of the maildir (so it will look like "new/blahblah"). 
 21   
 22  import os 
 23  from twisted.python import log, runtime 
 24  from twisted.application import service, internet 
 25  from twisted.internet import reactor, defer 
 26  dnotify = None 
 27  try: 
 28      import dnotify 
 29  except: 
 30      log.msg("unable to import dnotify, so Maildir will use polling instead") 
 34   
 36      pollinterval = 10  # only used if we don't have DNotify 
 37   
 39          service.MultiService.__init__(self) 
 40          if basedir: 
 41              self.setBasedir(basedir) 
 42          self.files = [] 
 43          self.dnotify = None 
 44   
 46          # some users of MaildirService (scheduler.Try_Jobdir, in particular) 
 47          # don't know their basedir until setServiceParent, since it is 
 48          # relative to the buildmaster's basedir. So let them set it late. We 
 49          # don't actually need it until our own startService. 
 50          self.basedir = basedir 
 51          self.newdir = os.path.join(self.basedir, "new") 
 52          self.curdir = os.path.join(self.basedir, "cur") 
 53   
 55          service.MultiService.startService(self) 
 56          if not os.path.isdir(self.newdir) or not os.path.isdir(self.curdir): 
 57              raise NoSuchMaildir("invalid maildir '%s'" % self.basedir) 
 58          try: 
 59              if dnotify: 
 60                  # we must hold an fd open on the directory, so we can get 
 61                  # notified when it changes. 
 62                  self.dnotify = dnotify.DNotify(self.newdir, 
 63                                                 self.dnotify_callback, 
 64                                                 [dnotify.DNotify.DN_CREATE]) 
 65          except (IOError, OverflowError): 
 66              # IOError is probably linux<2.4.19, which doesn't support 
 67              # dnotify. OverflowError will occur on some 64-bit machines 
 68              # because of a python bug 
 69              log.msg("DNotify failed, falling back to polling") 
 70          if not self.dnotify: 
 71              t = internet.TimerService(self.pollinterval, self.poll) 
 72              t.setServiceParent(self) 
 73          self.poll() 
 74   
 76          log.msg("dnotify noticed something, now polling") 
 77   
 78          # give it a moment. I found that qmail had problems when the message 
 79          # was removed from the maildir instantly. It shouldn't, that's what 
 80          # maildirs are made for. I wasn't able to eyeball any reason for the 
 81          # problem, and safecat didn't behave the same way, but qmail reports 
 82          # "Temporary_error_on_maildir_delivery" (qmail-local.c:165, 
 83          # maildir_child() process exited with rc not in 0,2,3,4). Not sure 
 84          # why, and I'd have to hack qmail to investigate further, so it's 
 85          # easier to just wait a second before yanking the message out of new/ 
 86   
 87          reactor.callLater(0.1, self.poll) 
 88   
 89   
 91          if self.dnotify: 
 92              self.dnotify.remove() 
 93              self.dnotify = None 
 94          return service.MultiService.stopService(self) 
 95   
 96      @defer.inlineCallbacks 
 98          assert self.basedir 
 99          # see what's new 
100          for f in self.files: 
101              if not os.path.isfile(os.path.join(self.newdir, f)): 
102                  self.files.remove(f) 
103          newfiles = [] 
104          for f in os.listdir(self.newdir): 
105              if not f in self.files: 
106                  newfiles.append(f) 
107          self.files.extend(newfiles) 
108          for n in newfiles: 
109              try: 
110                  yield self.messageReceived(n) 
111              except: 
112                  log.msg("while reading '%s' from maildir '%s':" % (n, self.basedir)) 
113                  log.err() 
114   
116          if runtime.platformType == "posix": 
117              # open the file before moving it, because I'm afraid that once 
118              # it's in cur/, someone might delete it at any moment 
119              path = os.path.join(self.newdir, filename) 
120              f = open(path, "r") 
121              os.rename(os.path.join(self.newdir, filename), 
122                        os.path.join(self.curdir, filename)) 
123          elif runtime.platformType == "win32": 
124              # do this backwards under windows, because you can't move a file 
125              # that somebody is holding open. This was causing a Permission 
126              # Denied error on bear's win32-twisted1.3 buildslave. 
127              os.rename(os.path.join(self.newdir, filename), 
128                        os.path.join(self.curdir, filename)) 
129              path = os.path.join(self.curdir, filename) 
130              f = open(path, "r") 
131   
132          return f 
133   
136   
| Trees | Indices | Help | 
        
  | 
  
|---|
| Generated by Epydoc 3.0.1 on Wed Nov 21 16:22:52 2012 | http://epydoc.sourceforge.net |