summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Defaults.py12
-rw-r--r--Mailman/database/__init__.py47
-rw-r--r--Mailman/initialize.py49
-rw-r--r--Mailman/interfaces/database.py48
-rw-r--r--setup.py6
5 files changed, 122 insertions, 40 deletions
diff --git a/Mailman/Defaults.py b/Mailman/Defaults.py
index 3c06b709a..7667bc753 100644
--- a/Mailman/Defaults.py
+++ b/Mailman/Defaults.py
@@ -1,5 +1,3 @@
-# -*- python -*-
-
# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
@@ -19,11 +17,6 @@
"""Distributed default settings for significant Mailman config variables."""
-# NEVER make site configuration changes to this file. ALWAYS make them in
-# mm_cfg.py instead, in the designated area. See the comments in that file
-# for details.
-
-
import os
from munepy import Enum
@@ -110,11 +103,6 @@ DEFAULT_VAR_DIRECTORY = '/var/mailman'
# Database options
#####
-# Initialization function for creating the IListManager, IUserManager, and
-# IMessageManager objects, as a Python dotted name. This function must take
-# zero arguments.
-MANAGERS_INIT_FUNCTION = 'Mailman.database.initialize'
-
# Use this to set the SQLAlchemy database engine URL. You generally have one
# primary database connection for all of Mailman. List data and most rosters
# will store their data in this database, although external rosters may access
diff --git a/Mailman/database/__init__.py b/Mailman/database/__init__.py
index 6c6312d0a..d50c33973 100644
--- a/Mailman/database/__init__.py
+++ b/Mailman/database/__init__.py
@@ -20,30 +20,45 @@ from __future__ import with_statement
import os
from elixir import objectstore
+from zope.interface import implements
+from Mailman.interfaces import IDatabase
from Mailman.database.listmanager import ListManager
from Mailman.database.usermanager import UserManager
+__metaclass__ = type
__all__ = [
- 'initialize',
- 'flush',
+ 'StockDatabase',
+ 'flush', # for test convenience
]
+flush = None
+
-def initialize():
- 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):
- model.initialize()
- config.list_manager = ListManager()
- config.user_manager = UserManager()
- flush()
+class StockDatabase:
+ implements(IDatabase)
+
+ def __init__(self):
+ # Expose the flush() method for test case convenience using the stock
+ # database.
+ global flush
+ flush = self.flush
+ self.list_manager = None
+ self.user_manager = 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):
+ model.initialize()
+ self.list_manager = ListManager()
+ self.user_manager = UserManager()
+ self.flush()
-def flush():
- objectstore.flush()
+ def flush(self):
+ objectstore.flush()
diff --git a/Mailman/initialize.py b/Mailman/initialize.py
index 9dee94cbe..03c861066 100644
--- a/Mailman/initialize.py
+++ b/Mailman/initialize.py
@@ -26,12 +26,16 @@ by the command line arguments.
import os
import sys
+import pkg_resources
+
+from zope.interface.verify import verifyObject
import Mailman.configuration
-import Mailman.database
import Mailman.ext
import Mailman.loginit
+from Mailman.interfaces import IDatabase, IListManager, IUserManager
+
DOT = '.'
@@ -55,17 +59,44 @@ def initialize_1(config, propagate_logs):
Mailman.loginit.initialize(propagate_logs)
# Set up site extensions directory
Mailman.ext.__path__.append(Mailman.configuration.config.EXT_DIR)
- # Initialize the IListManager, IMemberManager, and IMessageManager
- modparts = Mailman.configuration.config.MANAGERS_INIT_FUNCTION.split(DOT)
- funcname = modparts.pop()
- modname = DOT.join(modparts)
- __import__(modname)
- initfunc = getattr(sys.modules[modname], funcname)
- initfunc()
def initialize_2():
- Mailman.database.initialize()
+ # Find all declared entry points in the mailman.database group. There
+ # must be exactly one or two such entry points defined. If there are two,
+ # then we remove the one called 'stock' since that's the one that we
+ # distribute and it's obviously being overridden. If we're still left
+ # with more than one after we filter out the stock one, it is an error.
+ entrypoints = list(pkg_resources.iter_entry_points('mailman.database'))
+ if len(entrypoints) == 0:
+ raise RuntimeError('No database entry points found')
+ elif len(entrypoints) == 1:
+ # Okay, this is the one to use.
+ entrypoint = entrypoints[0]
+ elif len(database) == 2:
+ # Find the one /not/ named 'stock'.
+ entrypoints = [ep for ep in entrypoints if ep.name <> 'stock']
+ if len(entrypoints) == 0:
+ raise RuntimeError('No database entry points found')
+ elif len(entrypoints) == 2:
+ raise RuntimeError('Too many database entry points defined')
+ else:
+ assert len(entrypoints) == 1, 'Insanity'
+ entrypoint = entrypoint[0]
+ else:
+ raise RuntimeError('Too many database entry points defined')
+ # Instantiate the database entry point, ensure that it's of the right
+ # type, and initialize it. Then stash the object on our configuration
+ # object.
+ ep_object = entrypoint.load()
+ db = ep_object()
+ verifyObject(IDatabase, db)
+ db.initialize()
+ Mailman.configuration.config.db = db
+ verifyObject(IListManager, db.list_manager)
+ Mailman.configuration.config.list_manager = db.list_manager
+ verifyObject(IUserManager, db.user_manager)
+ Mailman.configuration.config.user_manager = db.user_manager
def initialize(config=None, propagate_logs=False):
diff --git a/Mailman/interfaces/database.py b/Mailman/interfaces/database.py
new file mode 100644
index 000000000..8c57ae6b3
--- /dev/null
+++ b/Mailman/interfaces/database.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interfaces for database interaction.
+
+By providing an object with this interface and declaring it in a package
+setup.py file as an entry point in the 'mailman.database' group with the name
+'initializer', you can distribute entirely different database layers for
+Mailman's back end.
+"""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IDatabase(Interface):
+ """Database layer interface."""
+
+ def initialize():
+ """Initialize the database layer, using whatever means necessary."""
+
+ def flush():
+ """Flush current database changes."""
+
+ # XXX Eventually we probably need to support a transaction manager
+ # interface, e.g. begin(), commit(), abort(). We will probably also need
+ # to support a shutdown() method for cleanly disconnecting from the
+ # database.sy
+
+ list_manager = Attribute(
+ """The IListManager instance provided by the database layer.""")
+
+ user_manager = Attribute(
+ """The IUserManager instance provided by the database layer.""")
diff --git a/setup.py b/setup.py
index 45167dadc..5db399924 100644
--- a/setup.py
+++ b/setup.py
@@ -82,9 +82,9 @@ Any other spelling is incorrect.""",
include_package_data = True,
entry_points = {
'console_scripts': list(scripts),
- 'setuptools.file_finders': [
- 'bzr = setuptoolsbzr:find_files_for_bzr',
- ],
+ 'setuptools.file_finders': 'bzr = setuptoolsbzr:find_files_for_bzr',
+ # Entry point for plugging in different database backends.
+ 'mailman.database': 'stock = Mailman.database:StockDatabase',
},
# Third-party requirements.
install_requires = [