summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Archiver/HyperArch.py6
-rw-r--r--Mailman/Archiver/HyperDatabase.py4
-rw-r--r--Mailman/Handlers/Scrubber.py11
-rw-r--r--Mailman/MTA/Manual.py2
-rw-r--r--Mailman/MTA/Postfix.py16
-rw-r--r--Mailman/MailList.py104
-rw-r--r--Mailman/app/lifecycle.py1
-rw-r--r--Mailman/bin/arch.py85
-rw-r--r--Mailman/bin/gate_news.py21
-rw-r--r--Mailman/bin/mailmanctl.py8
-rw-r--r--Mailman/bin/withlist.py44
-rw-r--r--Mailman/database/__init__.py9
-rw-r--r--Mailman/database/usermanager.py1
-rw-r--r--Mailman/lockfile.py (renamed from Mailman/LockFile.py)8
-rw-r--r--Mailman/queue/archive.py16
-rw-r--r--Mailman/queue/bounce.py1
-rw-r--r--Mailman/queue/command.py36
-rw-r--r--Mailman/queue/incoming.py24
-rw-r--r--Mailman/queue/outgoing.py1
-rw-r--r--Mailman/tests/test_lockfile.py2
20 files changed, 111 insertions, 289 deletions
diff --git a/Mailman/Archiver/HyperArch.py b/Mailman/Archiver/HyperArch.py
index 80d4ea7a4..7ce0905ca 100644
--- a/Mailman/Archiver/HyperArch.py
+++ b/Mailman/Archiver/HyperArch.py
@@ -43,10 +43,10 @@ from email.Errors import HeaderParseError
from email.Header import decode_header, make_header
from Mailman import Errors
-from Mailman import LockFile
from Mailman import MailList
from Mailman import Utils
from Mailman import i18n
+from Mailman import lockfile
from Mailman.Archiver import HyperDatabase
from Mailman.Archiver import pipermail
from Mailman.Mailbox import ArchiverMailbox
@@ -786,12 +786,12 @@ class HyperArchive(pipermail.T):
def GetArchLock(self):
if self._lock_file:
return 1
- self._lock_file = LockFile.LockFile(
+ self._lock_file = lockfile.LockFile(
os.path.join(config.LOCK_DIR,
self.maillist.fqdn_listname + '-arch.lock'))
try:
self._lock_file.lock(timeout=0.5)
- except LockFile.TimeOutError:
+ except lockfile.TimeOutError:
return 0
return 1
diff --git a/Mailman/Archiver/HyperDatabase.py b/Mailman/Archiver/HyperDatabase.py
index 36c299846..3644fbc58 100644
--- a/Mailman/Archiver/HyperDatabase.py
+++ b/Mailman/Archiver/HyperDatabase.py
@@ -27,7 +27,7 @@ import errno
# package/project modules
#
import pipermail
-from Mailman import LockFile
+from Mailman.lockfile import LockFile
CACHESIZE = pipermail.CACHESIZE
@@ -58,7 +58,7 @@ class DumbBTree:
def __init__(self, path):
self.current_index = 0
self.path = path
- self.lockfile = LockFile.LockFile(self.path + ".lock")
+ self.lockfile = LockFile(self.path + ".lock")
self.lock()
self.__dirty = 0
self.dict = {}
diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py
index 655742899..3f29fc02b 100644
--- a/Mailman/Handlers/Scrubber.py
+++ b/Mailman/Handlers/Scrubber.py
@@ -17,6 +17,8 @@
"""Cleanse a message for archiving."""
+from __future__ import with_statement
+
import os
import re
import sha
@@ -34,13 +36,13 @@ from email.generator import Generator
from email.parser import HeaderParser
from email.utils import make_msgid, parsedate
-from Mailman import LockFile
from Mailman import Message
from Mailman import Utils
from Mailman.Errors import DiscardMessage
from Mailman.app.archiving import get_base_archive_url
from Mailman.configuration import config
from Mailman.i18n import _
+from Mailman.lockfile import LockFile
# Path characters for common platforms
pre = re.compile(r'[/\\:]')
@@ -422,10 +424,7 @@ def save_attachment(mlist, msg, dir, filter_html=True):
ext = '.bin'
path = None
# We need a lock to calculate the next attachment number
- lockfile = os.path.join(fsdir, 'attachments.lock')
- lock = LockFile.LockFile(lockfile)
- lock.lock()
- try:
+ with LockFile(os.path.join(fsdir, 'attachments.lock')):
# Now base the filename on what's in the attachment, uniquifying it if
# necessary.
if not filename or config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME:
@@ -461,8 +460,6 @@ def save_attachment(mlist, msg, dir, filter_html=True):
extra = '-%04d' % counter
else:
break
- finally:
- lock.unlock()
# `path' now contains the unique filename for the attachment. There's
# just one more step we need to do. If the part is text/html and
# ARCHIVE_HTML_SANITIZER is a string (which it must be or we wouldn't be
diff --git a/Mailman/MTA/Manual.py b/Mailman/MTA/Manual.py
index 953d46695..0d9a4bca7 100644
--- a/Mailman/MTA/Manual.py
+++ b/Mailman/MTA/Manual.py
@@ -98,7 +98,7 @@ equivalent) file by adding the following lines, and possibly running the
def remove(mlist, cgi=False):
- listname = mlist.internal_name()
+ listname = mlist.fqdn_listname
fieldsz = len(listname) + len('-unsubscribe')
if cgi:
# If a list is being removed via the CGI, the best we can do is send
diff --git a/Mailman/MTA/Postfix.py b/Mailman/MTA/Postfix.py
index 6b43011ff..1712bb638 100644
--- a/Mailman/MTA/Postfix.py
+++ b/Mailman/MTA/Postfix.py
@@ -17,6 +17,8 @@
"""Creation/deletion hooks for the Postfix MTA."""
+from __future__ import with_statement
+
import os
import grp
import pwd
@@ -26,11 +28,11 @@ import logging
from stat import *
-from Mailman import LockFile
from Mailman import Utils
from Mailman.MTA.Utils import makealiases
from Mailman.configuration import config
from Mailman.i18n import _
+from Mailman.lockfile import LockFile
LOCKFILE = os.path.join(config.LOCK_DIR, 'creator')
ALIASFILE = os.path.join(config.DATA_DIR, 'aliases')
@@ -66,10 +68,6 @@ def _update_maps():
-def makelock():
- return LockFile.LockFile(LOCKFILE)
-
-
def _zapfile(filename):
# Truncate the file w/o messing with the file permissions, but only if it
# already exists.
@@ -274,6 +272,7 @@ def create(mlist, cgi=False, nolock=False, quiet=False):
# Acquire the global list database lock. quiet flag is ignored.
lock = None
if not nolock:
+ # XXX FIXME
lock = makelock()
lock.lock()
# Do the aliases file, which always needs to be done
@@ -339,9 +338,7 @@ def _do_remove(mlist, textfile):
def remove(mlist, cgi=False):
# Acquire the global list database lock
- lock = makelock()
- lock.lock()
- try:
+ with LockFile(LOCKFILE):
if config.USE_LMTP:
_do_remove(mlist, TRPTFILE)
else:
@@ -350,8 +347,7 @@ def remove(mlist, cgi=False):
_do_remove(mlist, VIRTFILE)
# Regenerate the alias and map files
_update_maps()
- finally:
- lock.unlock(unconditionally=True)
+ config.db.commit()
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index d90de18f0..335d82581 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -47,7 +47,6 @@ from email.Header import Header
from email.Utils import getaddresses, formataddr, parseaddr
from Mailman import Errors
-from Mailman import LockFile
from Mailman import Utils
from Mailman import Version
from Mailman import database
@@ -132,36 +131,6 @@ class MailList(object, Archiver, Digester, SecurityManager, Bouncer):
return '<mailing list "%s" at %x>' % (self.fqdn_listname, id(self))
- #
- # Lock management
- #
- def _make_lock(self, name, lock=False):
- self._lock = LockFile.LockFile(
- os.path.join(config.LOCK_DIR, name) + '.lock',
- lifetime=config.LIST_LOCK_LIFETIME)
- if lock:
- self._lock.lock()
-
- def Lock(self, timeout=0):
- self._lock.lock(timeout)
- self._memberadaptor.lock()
- # Must reload our database for consistency. Watch out for lists that
- # don't exist.
- try:
- self.Load()
- except Exception:
- self.Unlock()
- raise
-
- def Unlock(self):
- self._lock.unlock(unconditionally=True)
- self._memberadaptor.unlock()
-
- def Locked(self):
- return self._lock.locked()
-
-
-
def GetConfirmJoinSubject(self, listname, cookie):
if config.VERP_CONFIRMATIONS and cookie:
cset = i18n.get_translation().charset() or \
@@ -258,59 +227,6 @@ class MailList(object, Archiver, Digester, SecurityManager, Bouncer):
return value
- def Save(self):
- # Refresh the lock, just to let other processes know we're still
- # interested in it. This will raise a NotLockedError if we don't have
- # the lock (which is a serious problem!). TBD: do we need to be more
- # defensive?
- self._lock.refresh()
- # The member adaptor may have its own save operation
- self._memberadaptor.save()
- self.CheckHTMLArchiveDir()
-
- def Load(self):
- self._memberadaptor.load()
-
-
-
- #
- # Sanity checks
- #
- def CheckValues(self):
- """Normalize selected values to known formats."""
- if '' in urlparse(self.web_page_url)[:2]:
- # Either the "scheme" or the "network location" part of the parsed
- # URL is empty; substitute faulty value with (hopefully sane)
- # default. Note that DEFAULT_URL is obsolete.
- self.web_page_url = (
- config.DEFAULT_URL or
- config.DEFAULT_URL_PATTERN % config.DEFAULT_URL_HOST)
- if self.web_page_url and self.web_page_url[-1] <> '/':
- self.web_page_url = self.web_page_url + '/'
- # Legacy reply_to_address could be an illegal value. We now verify
- # upon setting and don't check it at the point of use.
- try:
- if self.reply_to_address.strip() and self.reply_goes_to_list:
- Utils.ValidateEmail(self.reply_to_address)
- except Errors.EmailAddressError:
- elog.error('Bad reply_to_address "%s" cleared for list: %s',
- self.reply_to_address, self.internal_name())
- self.reply_to_address = ''
- self.reply_goes_to_list = 0
- # Legacy topics may have bad regular expressions in their patterns
- goodtopics = []
- for name, pattern, desc, emptyflag in self.topics:
- try:
- orpattern = OR.join(pattern.splitlines())
- re.compile(orpattern)
- except (re.error, TypeError):
- elog.error('Bad topic pattern "%s" for list: %s',
- orpattern, self.internal_name())
- else:
- goodtopics.append((name, pattern, desc, emptyflag))
- self.topics = goodtopics
-
-
#
# Membership management front-ends and assertion checks
#
@@ -479,26 +395,6 @@ class MailList(object, Archiver, Digester, SecurityManager, Bouncer):
raise Errors.MMNeedApproval, _(
'unsubscriptions require moderator approval')
- def ChangeMemberName(self, addr, name, globally):
- self.setMemberName(addr, name)
- if not globally:
- return
- for listname in config.list_manager.names:
- # Don't bother with ourselves
- if listname == self.internal_name():
- continue
- mlist = MailList(listname, lock=0)
- if mlist.host_name <> self.host_name:
- continue
- if not mlist.isMember(addr):
- continue
- mlist.Lock()
- try:
- mlist.setMemberName(addr, name)
- mlist.Save()
- finally:
- mlist.Unlock()
-
def ChangeMemberAddress(self, oldaddr, newaddr, globally):
# Changing a member address consists of verifying the new address,
# making sure the new address isn't already a member, and optionally
diff --git a/Mailman/app/lifecycle.py b/Mailman/app/lifecycle.py
index 8abb14c69..251ded2b8 100644
--- a/Mailman/app/lifecycle.py
+++ b/Mailman/app/lifecycle.py
@@ -18,6 +18,7 @@
"""Application level list creation."""
import os
+import sys
import shutil
import logging
diff --git a/Mailman/bin/arch.py b/Mailman/bin/arch.py
index a7929e407..09ca4d914 100644
--- a/Mailman/bin/arch.py
+++ b/Mailman/bin/arch.py
@@ -15,6 +15,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
+from __future__ import with_statement
+
import os
import sys
import errno
@@ -25,9 +27,10 @@ from Mailman import Errors
from Mailman import Version
from Mailman import i18n
from Mailman.Archiver.HyperArch import HyperArchive
-from Mailman.LockFile import LockFile
+from Mailman.Defaults import hours
from Mailman.MailList import MailList
from Mailman.configuration import config
+from Mailman.lockfile import LockFile
_ = i18n._
__i18n_templates__ = True
@@ -119,53 +122,41 @@ def main():
# really don't know how long it will take.
#
# XXX processUnixMailbox() should refresh the lock.
- #
- # XXX This may not be necessary because I think we lay claim to the
- # list lock up above, although that may be too short to be of use (and
- # maybe we don't really want to lock the list anyway).
- lockfile = os.path.join(config.LOCK_DIR, mlist._internal_name) + \
- '.archiver.lock'
- # set the lock lifetime to 3 hours. XXX is this reasonable???
- lock = LockFile(lockfile, lifetime=3*60*60)
- lock.lock()
- # Maybe wipe the old archives
- if opts.wipe:
- if mlist.scrub_nondigest:
- # TK: save the attachments dir because they are not in mbox
- saved = False
- atchdir = os.path.join(mlist.archive_dir(), 'attachments')
- savedir = os.path.join(mlist.archive_dir() + '.mbox',
- 'attachments')
- try:
- os.rename(atchdir, savedir)
- saved = True
- except OSError, e:
- if e.errno <> errno.ENOENT:
- raise
- shutil.rmtree(mlist.archive_dir())
- if mlist.scrub_nondigest and saved:
- os.renames(savedir, atchdir)
- try:
- fp = open(mbox)
- except IOError, e:
- if e.errno == errno.ENOENT:
- print >> sys.stderr, _('Cannot open mbox file: $mbox')
- else:
- print >> sys.stderr, e
- sys.exit(1)
+ with LockFile(os.path.join(mlist.full_path, '.archiver.lck'),
+ lifetime=int(hours(3))):
+ # Maybe wipe the old archives
+ if opts.wipe:
+ if mlist.scrub_nondigest:
+ # TK: save the attachments dir because they are not in mbox
+ saved = False
+ atchdir = os.path.join(mlist.archive_dir(), 'attachments')
+ savedir = os.path.join(mlist.archive_dir() + '.mbox',
+ 'attachments')
+ try:
+ os.rename(atchdir, savedir)
+ saved = True
+ except OSError, e:
+ if e.errno <> errno.ENOENT:
+ raise
+ shutil.rmtree(mlist.archive_dir())
+ if mlist.scrub_nondigest and saved:
+ os.renames(savedir, atchdir)
+ try:
+ fp = open(mbox)
+ except IOError, e:
+ if e.errno == errno.ENOENT:
+ print >> sys.stderr, _('Cannot open mbox file: $mbox')
+ else:
+ print >> sys.stderr, e
+ sys.exit(1)
- archiver = HyperArchive(mlist)
- archiver.VERBOSE = opts.verbose
- try:
- archiver.processUnixMailbox(fp, opts.start, opts.end)
- finally:
- archiver.close()
- fp.close()
- finally:
- if lock:
- lock.unlock()
- if mlist:
- mlist.Unlock()
+ archiver = HyperArchive(mlist)
+ archiver.VERBOSE = opts.verbose
+ try:
+ archiver.processUnixMailbox(fp, opts.start, opts.end)
+ finally:
+ archiver.close()
+ fp.close()
diff --git a/Mailman/bin/gate_news.py b/Mailman/bin/gate_news.py
index da78b6068..6fc8139c6 100644
--- a/Mailman/bin/gate_news.py
+++ b/Mailman/bin/gate_news.py
@@ -15,6 +15,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
+from __future__ import with_statement
+
import os
import sys
import time
@@ -26,11 +28,11 @@ import optparse
import email.Errors
from email.Parser import Parser
-from Mailman import LockFile
from Mailman import MailList
from Mailman import Message
from Mailman import Utils
from Mailman import Version
+from Mailman import lockfile
from Mailman import loginit
from Mailman.configuration import config
from Mailman.i18n import _
@@ -210,7 +212,7 @@ def process_lists(glock):
# loop over range, and this will not include the last
# element in the list.
poll_newsgroup(mlist, conn, start, last + 1, glock)
- except LockFile.TimeOutError:
+ except lockfile.TimeOutError:
log.error('Could not acquire list lock: %s', listname)
finally:
if mlist.Locked():
@@ -230,19 +232,14 @@ def main():
loginit.initialize(propagate=True)
log = logging.getLogger('mailman.fromusenet')
- lock = LockFile.LockFile(GATENEWS_LOCK_FILE,
- # It's okay to hijack this
- lifetime=LOCK_LIFETIME)
try:
- lock.lock(timeout=0.5)
+ with lockfile.LockFile(GATENEWS_LOCK_FILE,
+ # It's okay to hijack this
+ lifetime=LOCK_LIFETIME):
+ process_lists(lock)
+ clearcache()
except LockFile.TimeOutError:
log.error('Could not acquire gate_news lock')
- return
- try:
- process_lists(lock)
- finally:
- clearcache()
- lock.unlock(unconditionally=True)
diff --git a/Mailman/bin/mailmanctl.py b/Mailman/bin/mailmanctl.py
index f6190f685..07716029b 100644
--- a/Mailman/bin/mailmanctl.py
+++ b/Mailman/bin/mailmanctl.py
@@ -27,9 +27,9 @@ import optparse
from Mailman import Defaults
from Mailman import Errors
-from Mailman import LockFile
from Mailman import Utils
from Mailman import Version
+from Mailman import lockfile
from Mailman import loginit
from Mailman.configuration import config
from Mailman.i18n import _
@@ -197,11 +197,11 @@ def qrunner_state():
def acquire_lock_1(force):
# Be sure we can acquire the master qrunner lock. If not, it means some
# other master qrunner daemon is already going.
- lock = LockFile.LockFile(config.LOCK_FILE, LOCK_LIFETIME)
+ lock = lockfile.LockFile(config.LOCK_FILE, LOCK_LIFETIME)
try:
lock.lock(0.1)
return lock
- except LockFile.TimeOutError:
+ except lockfile.TimeOutError:
if not force:
raise
# Force removal of lock first
@@ -216,7 +216,7 @@ def acquire_lock(force):
try:
lock = acquire_lock_1(force)
return lock
- except LockFile.TimeOutError:
+ except lockfile.TimeOutError:
status = qrunner_state()
if status == 1:
# host matches and proc exists
diff --git a/Mailman/bin/withlist.py b/Mailman/bin/withlist.py
index cf40ddabd..dc820eb90 100644
--- a/Mailman/bin/withlist.py
+++ b/Mailman/bin/withlist.py
@@ -17,7 +17,6 @@
import os
import sys
-import atexit
import optparse
from Mailman import Errors
@@ -31,20 +30,6 @@ __i18n_templates__ = True
LAST_MLIST = None
VERBOSE = True
-LOCK = False
-
-
-
-def exitfunc(mlist):
- """Unlock a locked list, but do not implicitly Save() it."""
- if mlist.Locked():
- if VERBOSE:
- listname = mlist.fqdn_listname
- print >> sys.stderr, _(
- 'Unlocking (but not saving) list: $listname')
- mlist.Unlock()
- if VERBOSE:
- print >> sys.stderr, _('Finalizing')
@@ -54,18 +39,12 @@ def do_list(listname, args, func):
if '@' not in listname:
listname += '@' + config.DEFAULT_EMAIL_HOST
- if VERBOSE:
- print >> sys.stderr, _('Loading list $listname'),
- if LOCK:
- print >> sys.stderr, _('(locked)')
- else:
- print >> sys.stderr, _('(unlocked)')
-
mlist = config.db.list_manager.get(listname)
if mlist is None:
print >> sys.stderr, _('Unknown list: $listname')
else:
- atexit.register(exitfunc, mlist)
+ if VERBOSE:
+ print >> sys.stderr, _('Loaded list: $listname')
LAST_MLIST = mlist
# Try to import the module and run the callable.
if func:
@@ -107,7 +86,7 @@ Now, from the command line you can print the list's posting address by running
the following from the command line:
% bin/withlist -r listaddr mylist
- Loading list: mylist (unlocked)
+ Loading list: mylist
Importing listaddr ...
Running listaddr.listaddr() ...
mylist@myhost.com
@@ -115,7 +94,7 @@ the following from the command line:
And you can print the list's request address by running:
% bin/withlist -r listaddr.requestaddr mylist
- Loading list: mylist (unlocked)
+ Loading list: mylist
Importing listaddr ...
Running listaddr.requestaddr() ...
mylist-request@myhost.com
@@ -136,15 +115,6 @@ called 'changepw.py':
and run this from the command line:
% bin/withlist -l -r changepw mylist somebody@somewhere.org foobar"""))
- parser.add_option('-l', '--lock',
- default=False, action='store_true', help=_("""\
-Lock the list when opening. Normally the list is opened unlocked (e.g. for
-read-only operations). You can always lock the file after the fact by typing
-'m.Lock()'
-
-Note that if you use this option, you should explicitly call m.Save() before
-exiting, since the interpreter's clean up procedure will not automatically
-save changes to the IMailingList object (but it will unlock the list)."""))
parser.add_option('-i', '--interactive',
default=None, action='store_true', help=_("""\
Leaves you at an interactive prompt after all other processing is complete.
@@ -180,14 +150,12 @@ the results."""))
def main():
- global LAST_MLIST, LOCK, VERBOSE
+ global LAST_MLIST, VERBOSE
parser, opts, args = parseargs()
initialize(opts.config, not opts.quiet)
VERBOSE = not opts.quiet
- LOCK = opts.lock
-
# The default for interact is true unless -r was given
if opts.interactive is None:
if not opts.run:
@@ -241,5 +209,5 @@ def main():
"The variable 'm' is the $listname mailing list")
else:
banner = interact.DEFAULT_BANNER
- overrides = dict(m=LAST_MLIST, r=r)
+ overrides = dict(m=LAST_MLIST, r=r, flush=config.db.flush)
interact.interact(upframe=False, banner=banner, overrides=overrides)
diff --git a/Mailman/database/__init__.py b/Mailman/database/__init__.py
index 9c3cf39ea..e9c338952 100644
--- a/Mailman/database/__init__.py
+++ b/Mailman/database/__init__.py
@@ -56,13 +56,12 @@ class StockDatabase:
self.requests = None
def initialize(self):
- from Mailman.LockFile import LockFile
from Mailman.configuration import config
from Mailman.database import model
- # Serialize this so we don't get multiple processes trying to create the
- # database at the same time.
- lockfile = os.path.join(config.LOCK_DIR, '<dbcreatelock>')
- with LockFile(lockfile):
+ from Mailman.lockfile import LockFile
+ # Serialize this so we don't get multiple processes trying to create
+ # the database at the same time.
+ with LockFile(os.path.join(config.LOCK_DIR, 'dbcreate.lck')):
model.initialize()
self.list_manager = ListManager()
self.user_manager = UserManager()
diff --git a/Mailman/database/usermanager.py b/Mailman/database/usermanager.py
index 038427879..1958080fd 100644
--- a/Mailman/database/usermanager.py
+++ b/Mailman/database/usermanager.py
@@ -25,7 +25,6 @@ from elixir import *
from zope.interface import implements
from Mailman import Errors
-from Mailman.LockFile import LockFile
from Mailman.configuration import config
from Mailman.database.model import *
from Mailman.interfaces import IUserManager
diff --git a/Mailman/LockFile.py b/Mailman/lockfile.py
index 9323b4895..7db746952 100644
--- a/Mailman/LockFile.py
+++ b/Mailman/lockfile.py
@@ -47,6 +47,14 @@ data. In a distributed (NFS) environment, you also need to make sure that
your clocks are properly synchronized.
"""
+__metaclass__ = type
+__all__ = [
+ 'LockError',
+ 'AlreadyLockedError',
+ 'NotLockedError',
+ 'LockFile',
+ ]
+
# This code has undergone several revisions, with contributions from Barry
# Warsaw, Thomas Wouters, Harald Meland, and John Viega. It should also work
# well outside of Mailman so it could be used for other Python projects
diff --git a/Mailman/queue/archive.py b/Mailman/queue/archive.py
index c6565e11d..b0274d49c 100644
--- a/Mailman/queue/archive.py
+++ b/Mailman/queue/archive.py
@@ -17,11 +17,13 @@
"""Archive queue runner."""
+from __future__ import with_statement
+
import time
from email.Utils import parsedate_tz, mktime_tz, formatdate
-from Mailman import LockFile
from Mailman.configuration import config
+from Mailman.lockfile import LockFile
from Mailman.queue import Runner
@@ -64,14 +66,6 @@ class ArchiveRunner(Runner):
msg['X-Original-Date'] = originaldate
# Always put an indication of when we received the message.
msg['X-List-Received-Date'] = receivedtime
- # Now try to get the list lock
- try:
- mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT)
- except LockFile.TimeOutError:
- # oh well, try again later
- return 1
- try:
+ # While a list archiving lock is acquired, archive the message.
+ with LockFile(os.path.join(mlist.full_path, 'archive.lck')):
mlist.ArchiveMail(msg)
- mlist.Save()
- finally:
- mlist.Unlock()
diff --git a/Mailman/queue/bounce.py b/Mailman/queue/bounce.py
index 361b01fac..07fb3ab27 100644
--- a/Mailman/queue/bounce.py
+++ b/Mailman/queue/bounce.py
@@ -27,7 +27,6 @@ from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from email.Utils import parseaddr
-from Mailman import LockFile
from Mailman import Utils
from Mailman.Bouncers import BouncerAPI
from Mailman.Message import UserNotification
diff --git a/Mailman/queue/command.py b/Mailman/queue/command.py
index a67e757f3..ca53d0192 100644
--- a/Mailman/queue/command.py
+++ b/Mailman/queue/command.py
@@ -31,7 +31,6 @@ from email.Iterators import typed_subpart_iterator
from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
-from Mailman import LockFile
from Mailman import Message
from Mailman import Utils
from Mailman.Handlers import Replybot
@@ -214,29 +213,18 @@ class CommandRunner(Runner):
return False
# Now craft the response
res = Results(mlist, msg, msgdata)
- # BAW: Not all the functions of this qrunner require the list to be
- # locked. Still, it's more convenient to lock it here and now and
- # deal with lock failures in one place.
- try:
- mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT)
- except LockFile.TimeOutError:
- # Oh well, try again later
- return True
# This message will have been delivered to one of mylist-request,
# mylist-join, or mylist-leave, and the message metadata will contain
# a key to which one was used.
- try:
- if msgdata.get('torequest'):
- res.process()
- elif msgdata.get('tojoin'):
- res.do_command('join')
- elif msgdata.get('toleave'):
- res.do_command('leave')
- elif msgdata.get('toconfirm'):
- mo = re.match(config.VERP_CONFIRM_REGEXP, msg.get('to', ''))
- if mo:
- res.do_command('confirm', (mo.group('cookie'),))
- res.send_response()
- mlist.Save()
- finally:
- mlist.Unlock()
+ if msgdata.get('torequest'):
+ res.process()
+ elif msgdata.get('tojoin'):
+ res.do_command('join')
+ elif msgdata.get('toleave'):
+ res.do_command('leave')
+ elif msgdata.get('toconfirm'):
+ mo = re.match(config.VERP_CONFIRM_REGEXP, msg.get('to', ''))
+ if mo:
+ res.do_command('confirm', (mo.group('cookie'),))
+ res.send_response()
+ config.db.commit()
diff --git a/Mailman/queue/incoming.py b/Mailman/queue/incoming.py
index 05ab924e6..6118a7ca0 100644
--- a/Mailman/queue/incoming.py
+++ b/Mailman/queue/incoming.py
@@ -102,7 +102,6 @@ import logging
from cStringIO import StringIO
from Mailman import Errors
-from Mailman import LockFile
from Mailman.configuration import config
from Mailman.queue import Runner
@@ -117,12 +116,6 @@ class IncomingRunner(Runner):
def _dispose(self, mlist, msg, msgdata):
if msgdata.get('envsender') is None:
msg['envsender'] = mlist.no_reply_address
- # Try to get the list lock.
- try:
- mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT)
- except LockFile.TimeOutError:
- # Oh well, try again later
- return 1
# Process the message through a handler pipeline. The handler
# pipeline can actually come from one of three places: the message
# metadata, the mlist, or the global pipeline.
@@ -131,16 +124,13 @@ class IncomingRunner(Runner):
# will contain the retry pipeline. Use this above all else.
# Otherwise, if the mlist has a `pipeline' attribute, it should be
# used. Final fallback is the global pipeline.
- try:
- pipeline = self._get_pipeline(mlist, msg, msgdata)
- msgdata['pipeline'] = pipeline
- more = self._dopipeline(mlist, msg, msgdata, pipeline)
- if not more:
- del msgdata['pipeline']
- mlist.Save()
- return more
- finally:
- mlist.Unlock()
+ pipeline = self._get_pipeline(mlist, msg, msgdata)
+ msgdata['pipeline'] = pipeline
+ more = self._dopipeline(mlist, msg, msgdata, pipeline)
+ if not more:
+ del msgdata['pipeline']
+ config.db.commit()
+ return more
# Overridable
def _get_pipeline(self, mlist, msg, msgdata):
diff --git a/Mailman/queue/outgoing.py b/Mailman/queue/outgoing.py
index a1e64096d..8322766a4 100644
--- a/Mailman/queue/outgoing.py
+++ b/Mailman/queue/outgoing.py
@@ -26,7 +26,6 @@ import socket
import logging
from Mailman import Errors
-from Mailman import LockFile
from Mailman import Message
from Mailman.configuration import config
from Mailman.queue import Runner, Switchboard
diff --git a/Mailman/tests/test_lockfile.py b/Mailman/tests/test_lockfile.py
index ae0753578..9d6420e74 100644
--- a/Mailman/tests/test_lockfile.py
+++ b/Mailman/tests/test_lockfile.py
@@ -22,7 +22,7 @@ import shutil
import tempfile
import unittest
-from Mailman.LockFile import LockFile
+from Mailman.lockfile import LockFile
LOCKFILE_NAME = '.mm-test-lock'