------------------------------------------------------------ revno: 6794 committer: Barry Warsaw <[email protected]> branch nick: 3.0 timestamp: Sat 2009-09-19 16:51:15 -0400 message: Convert bin/inject to bin/mailman inject Expose the database store on .store instead of ._store A few other cleanups. removed: src/mailman/bin/inject.py added: src/mailman/commands/cli_inject.py src/mailman/commands/docs/inject.txt modified: src/mailman/commands/docs/echo.txt src/mailman/commands/docs/end.txt src/mailman/commands/docs/join.txt src/mailman/commands/docs/lists.txt src/mailman/commands/docs/members.txt src/mailman/commands/docs/remove.txt src/mailman/database/__init__.py src/mailman/database/listmanager.py src/mailman/database/mailinglist.py src/mailman/docs/listmanager.txt src/mailman/queue/docs/incoming.txt
-- lp:mailman https://code.launchpad.net/~mailman-coders/mailman/3.0 Your team Mailman Checkins is subscribed to branch lp:mailman. To unsubscribe from this branch go to https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
=== removed file 'src/mailman/bin/inject.py' --- src/mailman/bin/inject.py 2009-08-26 06:27:37 +0000 +++ src/mailman/bin/inject.py 1970-01-01 00:00:00 +0000 @@ -1,91 +0,0 @@ -# Copyright (C) 2002-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/>. - -import os -import sys - -from email import message_from_string -from zope.component import getUtility - -from mailman import Utils -from mailman.configuration import config -from mailman.i18n import _ -from mailman.inject import inject_text -from mailman.interfaces.listmanager import IListManager -from mailman.message import Message -from mailman.options import SingleMailingListOptions - - - -class ScriptOptions(SingleMailingListOptions): - usage=_("""\ -%prog [options] [filename] - -Inject a message from a file into Mailman's incoming queue. 'filename' is the -name of the plaintext message file to inject. If omitted, or the string '-', -standard input is used. -""") - - def add_options(self): - super(ScriptOptions, self).add_options() - self.parser.add_option( - '-q', '--queue', - type='string', help=_("""\ -The name of the queue to inject the message to. The queuename must be one of -the directories inside the qfiles directory. If omitted, the incoming queue -is used.""")) - - def sanity_check(self): - if not self.options.listname: - self.parser.error(_('Missing listname')) - if len(self.arguments) == 0: - self.filename = '-' - elif len(self.arguments) > 1: - self.parser.print_error(_('Unexpected arguments')) - else: - self.filename = self.arguments[0] - - - -def main(): - options = ScriptOptions() - options.initialize() - - if options.options.queue is None: - qdir = config.INQUEUE_DIR - else: - qdir = os.path.join(config.QUEUE_DIR, options.options.queue) - if not os.path.isdir(qdir): - options.parser.error(_('Bad queue directory: $qdir')) - - fqdn_listname = options.options.listname - mlist = getUtility(IListManager).get(fqdn_listname) - if mlist is None: - options.parser.error(_('No such list: $fqdn_listname')) - - if options.filename == '-': - message_text = sys.stdin.read() - else: - with open(options.filename) as fp: - message_text = fp.read() - - inject_text(mlist, message_text, qdir=qdir) - - - -if __name__ == '__main__': - main() === added file 'src/mailman/commands/cli_inject.py' --- src/mailman/commands/cli_inject.py 1970-01-01 00:00:00 +0000 +++ src/mailman/commands/cli_inject.py 2009-09-19 20:51:15 +0000 @@ -0,0 +1,104 @@ +# 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/>. + +"""Module stuff.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'Inject', + ] + + +import sys + +from zope.component import getUtility +from zope.interface import implements + +from mailman.config import config +from mailman.i18n import _ +from mailman.inject import inject_text +from mailman.interfaces.command import ICLISubCommand +from mailman.interfaces.listmanager import IListManager + + + +class Inject: + """Inject a message from a file into a mailing list's queue.""" + + implements(ICLISubCommand) + + name = 'inject' + + def add(self, parser, command_parser): + """See `ICLISubCommand`.""" + self.parser = parser + command_parser.add_argument( + '-q', '--queue', + type=unicode, help=_("""\ + The name of the queue to inject the message to. QUEUE must be one + of the directories inside the qfiles directory. If omitted, the + incoming queue is used.""")) + command_parser.add_argument( + '-s', '--show', + action='store_true', default=False, + help=_('Show a list of all available queue names and exit.')) + command_parser.add_argument( + '-f', '--filename', + type='string', help=_(""" + Name of file containing the message to inject. If not given, or + '-' (without the quotes) standard input is used. + """)) + # Required positional argument. + command_parser.add_argument( + 'listname', metavar='LISTNAME', nargs='?', + help=_("""\ + The 'fully qualified list name', i.e. the posting address of the + mailing list to inject the message into.""")) + + def process(self, args): + """See `ICLISubCommand`.""" + # Process --show first; if given, print output and exit, ignoring all + # other command line switches. + if args.show: + print 'Available queues:' + for switchboard in sorted(config.switchboards): + print ' ', switchboard + return + # Could be None or sequence of length 0. + if args.listname is None: + self.parser.error(_('List name is required')) + return + assert len(args.listname) == 1, ( + 'Unexpected positional arguments: %s' % args.listname) + fqdn_listname = args.listname[0] + mlist = getUtility(IListManager).get(fqdn_listname) + if mlist is None: + self.parser.error(_('No such list: $fqdn_listname')) + return + queue = ('in' if args.queue is None else args.queue) + switchboard = config.switchboards.get(queue) + if switchboard is None: + self.parser.error(_('No such queue: $queue')) + return + if args.filename in (None, '-'): + message_text = sys.stdin.read() + else: + with open(args.filename) as fp: + message_text = fp.read() + inject_text(mlist, message_text, switchboard=queue) === modified file 'src/mailman/commands/docs/echo.txt' --- src/mailman/commands/docs/echo.txt 2009-07-17 05:16:27 +0000 +++ src/mailman/commands/docs/echo.txt 2009-09-19 20:51:15 +0000 @@ -14,7 +14,6 @@ The original message is ignored, but the results receive the echoed command. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('[email protected]') >>> from mailman.queue.command import Results === modified file 'src/mailman/commands/docs/end.txt' --- src/mailman/commands/docs/end.txt 2009-07-17 05:16:27 +0000 +++ src/mailman/commands/docs/end.txt 2009-09-19 20:51:15 +0000 @@ -18,7 +18,6 @@ The command itself is fairly simple; it just stops command processing, and the message isn't even looked at. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('[email protected]') >>> from mailman.email.message import Message >>> print command.process(mlist, Message(), {}, (), None) === added file 'src/mailman/commands/docs/inject.txt' --- src/mailman/commands/docs/inject.txt 1970-01-01 00:00:00 +0000 +++ src/mailman/commands/docs/inject.txt 2009-09-19 20:51:15 +0000 @@ -0,0 +1,193 @@ +============================== +Command line message injection +============================== + +You can inject a message directly into a queue directory via the command +line. + + >>> from mailman.commands.cli_inject import Inject + >>> command = Inject() + + >>> class FakeArgs: + ... queue = None + ... show = False + ... filename = None + ... listname = None + >>> args = FakeArgs() + + >>> class FakeParser: + ... def error(self, message): + ... print message + >>> command.parser = FakeParser() + +It's easy to find out which queues are available. + + >>> args.show = True + >>> command.process(args) + Available queues: + archive + bad + bounces + command + digest + in + lmtp + maildir + news + out + pipeline + rest + retry + shunt + virgin + + >>> args.show = False + +Usually, the text of the message to inject is in a file. + + >>> import os, tempfile + >>> fd, filename = tempfile.mkstemp() + >>> with os.fdopen(fd, 'w') as fp: + ... print >> fp, """\ + ... From: [email protected] + ... To: [email protected] + ... Subject: testing + ... + ... This is a test message. + ... """ + +However, the mailing list name is always required. + + >>> args.filename = filename + >>> command.process(args) + List name is required + +Let's provide a list name and try again. + + >>> mlist = create_list('[email protected]') + >>> transaction.commit() + + >>> in_queue = config.switchboards['in'] + >>> len(in_queue.files) + 0 + >>> args.listname = ['[email protected]'] + >>> command.process(args) + +By default, the incoming queue is used. + + >>> len(in_queue.files) + 1 + + >>> from mailman.testing.helpers import get_queue_messages + >>> item = get_queue_messages('in')[0] + >>> print item.msg.as_string() + From: [email protected] + To: [email protected] + Subject: testing + Message-ID: ... + Date: ... + <BLANKLINE> + This is a test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : [email protected] + original_size: 90 + version : 3 + +But a different queue can be specified on the command line. + + >>> args.queue = 'virgin' + >>> command.process(args) + + >>> len(in_queue.files) + 0 + >>> virgin_queue = config.switchboards['virgin'] + >>> len(virgin_queue.files) + 1 + >>> item = get_queue_messages('virgin')[0] + >>> print item.msg.as_string() + From: [email protected] + To: [email protected] + Subject: testing + Message-ID: ... + Date: ... + <BLANKLINE> + This is a test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : [email protected] + original_size: 90 + version : 3 + + # Clean up the tempfile. + >>> os.remove(filename) + + +Standard input +============== + +The message text can also be provided on standard input. + + >>> from StringIO import StringIO + + # Remember: we've got unicode literals turned on. + >>> standard_in = StringIO(str("""\ + ... From: [email protected] + ... To: [email protected] + ... Subject: another test + ... + ... This is another test message. + ... """)) + + >>> import sys + >>> sys.stdin = standard_in + >>> args.filename = '-' + >>> args.queue = None + + >>> command.process(args) + >>> len(in_queue.files) + 1 + >>> item = get_queue_messages('in')[0] + >>> print item.msg.as_string() + From: [email protected] + To: [email protected] + Subject: another test + Message-ID: ... + Date: ... + <BLANKLINE> + This is another test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : [email protected] + original_size: 100 + version : 3 + + # Clean up. + >>> sys.stdin = sys.__stdin__ + >>> args.filename = filename + + +Errors +====== + +It is an error to specify a queue that doesn't exist. + + >>> args.queue = 'xxbogusxx' + >>> command.process(args) + No such queue: xxbogusxx + +It is also an error to specify a mailing list that doesn't exist. + + >>> args.queue = None + >>> args.listname = ['bogus'] + >>> command.process(args) + No such list: bogus === modified file 'src/mailman/commands/docs/join.txt' --- src/mailman/commands/docs/join.txt 2009-08-26 14:51:52 +0000 +++ src/mailman/commands/docs/join.txt 2009-09-19 20:51:15 +0000 @@ -26,7 +26,6 @@ ------------------ >>> from mailman.email.message import Message - >>> from mailman.app.lifecycle import create_list >>> from mailman.queue.command import Results >>> mlist = create_list('[email protected]') === modified file 'src/mailman/commands/docs/lists.txt' --- src/mailman/commands/docs/lists.txt 2009-08-09 15:01:16 +0000 +++ src/mailman/commands/docs/lists.txt 2009-09-19 20:51:15 +0000 @@ -25,7 +25,6 @@ >>> domain_mgr.add('example.net') <Domain example.net...> - >>> from mailman.app.lifecycle import create_list >>> mlist_1 = create_list('[email protected]') >>> mlist_1.description = 'List One' === modified file 'src/mailman/commands/docs/members.txt' --- src/mailman/commands/docs/members.txt 2009-08-17 02:44:01 +0000 +++ src/mailman/commands/docs/members.txt 2009-09-19 20:51:15 +0000 @@ -4,7 +4,6 @@ You can add members to a mailing list from the command line. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('[email protected]') >>> class FakeArgs: === modified file 'src/mailman/commands/docs/remove.txt' --- src/mailman/commands/docs/remove.txt 2009-08-26 06:27:37 +0000 +++ src/mailman/commands/docs/remove.txt 2009-09-19 20:51:15 +0000 @@ -4,7 +4,6 @@ A system administrator can remove mailing lists by the command line. - >>> from mailman.app.lifecycle import create_list >>> create_list('[email protected]') <mailing list "[email protected]" at ...> @@ -31,7 +30,6 @@ You can also remove lists quietly. - >>> from mailman.app.lifecycle import create_list >>> create_list('[email protected]') <mailing list "[email protected]" at ...> @@ -47,7 +45,6 @@ By default 'mailman remove' does not remove a mailing list's archives. - >>> from mailman.app.lifecycle import create_list >>> create_list('[email protected]') <mailing list "[email protected]" at ...> === modified file 'src/mailman/database/__init__.py' --- src/mailman/database/__init__.py 2009-08-27 02:44:22 +0000 +++ src/mailman/database/__init__.py 2009-09-19 20:51:15 +0000 @@ -54,7 +54,7 @@ def __init__(self): self.url = None - self._store = None + self.store = None def initialize(self, debug=None): """See `IDatabase`.""" === modified file 'src/mailman/database/listmanager.py' --- src/mailman/database/listmanager.py 2009-08-26 06:27:37 +0000 +++ src/mailman/database/listmanager.py 2009-09-19 20:51:15 +0000 @@ -30,6 +30,7 @@ from zope.interface import implements from mailman.config import config +from mailman.core.errors import InvalidEmailAddress from mailman.database.mailinglist import MailingList from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError from mailman.interfaces.rest import IResolvePathNames @@ -44,7 +45,9 @@ # pylint: disable-msg=R0201 def create(self, fqdn_listname): """See `IListManager`.""" - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') + if len(hostname) == 0: + raise InvalidEmailAddress(fqdn_listname) mlist = config.db.store.find( MailingList, MailingList.list_name == listname, @@ -58,7 +61,7 @@ def get(self, fqdn_listname): """See `IListManager`.""" - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') mlist = config.db.store.find(MailingList, list_name=listname, host_name=hostname).one() === modified file 'src/mailman/database/mailinglist.py' --- src/mailman/database/mailinglist.py 2009-07-17 02:36:06 +0000 +++ src/mailman/database/mailinglist.py 2009-09-19 20:51:15 +0000 @@ -178,7 +178,8 @@ def __init__(self, fqdn_listname): super(MailingList, self).__init__() - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') + assert hostname, 'Bad list name: {0}'.format(fqdn_listname) self.list_name = listname self.host_name = hostname # For the pending database === modified file 'src/mailman/docs/listmanager.txt' --- src/mailman/docs/listmanager.txt 2009-08-26 06:27:37 +0000 +++ src/mailman/docs/listmanager.txt 2009-09-19 20:51:15 +0000 @@ -36,11 +36,19 @@ If you try to create a mailing list with the same name as an existing list, you will get an exception. - >>> mlist_dup = list_manager.create('[email protected]') + >>> list_manager.create('[email protected]') Traceback (most recent call last): ... ListAlreadyExistsError: [email protected] +It is an error to create a mailing list that isn't a fully qualified list name +(i.e. posting address). + + >>> list_manager.create('foo') + Traceback (most recent call last): + ... + InvalidEmailAddress: foo + Deleting a mailing list ======================= @@ -73,6 +81,11 @@ >>> print list_manager.get('[email protected]') None +You also get None if the list name is invalid. + + >>> print list_manager.get('foo') + None + Iterating over all mailing lists ================================ === modified file 'src/mailman/queue/docs/incoming.txt' --- src/mailman/queue/docs/incoming.txt 2009-07-19 02:31:45 +0000 +++ src/mailman/queue/docs/incoming.txt 2009-09-19 20:51:15 +0000 @@ -12,7 +12,6 @@ message eventually ending up in one of the four disposition states described above. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('[email protected]') >>> print mlist.start_chain built-in
_______________________________________________ Mailman-checkins mailing list [email protected] Unsubscribe: http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org
