summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/__init__.py31
-rw-r--r--src/mailman/config/config.py1
-rw-r--r--src/mailman/config/schema.cfg8
-rw-r--r--src/mailman/core/initialize.py22
-rw-r--r--src/mailman/docs/hooks.txt111
-rw-r--r--src/mailman/options.py6
-rw-r--r--src/mailman/rest/webservice.py7
7 files changed, 169 insertions, 17 deletions
diff --git a/src/mailman/__init__.py b/src/mailman/__init__.py
index e69de29bb..8c5301b0d 100644
--- a/src/mailman/__init__.py
+++ b/src/mailman/__init__.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman 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 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman 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
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""The `mailman` package."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ ]
+
+
+# lazr.restful uses the sha module, but that's deprecated in Python 2.6 in
+# favor of the hashlib module.
+import warnings
+warnings.filterwarnings(
+ 'ignore', category=DeprecationWarning, module='lazr.restful._resource')
diff --git a/src/mailman/config/config.py b/src/mailman/config/config.py
index d7199f505..0e3f0dad7 100644
--- a/src/mailman/config/config.py
+++ b/src/mailman/config/config.py
@@ -40,7 +40,6 @@ from mailman.languages.manager import LanguageManager
from mailman.styles.manager import StyleManager
from mailman.utilities.filesystem import makedirs
-
SPACE = ' '
diff --git a/src/mailman/config/schema.cfg b/src/mailman/config/schema.cfg
index 73a2ff34e..e32a3896a 100644
--- a/src/mailman/config/schema.cfg
+++ b/src/mailman/config/schema.cfg
@@ -54,6 +54,14 @@ email_commands_max_lines: 10
# the pending database.
pending_request_life: 3d
+# A callable to run with no arguments early in the initialization process.
+# This runs before database initialization.
+pre_hook:
+
+# A callable to run with no arguments late in the initialization process.
+# This runs after adapters are initialized.
+post_hook:
+
[passwords]
# When Mailman generates them, this is the default length of member passwords.
diff --git a/src/mailman/core/initialize.py b/src/mailman/core/initialize.py
index a92f1fd19..18cb823ee 100644
--- a/src/mailman/core/initialize.py
+++ b/src/mailman/core/initialize.py
@@ -89,15 +89,21 @@ def initialize_2(debug=False):
:param debug: Should the database layer be put in debug mode?
:type debug: boolean
"""
+ # Run the pre-hook if there is one.
+ config = mailman.config.config
+ if config.mailman.pre_hook:
+ package, dot, function = config.mailman.pre_hook.rpartition('.')
+ __import__(package)
+ getattr(sys.modules[package], function)()
# Instantiate the database class, ensure that it's of the right type, and
# initialize it. Then stash the object on our configuration object.
- database_class = mailman.config.config.database['class']
- module_name, class_name = database_class.rsplit('.', 1)
- __import__(module_name)
- database = getattr(sys.modules[module_name], class_name)()
+ database_class = config.database['class']
+ package, dot, class_name = database_class.rpartition('.')
+ __import__(package)
+ database = getattr(sys.modules[package], class_name)()
verifyObject(IDatabase, database)
database.initialize(debug)
- mailman.config.config.db = database
+ config.db = database
# Initialize the rules and chains. Do the imports here so as to avoid
# circular imports.
from mailman.app.commands import initialize as initialize_commands
@@ -123,6 +129,12 @@ def initialize_3():
from mailman.database.mailinglist import (
adapt_mailing_list_to_acceptable_alias_set)
adapter_hooks.append(adapt_mailing_list_to_acceptable_alias_set)
+ # Run the post-hook if there is one.
+ config = mailman.config.config
+ if config.mailman.post_hook:
+ package, dot, function = config.mailman.post_hook.rpartition('.')
+ __import__(package)
+ getattr(sys.modules[package], function)()
diff --git a/src/mailman/docs/hooks.txt b/src/mailman/docs/hooks.txt
new file mode 100644
index 000000000..ddc4fe5fa
--- /dev/null
+++ b/src/mailman/docs/hooks.txt
@@ -0,0 +1,111 @@
+=====
+Hooks
+=====
+
+Mailman defines two initialization hooks, one which is run early in the
+initialization process and the other run late in the initialization process.
+Hooks name an importable callable so it must be accessible on sys.path.
+
+ >>> import os, sys
+ >>> from mailman.config import config
+ >>> config_directory = os.path.dirname(config.filename)
+ >>> sys.path.insert(0, config_directory)
+
+ >>> hook_path = os.path.join(config_directory, 'hooks.py')
+ >>> with open(hook_path, 'w') as fp:
+ ... print >> fp, """\
+ ... counter = 1
+ ... def pre_hook():
+ ... global counter
+ ... print 'pre-hook:', counter
+ ... counter += 1
+ ...
+ ... def post_hook():
+ ... global counter
+ ... print 'post-hook:', counter
+ ... counter += 1
+ ... """
+ >>> fp.close()
+
+
+Pre-hook
+========
+
+We can set the pre-hook in the configuration file.
+
+ >>> config_path = os.path.join(config_directory, 'hooks.cfg')
+ >>> with open(config_path, 'w') as fp:
+ ... print >> fp, """\
+ ... [meta]
+ ... extends: test.cfg
+ ...
+ ... [mailman]
+ ... pre_hook: hooks.pre_hook
+ ... """
+
+The hooks are run in the second and third steps of initialization. However,
+we can't run those initialization steps in process, so call `bin/version` to
+force the hooks to run.
+
+ >>> import subprocess
+ >>> def call():
+ ... proc = subprocess.Popen(
+ ... 'bin/version',
+ ... cwd='../..', # testrunner runs from ./parts/test
+ ... env=dict(MAILMAN_CONFIG_FILE=config_path,
+ ... PYTHONPATH=config_directory),
+ ... stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ ... stdout, stderr = proc.communicate()
+ ... assert proc.returncode == 0, stderr
+ ... print stdout
+
+ >>> call()
+ pre-hook: 1
+ Using GNU Mailman 3...
+ <BLANKLINE>
+
+ >>> os.remove(config_path)
+
+
+Post-hook
+=========
+
+We can set the post-hook in the configuration file.
+
+ >>> with open(config_path, 'w') as fp:
+ ... print >> fp, """\
+ ... [meta]
+ ... extends: test.cfg
+ ...
+ ... [mailman]
+ ... post_hook: hooks.post_hook
+ ... """
+
+ >>> call()
+ post-hook: 1
+ Using GNU Mailman 3...
+ <BLANKLINE>
+
+ >>> os.remove(config_path)
+
+
+Running both hooks
+==================
+
+We can set the pre- and post-hooks in the configuration file.
+
+ >>> with open(config_path, 'w') as fp:
+ ... print >> fp, """\
+ ... [meta]
+ ... extends: test.cfg
+ ...
+ ... [mailman]
+ ... pre_hook: hooks.pre_hook
+ ... post_hook: hooks.post_hook
+ ... """
+
+ >>> call()
+ pre-hook: 1
+ post-hook: 2
+ Using GNU Mailman 3...
+ <BLANKLINE>
diff --git a/src/mailman/options.py b/src/mailman/options.py
index d18c78cea..85508501a 100644
--- a/src/mailman/options.py
+++ b/src/mailman/options.py
@@ -137,10 +137,8 @@ class Options:
from the configuration files.
:type propagate_logs: bool or None.
"""
- # Fall back to using the environment variable if -C is not given.
- config_file = (os.getenv('MAILMAN_CONFIG_FILE')
- if self.options.config is None
- else self.options.config)
+ # The environment variable overrides the -C option.
+ config_file = os.getenv('MAILMAN_CONFIG_FILE', self.options.config)
initialize(config_file, propagate_logs=propagate_logs)
self.sanity_check()
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index c6f0da2ef..bf1012203 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -28,13 +28,6 @@ __all__ = [
import logging
-import warnings
-
-# lazr.restful uses the sha module, but that's deprecated in Python 2.6 in
-# favor of the hashlib module.
-warnings.filterwarnings(
- 'ignore', category=DeprecationWarning, module='lazr.restful._resource')
-
# Don't use wsgiref.simple_server.make_server() because we need to override
# BaseHTTPRequestHandler.log_message() so that logging output will go to the