[Buildbot-commits] buildbot/buildbot/changes mail.py, 1.23, 1.24 maildir.py, 1.8, 1.9 maildirgtk.py, 1.1, NONE maildirtwisted.py, 1.3, NONE

Brian Warner warner at users.sourceforge.net
Tue Jan 23 21:04:34 UTC 2007


Update of /cvsroot/buildbot/buildbot/buildbot/changes
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv15423/buildbot/changes

Modified Files:
	mail.py maildir.py 
Removed Files:
	maildirgtk.py maildirtwisted.py 
Log Message:
[project @ clean up maildir usage, remove a use of reactor.iterate from tests]

Original author: warner at lothar.com
Date: 2007-01-23 21:02:10

Index: mail.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/mail.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- mail.py	11 Dec 2006 09:06:34 -0000	1.23
+++ mail.py	23 Jan 2007 21:04:32 -0000	1.24
@@ -6,8 +6,11 @@
 import os, re
 from rfc822 import Message
 
+from zope.interface import implements
 from buildbot import util
-from buildbot.changes import base, changes, maildirtwisted
+from buildbot.interfaces import IChangeSource
+from buildbot.changes import changes
+from buildbot.changes.maildir import MaildirService
 
 def parseFreshCVSMail(self, fd, prefix=None, sep="/"):
     """Parse mail sent by FreshCVS"""
@@ -294,16 +297,18 @@
 
 
 
-class MaildirSource(maildirtwisted.MaildirTwisted, base.ChangeSource):
+class MaildirSource(MaildirService, util.ComparableMixin):
     """This source will watch a maildir that is subscribed to a FreshCVS
     change-announcement mailing list.
     """
-    compare_attrs = ["basedir", "newdir", "pollinterval", "parser"]
+    implements(IChangeSource)
+
+    compare_attrs = ["basedir", "pollinterval", "parser"]
     parser = None
     name = None
 
     def __init__(self, maildir, prefix=None, sep="/"):
-        maildirtwisted.MaildirTwisted.__init__(self, maildir)
+        MaildirService.__init__(self, maildir)
         self.prefix = prefix
         self.sep = sep
 

Index: maildir.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/maildir.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- maildir.py	6 Sep 2006 00:41:54 -0000	1.8
+++ maildir.py	23 Jan 2007 21:04:32 -0000	1.9
@@ -3,80 +3,94 @@
 # This is a class which watches a maildir for new messages. It uses the
 # linux dirwatcher API (if available) to look for new files. The
 # .messageReceived method is invoked with the filename of the new message,
-# relative to the 'new' directory of the maildir.
-
-# this is an abstract base class. It must be subclassed by something to
-# provide a delay function (which polls in the case that DNotify isn't
-# available) and a way to safely schedule code to run after a signal handler
-# has fired. See maildirgtk.py and maildirtwisted.py for forms that use the
-# event loops provided by Gtk+ and Twisted.
+# relative to the top of the maildir (so it will look like "new/blahblah").
 
+import os
+from twisted.python import log
+from twisted.application import service, internet
+from twisted.internet import reactor
+dnotify = None
 try:
-    from dnotify import DNotify
-    have_dnotify = 1
+    import dnotify
 except:
-    have_dnotify = 0
-import os
+    # I'm not actually sure this log message gets recorded
+    log.msg("unable to import dnotify, so Maildir will use polling instead")
 
