diff options
| -rw-r--r-- | src/mailman/__init__.py | 31 | ||||
| -rw-r--r-- | src/mailman/config/config.py | 1 | ||||
| -rw-r--r-- | src/mailman/config/schema.cfg | 8 | ||||
| -rw-r--r-- | src/mailman/core/initialize.py | 22 | ||||
| -rw-r--r-- | src/mailman/docs/hooks.txt | 111 | ||||
| -rw-r--r-- | src/mailman/options.py | 6 | ||||
| -rw-r--r-- | src/mailman/rest/webservice.py | 7 |
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 |
