summaryrefslogtreecommitdiff
path: root/src/mailman/archiving/prototype.py
diff options
context:
space:
mode:
authorBarry Warsaw2012-03-14 13:03:45 -0700
committerBarry Warsaw2012-03-14 13:03:45 -0700
commitd8f6ee3844e8fc7e14f8fcf12994d92028b1854c (patch)
tree39971323c1c117bf7a5b056b6eb4dab7ead21a5a /src/mailman/archiving/prototype.py
parenteb509dc0466f34f63ab6dcf159de2f9137cb3fdb (diff)
parent6fbba4bf71f27eae34dd8fa0e39faa114aa27ea3 (diff)
downloadmailman-d8f6ee3844e8fc7e14f8fcf12994d92028b1854c.tar.gz
mailman-d8f6ee3844e8fc7e14f8fcf12994d92028b1854c.tar.zst
mailman-d8f6ee3844e8fc7e14f8fcf12994d92028b1854c.zip
Diffstat (limited to 'src/mailman/archiving/prototype.py')
-rw-r--r--src/mailman/archiving/prototype.py59
1 files changed, 57 insertions, 2 deletions
diff --git a/src/mailman/archiving/prototype.py b/src/mailman/archiving/prototype.py
index 55d78074e..453c6c770 100644
--- a/src/mailman/archiving/prototype.py
+++ b/src/mailman/archiving/prototype.py
@@ -25,11 +25,22 @@ __all__ = [
]
+import os
+import errno
+import logging
+
+from datetime import timedelta
+from mailbox import Maildir
from urlparse import urljoin
+
+from flufl.lock import Lock, TimeOutError
from zope.interface import implements
+from mailman.config import config
from mailman.interfaces.archiver import IArchiver
+log = logging.getLogger('mailman.error')
+
class Prototype:
@@ -61,5 +72,49 @@ class Prototype:
@staticmethod
def archive_message(mlist, message):
- """See `IArchiver`."""
- raise NotImplementedError
+ """See `IArchiver`.
+
+ This archiver saves messages into a maildir.
+ """
+ archive_dir = os.path.join(config.ARCHIVE_DIR, 'prototype')
+ try:
+ os.makedirs(archive_dir, 0775)
+ except OSError as error:
+ # If this already exists, then we're fine
+ if error.errno != errno.EEXIST:
+ raise
+
+ # Maildir will throw an error if the directories are partially created
+ # (for instance the toplevel exists but cur, new, or tmp do not)
+ # therefore we don't create the toplevel as we did above.
+ list_dir = os.path.join(archive_dir, mlist.fqdn_listname)
+ mailbox = Maildir(list_dir, create=True, factory=None)
+ lock_file = os.path.join(
+ config.LOCK_DIR, '{0}-maildir.lock'.format(mlist.fqdn_listname))
+
+ # Lock the maildir as Maildir.add() is not threadsafe. Don't use the
+ # context manager because it's not an error if we can't acquire the
+ # archiver lock. We'll just log the problem and continue.
+ #
+ # XXX 2012-03-14 BAW: When we extend the chain/pipeline architecture
+ # to other runners, e.g. the archive runner, it would be better to let
+ # any TimeOutError propagate up. That would cause the message to be
+ # re-queued and tried again later, rather than being discarded as
+ # happens now below.
+ lock = Lock(lock_file)
+ try:
+ lock.lock(timeout=timedelta(seconds=1))
+ # Add the message to the maildir. The return value could be used
+ # to construct the file path if necessary. E.g.
+ #
+ # os.path.join(archive_dir, mlist.fqdn_listname, 'new',
+ # message_key)
+ mailbox.add(message)
+ except TimeOutError:
+ # Log the error and go on.
+ log.error('Unable to acquire prototype archiver lock for {0}, '
+ 'discarding: {1}'.format(
+ mlist.fqdn_listname,
+ message.get('message-id', 'n/a')))
+ finally:
+ lock.unlock(unconditionally=True)