summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2008-03-22 21:43:38 -0400
committerBarry Warsaw2008-03-22 21:43:38 -0400
commit78aeaf14e41c473655267d8a0fad175c783012e7 (patch)
tree6a65a11c73c163299860d07409212e8215fe9165
parent6d9084326a4470da44c15193ddf0c4573fccb7f9 (diff)
downloadmailman-78aeaf14e41c473655267d8a0fad175c783012e7.tar.gz
mailman-78aeaf14e41c473655267d8a0fad175c783012e7.tar.zst
mailman-78aeaf14e41c473655267d8a0fad175c783012e7.zip
-rw-r--r--mailman/bin/__init__.py2
-rw-r--r--mailman/bin/create_list.py (renamed from mailman/bin/newlist.py)99
-rw-r--r--mailman/bin/list_lists.py72
-rw-r--r--mailman/bin/master.py9
-rw-r--r--mailman/bin/qrunner.py17
-rw-r--r--mailman/options.py59
6 files changed, 150 insertions, 108 deletions
diff --git a/mailman/bin/__init__.py b/mailman/bin/__init__.py
index f40c09d74..7c6b0b482 100644
--- a/mailman/bin/__init__.py
+++ b/mailman/bin/__init__.py
@@ -26,6 +26,7 @@ __all__ = [
'cleanarch',
'config_list',
'confirm',
+ 'create_list',
'disabled',
'dumpdb',
'export',
@@ -43,7 +44,6 @@ __all__ = [
'make_instance',
'master',
'mmsitepass',
- 'newlist',
'nightly_gzip',
'owner',
'post',
diff --git a/mailman/bin/newlist.py b/mailman/bin/create_list.py
index 447b66f4a..8cec2755c 100644
--- a/mailman/bin/newlist.py
+++ b/mailman/bin/create_list.py
@@ -17,30 +17,24 @@
from __future__ import with_statement
-import sha
import sys
-import getpass
-import datetime
-import optparse
from mailman import Errors
from mailman import Message
from mailman import Utils
-from mailman import Version
from mailman import i18n
from mailman.app.lifecycle import create_list
from mailman.configuration import config
-from mailman.initialize import initialize
from mailman.interfaces import ListAlreadyExistsError
+from mailman.options import SingleMailingListOptions
_ = i18n._
-def parseargs():
- parser = optparse.OptionParser(version=Version.MAILMAN_VERSION,
- usage=_("""\
+class ScriptOptions(SingleMailingListOptions):
+ usage=_("""\
%prog [options] fqdn_listname
Create a new mailing list.
@@ -49,79 +43,78 @@ fqdn_listname is the 'fully qualified list name', basically the posting
address of the list. It must be a valid email address and the domain must be
registered with Mailman.
-Note that listnames are forced to lowercase."""))
- parser.add_option('-l', '--language',
- type='string', action='store',
- help=_("""\
+Note that listnames are forced to lowercase.""")
+
+ def add_options(self):
+ super(ScriptOptions, self).add_options()
+ self.parser.add_option(
+ '--language',
+ type='unicode', action='store',
+ help=_("""\
Make the list's preferred language LANGUAGE, which must be a two letter
language code."""))
- parser.add_option('-o', '--owner',
- type='string', action='append', default=[],
- dest='owners', help=_("""\
+ self.parser.add_option(
+ '-o', '--owner',
+ type='unicode', action='append', default=[],
+ dest='owners', help=_("""\
Specific a listowner email address. If the address is not currently
registered with Mailman, the address is registered and linked to a user.
Mailman will send a confirmation message to the address, but it will also send
a list creation notice to the address. More than one owner can be
specified."""))
- parser.add_option('-q', '--quiet',
- default=False, action='store_true',
- help=_("""\
+ self.parser.add_option(
+ '-q', '--quiet',
+ default=False, action='store_true',
+ help=_("""\
Normally the administrator is notified by email (after a prompt) that their
list has been created. This option suppresses the prompt and
notification."""))
- parser.add_option('-a', '--automate',
- default=False, action='store_true',
- help=_("""\
+ self.parser.add_option(
+ '-a', '--automate',
+ default=False, action='store_true',
+ help=_("""\
This option suppresses the prompt prior to administrator notification but
still sends the notification. It can be used to make newlist totally
non-interactive but still send the notification, assuming at least one list
owner is specified with the -o option.."""))
- parser.add_option('-C', '--config',
- help=_('Alternative configuration file to use'))
- opts, args = parser.parse_args()
- # We can't verify opts.language here because the configuration isn't
- # loaded yet.
- return parser, opts, args
+
+ def sanity_check(self):
+ """Set up some defaults we couldn't set up earlier."""
+ if self.options.language is None:
+ self.options.language = config.DEFAULT_SERVER_LANGUAGE
+ # Is the language known?
+ if self.options.language not in config.languages.enabled_codes:
+ self.parser.error(_('Unknown language: $opts.language'))
+ # Handle variable number of positional arguments
+ if len(self.arguments) > 0:
+ parser.error(_('Unexpected arguments'))
def main():
- parser, opts, args = parseargs()
- initialize(opts.config)
-
- # Set up some defaults we couldn't set up in parseargs()
- if opts.language is None:
- opts.language = config.DEFAULT_SERVER_LANGUAGE
- # Is the language known?
- if opts.language not in config.languages.enabled_codes:
- parser.error(_('Unknown language: $opts.language'))
- # Handle variable number of positional arguments
- if len(args) == 0:
- parser.error(_('You must supply a mailing list name'))
- elif len(args) == 1:
- fqdn_listname = args[0].lower()
- elif len(args) > 1:
- parser.error(_('Unexpected arguments'))
+ options = ScriptOptions()
+ options.initialize()
# Create the mailing list, applying styles as appropriate.
+ fqdn_listname = options.options.listname
try:
- mlist = create_list(fqdn_listname, opts.owners)
- mlist.preferred_language = opts.language
+ mlist = create_list(fqdn_listname, options.options.owners)
+ mlist.preferred_language = options.options.language
except Errors.InvalidEmailAddress:
- parser.error(_('Illegal list name: $fqdn_listname'))
+ options.parser.error(_('Illegal list name: $fqdn_listname'))
except ListAlreadyExistsError:
- parser.error(_('List already exists: $fqdn_listname'))
+ options.parser.error(_('List already exists: $fqdn_listname'))
except Errors.BadDomainSpecificationError, domain:
- parser.error(_('Undefined domain: $domain'))
+ options.parser.error(_('Undefined domain: $domain'))
- config.db.flush()
+ config.db.commit()
# Send notices to the list owners. XXX This should also be moved to the
# Mailman.app.create module.
- if not opts.quiet and not opts.automate:
+ if not options.options.quiet and not options.options.automate:
print _('Hit enter to notify $fqdn_listname owners...'),
sys.stdin.readline()
- if not opts.quiet:
+ if not options.options.quiet:
d = dict(
listname = mlist.fqdn_listname,
admin_url = mlist.script_url('admin'),
@@ -136,6 +129,6 @@ def main():
with i18n.using_language(mlist.preferred_language):
msg = Message.UserNotification(
owner_mail, mlist.no_reply_address,
- _('Your new mailing list: $listname'),
+ _('Your new mailing list: $fqdn_listname'),
text, mlist.preferred_language)
msg.send(mlist)
diff --git a/mailman/bin/list_lists.py b/mailman/bin/list_lists.py
index 2bd85a947..7742f1dbb 100644
--- a/mailman/bin/list_lists.py
+++ b/mailman/bin/list_lists.py
@@ -15,53 +15,55 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-import optparse
-
from mailman import Defaults
from mailman import Version
from mailman.configuration import config
from mailman.i18n import _
from mailman.initialize import initialize
+from mailman.options import Options
-def parseargs():
- parser = optparse.OptionParser(version=Version.MAILMAN_VERSION,
- usage=_("""\
+class ScriptOptions(Options):
+ usage=_("""\
%prog [options]
-List all mailing lists."""))
- parser.add_option('-a', '--advertised',
- default=False, action='store_true',
- help=_("""\
+List all mailing lists.""")
+
+ def add_options(self):
+ super(ScriptOptions, self).add_options()
+ self.parser.add_option(
+ '-a', '--advertised',
+ default=False, action='store_true',
+ help=_("""\
List only those mailing lists that are publicly advertised"""))
- parser.add_option('-b', '--bare',
- default=False, action='store_true',
- help=_("""\
+ self.parser.add_option(
+ '-b', '--bare',
+ default=False, action='store_true',
+ help=_("""\
Displays only the list name, with no description."""))
- parser.add_option('-d', '--domain',
- default=[], type='string', action='append',
- dest='domains', help=_("""\
+ self.parser.add_option(
+ '-d', '--domain',
+ default=[], type='string', action='append',
+ dest='domains', help=_("""\
List only those mailing lists that match the given virtual domain, which may
be either the email host or the url host name. Multiple -d options may be
given."""))
- parser.add_option('-f', '--full',
- default=False, action='store_true',
- help=_("""\
+ self.parser.add_option(
+ '-f', '--full',
+ default=False, action='store_true',
+ help=_("""\
Print the full list name, including the posting address."""))
- parser.add_option('-C', '--config',
- help=_('Alternative configuration file to use'))
- opts, args = parser.parse_args()
- if args:
- parser.print_help()
- parser.error(_('Unexpected arguments'))
- return parser, opts, args
+
+ def sanity_check(self):
+ if len(self.arguments) > 0:
+ self.parser.error(_('Unexpected arguments'))
def main():
- parser, opts, args = parseargs()
- initialize(opts.config)
+ options = ScriptOptions()
+ options.initialize()
mlists = []
longest = 0
@@ -69,36 +71,36 @@ def main():
listmgr = config.db.list_manager
for fqdn_name in sorted(listmgr.names):
mlist = listmgr.get(fqdn_name)
- if opts.advertised and not mlist.advertised:
+ if options.options.advertised and not mlist.advertised:
continue
- if opts.domains:
- for domain in opts.domains:
+ if options.options.domains:
+ for domain in options.options.domains:
if domain in mlist.web_page_url or domain == mlist.host_name:
mlists.append(mlist)
break
else:
mlists.append(mlist)
- if opts.full:
+ if options.options.full:
name = mlist.fqdn_listname
else:
name = mlist.real_name
longest = max(len(name), longest)
- if not mlists and not opts.bare:
+ if not mlists and not options.options.bare:
print _('No matching mailing lists found')
return
- if not opts.bare:
+ if not options.options.bare:
num_mlists = len(mlists)
print _('$num_mlists matching mailing lists found:')
format = '%%%ds - %%.%ds' % (longest, 77 - longest)
for mlist in mlists:
- if opts.full:
+ if options.options.full:
name = mlist.fqdn_listname
else:
name = mlist.real_name
- if opts.bare:
+ if options.options.bare:
print name
else:
description = mlist.description or _('[no description available]')
diff --git a/mailman/bin/master.py b/mailman/bin/master.py
index 6577a0079..7369dd2ca 100644
--- a/mailman/bin/master.py
+++ b/mailman/bin/master.py
@@ -38,11 +38,9 @@ from locknix import lockfile
from munepy import Enum
from mailman import Defaults
-from mailman import Version
from mailman import loginit
from mailman.configuration import config
from mailman.i18n import _
-from mailman.initialize import initialize
from mailman.options import Options
@@ -51,7 +49,7 @@ LOCK_LIFETIME = Defaults.days(1) + Defaults.hours(6)
-class MasterOptions(Options):
+class ScriptOptions(Options):
"""Options for the master watcher."""
usage = _("""\
@@ -405,8 +403,9 @@ qrunner %s reached maximum restart limit of %d, not restarting.""",
def main():
"""Main process."""
- options = MasterOptions()
- initialize(options.options.config)
+
+ options = ScriptOptions()
+ options.initialize()
# Acquire the master lock, exiting if we can't acquire it. We'll let the
# caller handle any clean up or lock breaking. No with statement here
diff --git a/mailman/bin/qrunner.py b/mailman/bin/qrunner.py
index 0b9c823a1..e78dfab4e 100644
--- a/mailman/bin/qrunner.py
+++ b/mailman/bin/qrunner.py
@@ -19,11 +19,9 @@ import sys
import signal
import logging
-from mailman import Version
from mailman import loginit
from mailman.configuration import config
from mailman.i18n import _
-from mailman.initialize import initialize
from mailman.options import Options
@@ -55,7 +53,7 @@ def r_callback(option, opt, value, parser):
-class RunnerOptions(Options):
+class ScriptOptions(Options):
usage=_("""\
Run one or more qrunners, once or repeatedly.
@@ -114,6 +112,10 @@ This should only be used when running qrunner as a subprocess of the
mailmanctl startup script. It changes some of the exit-on-error behavior to
work better with that framework."""))
+ def initialize(self):
+ """Override initialization to propagate logs correctly."""
+ super(ScriptOptions, self).initialize(not self.options.subproc)
+
def sanity_check(self):
if self.arguments:
self.parser.error(_('Unexpected arguments'))
@@ -198,13 +200,8 @@ def set_signals(loop):
def main():
global log
- options = RunnerOptions()
- # If we're not running as a subprocess of mailmanctl, then we'll log to
- # stderr in addition to logging to the log files. We do this by passing a
- # value of True to propagate, which allows the 'mailman' root logger to
- # see the log messages.
- initialize(options.options.config,
- propagate_logs=not options.options.subproc)
+ options = ScriptOptions()
+ options.initialize()
if options.options.list:
prefixlen = max(len(shortname)
diff --git a/mailman/options.py b/mailman/options.py
index 78cf617c4..ee310f3b9 100644
--- a/mailman/options.py
+++ b/mailman/options.py
@@ -18,14 +18,39 @@
"""Common argument parsing."""
__metaclass__ = type
-__all__ = ['Options']
+__all__ = [
+ 'Options',
+ 'SingleMailingListOptions',
+ ]
-from optparse import OptionParser
+import sys
+
+from copy import copy
+from optparse import Option, OptionParser, OptionValueError
from mailman.Version import MAILMAN_VERSION
from mailman.configuration import config
from mailman.i18n import _
+from mailman.initialize import initialize
+
+
+
+def check_unicode(option, opt, value):
+ if isinstance(value, unicode):
+ return value
+ try:
+ return value.decode(sys.getdefaultencoding())
+ except UnicodeDecodeError:
+ raise OptionValueError(
+ "option %s: Cannot decode: %r" % (opt, value))
+
+
+class MailmanOption(Option):
+ """Extension types for unicode options."""
+ TYPES = Option.TYPES + ('unicode',)
+ TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+ TYPE_CHECKER['unicode'] = check_unicode
@@ -36,7 +61,9 @@ class Options:
usage = None
def __init__(self):
- self.parser = OptionParser(version=MAILMAN_VERSION, usage=self.usage)
+ self.parser = OptionParser(version=MAILMAN_VERSION,
+ option_class=MailmanOption,
+ usage=self.usage)
self.add_common_options()
self.add_options()
options, arguments = self.parser.parse_args()
@@ -45,7 +72,6 @@ class Options:
# Also, for convenience, place the options in the configuration file
# because occasional global uses are necessary.
config.options = self
- self.sanity_check()
def add_options(self):
"""Allow the subclass to add its own specific arguments."""
@@ -60,3 +86,28 @@ class Options:
self.parser.add_option(
'-C', '--config',
help=_('Alternative configuration file to use'))
+
+ def initialize(self, propagate_logs=False):
+ """Initialize the configuration system.
+
+ After initialization of the configuration system, perform sanity
+ checks. We do it in this order because some sanity checks require the
+ configuration to be initialized.
+
+ :param propagate_logs: Flag specifying whether log messages in
+ sub-loggers should be propagated to the master logger (and hence
+ to the root logger).
+ """
+ initialize(self.options.config, propagate_logs=propagate_logs)
+ self.sanity_check()
+
+
+
+class SingleMailingListOptions(Options):
+ """A helper for specifying the mailing list on the command line."""
+
+ def add_options(self):
+ self.parser.add_option(
+ '-l', '--listname',
+ type='unicode', help=_('The mailing list name'))
+ super(SingleMailingListOptions, self).add_options()