def main(): """bin/mailman""" # Create the basic parser and add all globally common options. parser = argparse.ArgumentParser( description=_("""\ The GNU Mailman mailing list management system Copyright 1998-2012 by the Free Software Foundation, Inc. http://www.list.org """), formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( '-v', '--version', action='version', version=MAILMAN_VERSION_FULL, help=_('Print this version string and exit')) parser.add_argument( '-C', '--config', help=_("""\ Configuration file to use. If not given, the environment variable MAILMAN_CONFIG_FILE is consulted and used if set. If neither are given, a default configuration file is loaded.""")) # Look at all modules in the mailman.bin package and if they are prepared # to add a subcommand, let them do so. I'm still undecided as to whether # this should be pluggable or not. If so, then we'll probably have to # partially parse the arguments now, then initialize the system, then find # the plugins. Punt on this for now. subparser = parser.add_subparsers(title='Commands') subcommands = [] for command_class in find_components('mailman.commands', ICLISubCommand): command = command_class() verifyObject(ICLISubCommand, command) subcommands.append(command) # --help should display the subcommands by alphabetical order, except that # 'mailman help' should be first. def sort_function(command, other): """Sorting helper.""" if command.name == 'help': return -1 elif other.name == 'help': return 1 else: return cmp(command.name, other.name) subcommands.sort(cmp=sort_function) for command in subcommands: command_parser = subparser.add_parser( command.name, help=_(command.__doc__)) command.add(parser, command_parser) command_parser.set_defaults(func=command.process) args = parser.parse_args() if len(args.__dict__) == 0: # No arguments or subcommands were given. parser.print_help() parser.exit() # Initialize the system. Honor the -C flag if given. config_path = (None if args.config is None else os.path.abspath(os.path.expanduser(args.config))) initialize(config_path) # Perform the subcommand option. args.func(args)
def main(ctx, config_file, verbose, list_runners, once, runner_spec): # XXX https://github.com/pallets/click/issues/303 """Start a runner. The runner named on the command line is started, and it can either run through its main loop once (for those runners that support this) or continuously. The latter is how the master runner starts all its subprocesses. -r is required unless -l or -h is given, and its argument must be one of the names displayed by the -l switch. Normally, this script should be started from 'mailman start'. Running it separately or with -o is generally useful only for debugging. When run this way, the environment variable $MAILMAN_UNDER_MASTER_CONTROL will be set which subtly changes some error handling behavior. """ global log if runner_spec is None and not list_runners: ctx.fail(_('No runner name given.')) # Initialize the system. Honor the -C flag if given. initialize(config_file, verbose) log = logging.getLogger('mailman.runner') if verbose: console = logging.StreamHandler(sys.stderr) formatter = logging.Formatter(config.logging.root.format, config.logging.root.datefmt) console.setFormatter(formatter) logging.getLogger().addHandler(console) logging.getLogger().setLevel(logging.DEBUG) if list_runners: descriptions = {} for section in config.runner_configs: ignore, dot, shortname = section.name.rpartition('.') ignore, dot, classname = getattr(section, 'class').rpartition('.') descriptions[shortname] = classname longest = max(len(name) for name in descriptions) for shortname in sorted(descriptions): classname = descriptions[shortname] spaces = longest - len(shortname) name = (' ' * spaces) + shortname # noqa: F841 print(_('$name runs $classname')) sys.exit(0) runner = make_runner(*runner_spec, once=once) runner.set_signals() # Now start up the main loop log.info('{} runner started.'.format(runner.name)) runner.run() log.info('{} runner exiting.'.format(runner.name)) sys.exit(runner.status)
def main(): """The `mailman` command dispatcher.""" # Create the basic parser and add all globally common options. parser = argparse.ArgumentParser( description=_("""\ The GNU Mailman mailing list management system Copyright 1998-2016 by the Free Software Foundation, Inc. http://www.list.org """), formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('-v', '--version', action='version', version=MAILMAN_VERSION_FULL, help=_('Print this version string and exit')) parser.add_argument('-C', '--config', help=_("""\ Configuration file to use. If not given, the environment variable MAILMAN_CONFIG_FILE is consulted and used if set. If neither are given, a default configuration file is loaded.""")) # Look at all modules in the mailman.bin package and if they are prepared # to add a subcommand, let them do so. I'm still undecided as to whether # this should be pluggable or not. If so, then we'll probably have to # partially parse the arguments now, then initialize the system, then find # the plugins. Punt on this for now. subparser = parser.add_subparsers(title='Commands') subcommands = [] for command_class in find_components('mailman.commands', ICLISubCommand): command = command_class() verifyObject(ICLISubCommand, command) subcommands.append(command) subcommands.sort(key=cmp_to_key(_help_sorter)) for command in subcommands: command_parser = subparser.add_parser(command.name, help=_(command.__doc__)) command.add(parser, command_parser) command_parser.set_defaults(func=command.process) args = parser.parse_args() if len(args.__dict__) <= 1: # No arguments or subcommands were given. parser.print_help() parser.exit() # Initialize the system. Honor the -C flag if given. config_path = (None if args.config is None else os.path.abspath( os.path.expanduser(args.config))) initialize(config_path) # Perform the subcommand option. with transaction(): args.func(args)
def initialize(self, propagate_logs=None): """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: Optional flag specifying whether log messages in sub-loggers should be propagated to the master logger (and hence to the root logger). If not given, propagation is taken 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 initialize(config_file, propagate_logs=propagate_logs) self.sanity_check()
def initialize(self, propagate_logs=None): """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: Optional flag specifying whether log messages in sub-loggers should be propagated to the master logger (and hence to the root logger). If not given, propagation is taken 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) initialize(config_file, propagate_logs=propagate_logs) self.sanity_check()
def run(environ, start_response): """Create the WSGI application. Use this if you want to integrate Mailman's REST server with an external WSGI server, such as gunicorn. Be sure to set the $MAILMAN_CONFIG_FILE environment variable. """ # Imports are here to evaluate them lazily, prevent circular imports, and # make flake8 happy. global _initialized if not _initialized: from mailman.core.initialize import initialize # First things first, initialize the system before any other imports or # other operations. It must only be initialized once though. initialize(propagate_logs=True) _initialized = True # Hook things up to WSGI. from mailman.rest.wsgiapp import make_application app = make_application() return app(environ, start_response)
def main(config_file, restartable, force, runners, verbose): # XXX https://github.com/pallets/click/issues/303 """Master subprocess watcher. Start and watch the configured runners and ensure that they stay alive and kicking. Each runner is forked and exec'd in turn, with the master waiting on their process ids. When it detects a child runner has exited, it may restart it. The runners respond to SIGINT, SIGTERM, SIGUSR1 and SIGHUP. SIGINT, SIGTERM and SIGUSR1 all cause a runner to exit cleanly. The master will restart runners that have exited due to a SIGUSR1 or some kind of other exit condition (say because of an uncaught exception). SIGHUP causes the master and the runners to close their log files, and reopen then upon the next printed message. The master also responds to SIGINT, SIGTERM, SIGUSR1 and SIGHUP, which it simply passes on to the runners. Note that the master will close and reopen its own log files on receipt of a SIGHUP. The master also leaves its own process id in the file `data/master.pid` but you normally don't need to use this pid directly. """ initialize(config_file, verbose) # Acquire the master lock, exiting if we can't. We'll let the caller # handle any clean up or lock breaking. No `with` statement here because # Lock's constructor doesn't support a timeout. lock = acquire_lock(force) try: with open(config.PID_FILE, 'w') as fp: print(os.getpid(), file=fp) loop = Loop(lock, restartable, config.filename) loop.install_signal_handlers() try: loop.start_runners(runners) loop.loop() finally: loop.cleanup() os.remove(config.PID_FILE) finally: lock.unlock()
def initialize_config(ctx, param, value): if not ctx.resilient_parsing: initialize(value)
def main(): global log parser = argparse.ArgumentParser( description=_("""\ Start a runner The runner named on the command line is started, and it can either run through its main loop once (for those runners that support this) or continuously. The latter is how the master runner starts all its subprocesses. -r is required unless -l or -h is given, and its argument must be one of the names displayed by the -l switch. Normally, this script should be started from 'mailman start'. Running it separately or with -o is generally useful only for debugging. When run this way, the environment variable $MAILMAN_UNDER_MASTER_CONTROL will be set which subtly changes some error handling behavior. """)) parser.add_argument( '--version', action='version', version=MAILMAN_VERSION_FULL, help=_('Print this version string and exit')) parser.add_argument( '-C', '--config', help=_("""\ Configuration file to use. If not given, the environment variable MAILMAN_CONFIG_FILE is consulted and used if set. If neither are given, a default configuration file is loaded.""")) parser.add_argument( '-r', '--runner', metavar='runner[:slice:range]', dest='runner', action=ROptionAction, default=None, help=_("""\ Start the named runner, which must be one of the strings returned by the -l option. For runners that manage a queue directory, optional `slice:range` if given is used to assign multiple runner processes to that queue. range is the total number of runners for the queue while slice is the number of this runner from [0..range). For runners that do not manage a queue, slice and range are ignored. When using the `slice:range` form, you must ensure that each runner for the queue is given the same range value. If `slice:runner` is not given, then 1:1 is used. """)) parser.add_argument( '-o', '--once', default=False, action='store_true', help=_("""\ Run the named runner exactly once through its main loop. Otherwise, the runner runs indefinitely until the process receives a signal. This is not compatible with runners that cannot be run once.""")) parser.add_argument( '-l', '--list', default=False, action='store_true', help=_('List the available runner names and exit.')) parser.add_argument( '-v', '--verbose', default=None, action='store_true', help=_("""\ Display more debugging information to the log file.""")) args = parser.parse_args() if args.runner is None and not args.list: parser.error(_('No runner name given.')) # Initialize the system. Honor the -C flag if given. config_path = (None if args.config is None else os.path.abspath(os.path.expanduser(args.config))) initialize(config_path, args.verbose) log = logging.getLogger('mailman.runner') if args.verbose: console = logging.StreamHandler(sys.stderr) formatter = logging.Formatter(config.logging.root.format, config.logging.root.datefmt) console.setFormatter(formatter) logging.getLogger().addHandler(console) logging.getLogger().setLevel(logging.DEBUG) if args.list: descriptions = {} for section in config.runner_configs: ignore, dot, shortname = section.name.rpartition('.') ignore, dot, classname = getattr(section, 'class').rpartition('.') descriptions[shortname] = classname longest = max(len(name) for name in descriptions) for shortname in sorted(descriptions): classname = descriptions[shortname] spaces = longest - len(shortname) name = (' ' * spaces) + shortname # noqa: F841 print(_('$name runs $classname')) sys.exit(0) runner = make_runner(*args.runner, once=args.once) runner.set_signals() # Now start up the main loop log.info('%s runner started.', runner.name) runner.run() log.info('%s runner exiting.', runner.name) sys.exit(runner.status)
def main(): global log parser = argparse.ArgumentParser( description=_("""\ Start a runner The runner named on the command line is started, and it can either run through its main loop once (for those runners that support this) or continuously. The latter is how the master runner starts all its subprocesses. -r is required unless -l or -h is given, and its argument must be one of the names displayed by the -l switch. Normally, this script should be started from 'mailman start'. Running it separately or with -o is generally useful only for debugging. When run this way, the environment variable $MAILMAN_UNDER_MASTER_CONTROL will be set which subtly changes some error handling behavior. """)) parser.add_argument( '--version', action='version', version=MAILMAN_VERSION_FULL, help=_('Print this version string and exit')) parser.add_argument( '-C', '--config', help=_("""\ Configuration file to use. If not given, the environment variable MAILMAN_CONFIG_FILE is consulted and used if set. If neither are given, a default configuration file is loaded.""")) parser.add_argument( '-r', '--runner', metavar='runner[:slice:range]', dest='runner', action=ROptionAction, default=None, help=_("""\ Start the named runner, which must be one of the strings returned by the -l option. For runners that manage a queue directory, optional `slice:range` if given is used to assign multiple runner processes to that queue. range is the total number of runners for the queue while slice is the number of this runner from [0..range). For runners that do not manage a queue, slice and range are ignored. When using the `slice:range` form, you must ensure that each runner for the queue is given the same range value. If `slice:runner` is not given, then 1:1 is used. """)) parser.add_argument( '-o', '--once', default=False, action='store_true', help=_("""\ Run the named runner exactly once through its main loop. Otherwise, the runner runs indefinitely until the process receives a signal. This is not compatible with runners that cannot be run once.""")) parser.add_argument( '-l', '--list', default=False, action='store_true', help=_('List the available runner names and exit.')) parser.add_argument( '-v', '--verbose', default=None, action='store_true', help=_("""\ Display more debugging information to the log file.""")) args = parser.parse_args() if args.runner is None and not args.list: parser.error(_('No runner name given.')) # Initialize the system. Honor the -C flag if given. config_path = (None if args.config is None else os.path.abspath(os.path.expanduser(args.config))) initialize(config_path, args.verbose) log = logging.getLogger('mailman.runner') if args.verbose: console = logging.StreamHandler(sys.stderr) formatter = logging.Formatter(config.logging.root.format, config.logging.root.datefmt) console.setFormatter(formatter) logging.getLogger().addHandler(console) logging.getLogger().setLevel(logging.DEBUG) if args.list: descriptions = {} for section in config.runner_configs: ignore, dot, shortname = section.name.rpartition('.') ignore, dot, classname = getattr(section, 'class').rpartition('.') descriptions[shortname] = classname longest = max(len(name) for name in descriptions) for shortname in sorted(descriptions): classname = descriptions[shortname] name = (' ' * (longest - len(shortname))) + shortname print(_('$name runs $classname')) sys.exit(0) runner = make_runner(*args.runner, once=args.once) runner.set_signals() # Now start up the main loop log.info('%s runner started.', runner.name) runner.run() log.info('%s runner exiting.', runner.name) sys.exit(runner.status)
def main(): cfg = os.environ.get('MAILMANCONFIG', 'mailman.cfg') initialize(cfg, True) config.db.engine.execute(SQL) config.db.commit()
#!/usr/bin/python3 import os import sys from mailman.core.initialize import initialize from mailman.config import config from mailman.interfaces.pending import IPendings from mailman.interfaces.requests import IListRequests, RequestType from zope.component import getUtility def clean_pended(): getUtility(IPendings).evict() if __name__ == '__main__': if os.getuid() == 0: print("This script must be run as the mailman user", file=sys.stderr) sys.exit(1) initialize(config_path="/etc/mailman.cfg") clean_pended() config.db.commit()
#!/usr/bin/python3 """Wrapper script to work around mailman cli limitations in debian buster.""" # pylint: disable=import-error from mailman.app.membership import add_member, delete_member from mailman.core.initialize import initialize from mailman.database.transaction import transactional from mailman.interfaces.listmanager import IListManager from mailman.interfaces.member import DeliveryMode from mailman.interfaces.subscriptions import RequestRecord from zope.component import getUtility # initialize on import initialize() class ListManager: """Helper class to manage a mailman3 mailinglist.""" def __init__(self, mailinglist): self.list = getUtility(IListManager).get(mailinglist) @transactional def add(self, email): """Add email to mailinglist.""" add_member( self.list, RequestRecord(email, '', DeliveryMode.regular, self.list.preferred_language.code)) @transactional def delete(self, email):