use maildir for MonthlyArchiver

This commit is contained in:
Max Erenberg 2021-04-10 01:31:29 -04:00
parent 686729b916
commit a1dec6a0b2
1 changed files with 29 additions and 15 deletions

View File

@ -20,17 +20,20 @@
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
"""
A simple archiver which copies each message into a folder for the current
month.
A simple archiver which copies each message into a maildir folder for the
current year and month.
"""
from contextlib import suppress
from datetime import timedelta
from email.utils import parsedate
import gzip
import logging
from mailbox import Mailbox
import os
import time
from flufl.lock import Lock
from mailbox import Maildir
from mailman.config import config
from mailman.interfaces.archiver import IArchiver
from public import public
@ -44,7 +47,7 @@ log = logging.getLogger('mailman.archiver')
@implementer(IArchiver)
class MonthlyArchiver:
"""
A simple archiver which copies each message into a folder for the
A simple archiver which copies each message into a maildir for the
current month. It is adapted from the `Prototype` archiver.
"""
@ -67,8 +70,8 @@ class MonthlyArchiver:
def archive_message(mlist, message):
"""See `IArchiver`.
This archiver saves messages into a folder for the current year and
month, e.g. '2021-April'.
This archiver saves messages into a maildir for the current year and
month, e.g. '2021/April'.
:type mlist: mailman.model.listmanager.ListManager
:type message: mailman.email.message.Message
@ -81,24 +84,35 @@ class MonthlyArchiver:
log.warning('Could not extract date from message %s, using '
'local time instead' % message_id)
date = time.localtime()
year_and_month = time.strftime('%Y-%B', date)
year = time.strftime('%Y')
month = time.strftime('%B')
archive_dir = os.path.join(
config.ARCHIVE_DIR,
MonthlyArchiver.name,
mlist.fqdn_listname,
year_and_month
year,
month
)
with suppress(FileExistsError):
os.makedirs(archive_dir, 0o775)
for subdir in ['cur', 'new', 'tmp']:
with suppress(FileExistsError):
os.makedirs(os.path.join(archive_dir, subdir), 0o775)
maildir = Maildir(archive_dir, create=True)
# maildir.add() is not thread-safe
lock_file = os.path.join(
config.LOCK_DIR, '{0}-maildir.lock'.format(mlist.fqdn_listname))
lock = Lock(lock_file)
try:
lock.lock(timeout=timedelta(seconds=3))
filename = maildir.add(message)
finally:
lock.unlock(unconditionally=True)
# If we fail to acquire the lock, let the error propagate up
# Just use the current timestamp as the file name
filename = str(round(time.time(), 3)) + '.mail.gz'
dst = os.path.join(archive_dir, filename)
log.info('MonthlyArchiver archived message %s to %s' %
(message_id, dst))
# gzip the file to try to save some disk space
with gzip.open(dst, 'wb') as fo:
fo.write(message.as_bytes())
(message_id, filename))
return None