-class Maildir:
-    """This is a class which watches a maildir for new messages. Once
-    started, it will run its .messageReceived method when a message is
-    available.
+class NoSuchMaildir(Exception):
+    pass
+
+class MaildirService(service.MultiService):
+    """I watch a maildir for new messages. I should be placed as the service
+    child of some MultiService instance. When running, I use the linux
+    dirwatcher API (if available) or poll for new files in the 'new'
+    subdirectory of my maildir path. When I discover a new message, I invoke
+    my .messageReceived() method with the short filename of the new message,
+    so the full name of the new file can be obtained with
+    os.path.join(maildir, 'new', filename). messageReceived() should be
+    overridden by a subclass to do something useful. I will not move or
+    delete the file on my own: the subclass's messageReceived() should
+    probably do that.
     """
+    pollinterval = 10  # only used if we don't have DNotify
+
     def __init__(self, basedir=None):
         """Create the Maildir watcher. BASEDIR is the maildir directory (the
         one which contains new/ and tmp/)
         """
+        service.MultiService.__init__(self)
         self.basedir = basedir
         self.files = []
-        self.pollinterval = 10  # only used if we don't have DNotify
-        self.running = 0
         self.dnotify = None
 
     def setBasedir(self, basedir):
+        # some users of MaildirService (scheduler.Try_Jobdir, in particular)
+        # don't know their basedir until setServiceParent, since it is
+        # relative to the buildmaster's basedir. So let them set it late. We
+        # don't actually need it until our own startService.
         self.basedir = basedir
 
-    def start(self):
-        """You must run start to receive any messages."""
-        assert self.basedir
+    def startService(self):
+        service.MultiService.startService(self)
         self.newdir = os.path.join(self.basedir, "new")
-        if self.running:
-            return
-        self.running = 1
         if not os.path.isdir(self.basedir) or not os.path.isdir(self.newdir):
-            raise "invalid maildir '%s'" % self.basedir
-        # we must hold an fd open on the directory, so we can get notified
-        # when it changes.
-        global have_dnotify
-        if have_dnotify:
-            try:
-                self.dnotify = DNotify(self.newdir, self.dnotify_callback,
-                                       [DNotify.DN_CREATE])
-            except (IOError, OverflowError):
-                # IOError is probably linux<2.4.19, which doesn't support
-                # dnotify. OverflowError will occur on some 64-bit machines
-                # because of a python bug
-                print "DNotify failed, falling back to polling"
-                have_dnotify = 0
-
+            raise NoSuchMaildir("invalid maildir '%s'" % self.basedir)
+        try:
+            if dnotify:
+                # we must hold an fd open on the directory, so we can get
+                # notified when it changes.
+                self.dnotify = dnotify.DNotify(self.newdir,
+                                               self.dnotify_callback,
+                                               [dnotify.DNotify.DN_CREATE])
+        except (IOError, OverflowError):
+            # IOError is probably linux<2.4.19, which doesn't support
+            # dnotify. OverflowError will occur on some 64-bit machines
+            # because of a python bug
+            log.msg("DNotify failed, falling back to polling")
+        if not self.dnotify:
+            t = internet.TimerService(self.pollinterval, self.poll)
+            t.setServiceParent(self)
         self.poll()
 
-    def startTimeout(self):
-        raise NotImplemented
-    def stopTimeout(self):
-        raise NotImplemented
     def dnotify_callback(self):
-        print "callback"
-        self.poll()
-        raise NotImplemented
-        
-    def stop(self):
+        log.msg("dnotify noticed something, now polling")
+
+        # give it a moment. I found that qmail had problems when the message
+        # was removed from the maildir instantly. It shouldn't, that's what
+        # maildirs are made for. I wasn't able to eyeball any reason for the
+        # problem, and safecat didn't behave the same way, but qmail reports
+        # "Temporary_error_on_maildir_delivery" (qmail-local.c:165,
+        # maildir_child() process exited with rc not in 0,2,3,4). Not sure
+        # why, and I'd have to hack qmail to investigate further, so it's
+        # easier to just wait a second before yanking the message out of new/
+
+        reactor.callLater(0.1, self.poll)
+
+
+    def stopService(self):
         if self.dnotify:
             self.dnotify.remove()
             self.dnotify = None
-        else:
-            self.stopTimeout()
-        self.running = 0
+        return service.MultiService.stopService(self)
 
     def poll(self):
         assert self.basedir
@@ -94,22 +108,10 @@
         for n in newfiles:
             # TODO: consider catching exceptions in messageReceived
             self.messageReceived(n)
-        if not have_dnotify:
-            self.startTimeout()
 
     def messageReceived(self, filename):
-        """Called when a new file is noticed. Override it in subclasses.
-        Will receive path relative to maildir/new."""
-        print filename
-
+        """Called when a new file is noticed. Will call
+        self.parent.messageReceived() with a path relative to maildir/new.
+        Should probably be overridden in subclasses."""
+        self.parent.messageReceived(filename)
 
-def test1():
-    m = Maildir("ddir")
-    m.start()
-    import signal
-    while 1:
-        signal.pause()
-    
-if __name__ == '__main__':
-    test1()
-    

--- maildirgtk.py DELETED ---

--- maildirtwisted.py DELETED ---





More information about the Commits mailing list