From 4d0afa3872a1ce288c7019cd802ee02d01cf743d Mon Sep 17 00:00:00 2001 From: rjollos Date: Fri, 19 Aug 2016 02:56:10 +0000 Subject: [PATCH] 1.3.1dev: Replace `optparse` with `argparse` Refs #12148. git-svn-id: http://trac.edgewall.org/intertrac/log:/trunk@15064 af82e41b-90c4-0310-8c96-b1721e28e2e2 --- contrib/checkwiki.py | 51 +++--- contrib/htdigest.py | 129 +++++++------- contrib/htpasswd.py | 101 +++++------ contrib/sourceforge2trac.py | 18 +- trac/web/standalone.py | 347 +++++++++++++++++++----------------- 5 files changed, 335 insertions(+), 311 deletions(-) diff --git a/contrib/checkwiki.py b/contrib/checkwiki.py index ab25ba804b..89953eab14 100755 --- a/contrib/checkwiki.py +++ b/contrib/checkwiki.py @@ -12,6 +12,7 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://trac.edgewall.org/. +import argparse import os import sys from pkg_resources import resource_listdir, resource_string @@ -114,16 +115,24 @@ def write(self, data): pass -def parse_args(): - from optparse import OptionParser - parser = OptionParser(usage='Usage: %prog [options] [PAGES...]') - parser.add_option('-d', '--download', dest='download', default=False, - action='store_true', - help='Download default pages from trac.edgewall.org ' - 'before checking') - parser.add_option('-p', '--prefix', dest='prefix', default='', - help='Prepend "prefix/" to the page when downloading') - return parser.parse_args() +def parse_args(all_pages): + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--download', action='store_true', + help="download default pages from trac.edgewall.org " + "before checking") + parser.add_argument('-p', '--prefix', default='', + help="prepend PREFIX/ to the page name when " + "downloading") + parser.add_argument('pages', metavar='page', nargs='*', + help="the wiki page(s) to download and/or check") + + args = parser.parse_args() + if args.pages: + for page in args.pages: + if page not in all_pages: + parser.error("%s is not one of the default pages." % page) + + return args def download_default_pages(names, prefix): @@ -156,22 +165,22 @@ def download_default_pages(names, prefix): def main(): - options, args = parse_args() - names = sorted(name for name in resource_listdir('trac.wiki', - 'default-pages') - if not name.startswith('.')) - if args: - args = sorted(set(names) & set(map(os.path.basename, args))) + all_pages = sorted(name for name + in resource_listdir('trac.wiki', 'default-pages') + if not name.startswith('.')) + args = parse_args(all_pages) + if args.pages: + pages = sorted(args.pages) else: - args = names + pages = all_pages - if options.download: - download_default_pages(args, options.prefix) + if args.download: + download_default_pages(pages, args.prefix) env = EnvironmentStub(disable=['trac.mimeview.pygments.*']) load_components(env) with env.db_transaction: - for name in names: + for name in all_pages: wiki = WikiPage(env, name) wiki.text = resource_string('trac.wiki', 'default-pages/' + name).decode('utf-8') @@ -182,7 +191,7 @@ def main(): req = Mock(href=Href('/'), abs_href=Href('http://localhost/'), perm=MockPerm()) - for name in args: + for name in pages: wiki = WikiPage(env, name) if not wiki.exists: continue diff --git a/contrib/htdigest.py b/contrib/htdigest.py index 95e6851761..9abd951b04 100755 --- a/contrib/htdigest.py +++ b/contrib/htdigest.py @@ -17,19 +17,21 @@ from __future__ import print_function +import argparse import errno import fileinput +import getpass +import hashlib import sys -from getpass import getpass -from hashlib import md5 -from optparse import OptionParser + +from trac.util.text import printerr def ask_pass(): - pass1 = getpass('New password: ') - pass2 = getpass('Re-type new password: ') + pass1 = getpass.getpass('New password: ') + pass2 = getpass.getpass('Re-type new password: ') if pass1 != pass2: - print("They don't match, sorry", file=sys.stderr) + printerr("htdigest: password verification error") sys.exit(1) return pass1 @@ -41,67 +43,68 @@ def get_digest(userprefix, password=None): def make_digest(userprefix, password): - return userprefix + md5(userprefix + password).hexdigest() - + return userprefix + hashlib.md5(userprefix + password).hexdigest() -usage = "%prog [-c] [-b] passwordfile realm username" -parser = OptionParser(usage=usage) -parser.add_option('-c', action='store_true', dest='create', default=False, - help="Create a new file") -parser.add_option('-b', action='store_true', dest='batch', default=False, - help="Batch mode, password on the commandline.") -if len(sys.argv) <= 1: - parser.print_help() - sys.exit(1) +def main(): + """ + %(prog)s [-c] passwordfile realm username + %(prog)s -b[c] passwordfile realm username password\ + """ + parser = argparse.ArgumentParser(usage=main.__doc__) + parser.add_argument('-b', action='store_true', dest='batch', + help="batch mode; password is passed on the command " + "line IN THE CLEAR") + parser.add_argument('-c', action='store_true', dest='create', + help="create a new htdigest file, overwriting any " + "existing file") + parser.add_argument('passwordfile', help=argparse.SUPPRESS) + parser.add_argument('realm', help=argparse.SUPPRESS) + parser.add_argument('username', help=argparse.SUPPRESS) + parser.add_argument('password', nargs='?', help=argparse.SUPPRESS) -opts, args = parser.parse_args() + args = parser.parse_args() + if args.batch and args.password is None: + parser.error("too few arguments") + elif not args.batch and args.password is not None: + parser.error("too many arguments") -try: - if opts.batch: - filename, realm, username, password = args + prefix = '%s:%s:' % (args.username, args.realm) + if args.create: + try: + with open(args.passwordfile, 'w') as f: + print(get_digest(prefix, args.password), file=f) + except EnvironmentError as e: + if e.errno == errno.EACCES: + printerr("Unable to update file %s" % args.passwordfile) + sys.exit(1) + else: + raise else: - filename, realm, username = args - password = None -except ValueError: - parser.error("Wrong number of arguments") - -prefix = '%s:%s:' % (username, realm) - -if opts.create: - try: - f = open(filename, 'w') - except EnvironmentError as e: - if e.errno == errno.EACCES: - print("Unable to update file", filename, file=sys.stderr) - sys.exit(1) - else: - raise - try: - print(get_digest(prefix, password), file=f) - finally: - f.close() -else: - try: matched = False - for line in fileinput.input(filename, inplace=True): - if line.startswith(prefix): - if not matched: - print(get_digest(prefix, password)) - matched = True + try: + for line in fileinput.input(args.passwordfile, inplace=True): + if line.startswith(prefix): + if not matched: + print(get_digest(prefix, args.password)) + matched = True + else: + print(line.rstrip()) + if not matched: + with open(args.passwordfile, 'a') as f: + print(get_digest(prefix, args.password), file=f) + except EnvironmentError as e: + if e.errno == errno.ENOENT: + printerr("Could not open password file %s for reading. " + "Use -c option to create a new one." + % args.passwordfile) + sys.exit(1) + elif e.errno == errno.EACCES: + printerr("Unable to update file %s" % args.passwordfile) + sys.exit(1) else: - print(line.rstrip()) - if not matched: - with open(filename, 'a') as f: - print(get_digest(prefix, password), file=f) - except EnvironmentError as e: - if e.errno == errno.ENOENT: - print("Could not open passwd file %s for reading." % filename, - file=sys.stderr) - print("Use -c option to create a new one.", file=sys.stderr) - sys.exit(1) - elif e.errno == errno.EACCES: - print("Unable to update file", filename, file=sys.stderr) - sys.exit(1) - else: - raise + raise + + +if __name__ == '__main__': + main() diff --git a/contrib/htpasswd.py b/contrib/htpasswd.py index 5c9ed11c1c..48a7e73e2b 100755 --- a/contrib/htpasswd.py +++ b/contrib/htpasswd.py @@ -13,13 +13,13 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://trac.edgewall.org/. +import argparse import getpass -import optparse import sys from trac.util import salt from trac.util.compat import crypt, wait_for_file_mtime_change -from trac.util.text import printerr, printout +from trac.util.text import printerr if crypt is None: printerr("The crypt module is not found. Install the passlib package " @@ -27,6 +27,15 @@ sys.exit(1) +def ask_pass(): + pass1 = getpass.getpass('New password: ') + pass2 = getpass.getpass('Re-type new password: ') + if pass1 != pass2: + printerr("htpasswd: password verification error") + sys.exit(1) + return pass1 + + class HtpasswdFile(object): """A class for manipulating htpasswd files.""" @@ -70,65 +79,49 @@ def delete(self, username): def main(): """ - %prog [-c] filename username - %prog -b[c] filename username password - %prog -D filename username + %(prog)s [-c] passwordfile username + %(prog)s -b[c] passwordfile username password + %(prog)s -D passwordfile username\ """ - # For now, we only care about the use cases that affect tests/functional.py - parser = optparse.OptionParser(usage=main.__doc__) - parser.add_option('-b', action='store_true', dest='batch', default=False, - help='Batch mode; password is passed on the command line IN THE CLEAR.' - ) - parser.add_option('-c', action='store_true', dest='create', default=False, - help='Create a new htpasswd file, overwriting any existing file.') - parser.add_option('-D', action='store_true', dest='delete_user', - default=False, help='Remove the given user from the password file.') - - if len(sys.argv) <= 1: - parser.print_help() - sys.exit(1) - - options, args = parser.parse_args() - def syntax_error(msg): - """Utility function for displaying fatal error messages with usage - help. - """ - printerr("Syntax error: " + msg, newline=True) - printerr(parser.format_help(), newline=True) - sys.exit(1) - - # Non-option arguments - if len(args) < 2: - syntax_error("Insufficient number of arguments.\n") - filename, username = args[:2] - password = None - if options.delete_user: - if len(args) != 2: - syntax_error("Incorrect number of arguments.\n") + parser = argparse.ArgumentParser(usage=main.__doc__) + parser.add_argument('-b', action='store_true', dest='batch', + help="batch mode; password is passed on the command " + "line IN THE CLEAR") + parser_group = parser.add_mutually_exclusive_group() + parser_group.add_argument('-c', action='store_true', dest='create', + help="create a new htpasswd file, overwriting " + "any existing file") + parser_group.add_argument('-D', action='store_true', dest='delete_user', + help="remove the given user from the password " + "file") + parser.add_argument('passwordfile', help=argparse.SUPPRESS) + parser.add_argument('username', help=argparse.SUPPRESS) + parser.add_argument('password', nargs='?', help=argparse.SUPPRESS) + + args = parser.parse_args() + password = args.password + if args.delete_user: + if password is not None: + parser.error("too many arguments") else: - if len(args) == 3 and options.batch: - password = args[2] - elif len(args) == 2 and not options.batch: - first = getpass.getpass("New password:") - second = getpass.getpass("Re-type new password:") - if first == second: - password = first - else: - printout("htpasswd: password verification error") - return - else: - syntax_error("Incorrect number of arguments.\n") + if args.batch and password is None: + parser.error("too few arguments") + elif not args.batch and password is not None: + parser.error("too many arguments") try: - passwdfile = HtpasswdFile(filename, create=options.create) - except IOError: - syntax_error("File not found.\n") + passwdfile = HtpasswdFile(args.passwordfile, create=args.create) + except EnvironmentError: + printerr("File not found.") + sys.exit(1) else: - if options.delete_user: - passwdfile.delete(username) + if args.delete_user: + passwdfile.delete(args.username) else: - passwdfile.update(username, password) + if password is None: + password = ask_pass() + passwdfile.update(args.username, password) passwdfile.save() diff --git a/contrib/sourceforge2trac.py b/contrib/sourceforge2trac.py index a630cebf7f..6b3f0e66a6 100755 --- a/contrib/sourceforge2trac.py +++ b/contrib/sourceforge2trac.py @@ -85,7 +85,7 @@ severities:no field in source data """ -import optparse +import argparse import sys import time from xml.etree.ElementTree import ElementTree @@ -512,7 +512,7 @@ def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue): """, (ticket, time, author, field, oldvalue, newvalue)) -def importData(f, env, opt): +def importData(f, env): project = ExportedProjectData(f) trackers = project.trackers @@ -695,15 +695,15 @@ def importData(f, env, opt): def main(): - p = optparse.OptionParser( - "Usage: %prog xml_export.xml /path/to/trac/environment") - opt, args = p.parse_args() - if len(args) != 2: - p.error("Incorrect number of arguments") + parser = argparse.ArgumentParser() + parser.add_argument('filename', help="XML export file from sourceforge") + parser.add_argument('environment', help="path to Trac environment") + args = parser.parse_args() try: - importData(open(args[0]), args[1], opt) - except DBNotEmpty as e: + with open(args.filename, 'r') as f: + importData(f, args.environment) + except Exception as e: printerr("Error: %s" % e) sys.exit(1) diff --git a/trac/web/standalone.py b/trac/web/standalone.py index e46139b3b1..63baae44b7 100755 --- a/trac/web/standalone.py +++ b/trac/web/standalone.py @@ -21,14 +21,17 @@ from __future__ import print_function -import pkg_resources +import argparse +import functools import os +import pkg_resources import socket import sys from SocketServer import ThreadingMixIn from trac import __version__ as VERSION from trac.util import autoreload, daemon +from trac.util.text import printerr from trac.web.auth import BasicAuthentication, DigestAuthentication from trac.web.main import dispatch_request from trac.web.wsgi import WSGIServer, WSGIRequestHandler @@ -114,169 +117,186 @@ class TracHTTP11RequestHandler(TracHTTPRequestHandler): protocol_version = 'HTTP/1.1' -def main(): - from optparse import OptionParser, OptionValueError - parser = OptionParser(usage='usage: %prog [options] [projenv] ...', - version='%%prog %s' % VERSION) - - auths = {} - def _auth_callback(option, opt_str, value, parser, cls): - info = value.split(',', 3) - if len(info) != 3: - raise OptionValueError("Incorrect number of parameters for %s" - % option) - - env_name, filename, realm = info - if env_name in auths: - print('Ignoring duplicate authentication option for project: %s' - % env_name, file=sys.stderr) - else: - auths[env_name] = cls(os.path.abspath(filename), realm) - - def _validate_callback(option, opt_str, value, parser, valid_values): - if value not in valid_values: - raise OptionValueError('%s must be one of: %s, not %s' - % (opt_str, '|'.join(valid_values), value)) - setattr(parser.values, option.dest, value) - - def _octal(option, opt_str, value, parser): - try: - setattr(parser.values, option.dest, int(value, 8)) - except ValueError: - raise OptionValueError('Invalid octal umask value: %r' % value) - - parser.add_option('-a', '--auth', action='callback', type='string', - metavar='DIGESTAUTH', callback=_auth_callback, - callback_args=(DigestAuthentication,), - help='[projectdir],[htdigest_file],[realm]') - parser.add_option('--basic-auth', action='callback', type='string', - metavar='BASICAUTH', callback=_auth_callback, - callback_args=(BasicAuthentication,), - help='[projectdir],[htpasswd_file],[realm]') - - parser.add_option('-p', '--port', action='store', type='int', dest='port', - help='the port number to bind to') - parser.add_option('-b', '--hostname', action='store', dest='hostname', - help='the host name or IP address to bind to') - parser.add_option('--protocol', action='callback', type="string", - dest='protocol', callback=_validate_callback, - callback_args=(('http', 'scgi', 'ajp', 'fcgi'),), - help='http|scgi|ajp|fcgi') - parser.add_option('-q', '--unquote', action='store_true', - dest='unquote', - help='unquote PATH_INFO (may be needed when using ajp)') - parser.add_option('--http10', action='store_false', dest='http11', - help='use HTTP/1.0 protocol version instead of HTTP/1.1') - parser.add_option('--http11', action='store_true', dest='http11', - help='use HTTP/1.1 protocol version (default)') - parser.add_option('-e', '--env-parent-dir', action='store', - dest='env_parent_dir', metavar='PARENTDIR', - help='parent directory of the project environments') - parser.add_option('--base-path', action='store', type='string', # XXX call this url_base_path? - dest='base_path', - help='the initial portion of the request URL\'s "path"') - - parser.add_option('-r', '--auto-reload', action='store_true', - dest='autoreload', - help='restart automatically when sources are modified') - - parser.add_option('-s', '--single-env', action='store_true', - dest='single_env', help='only serve a single ' - 'project without the project list', default=False) +def parse_args(args=None): + parser = argparse.ArgumentParser() + + class _AuthAction(argparse.Action): + + def __init__(self, option_strings, dest, nargs=None, **kwargs): + self.cls = kwargs.pop('cls') + super(_AuthAction, self).__init__(option_strings, dest, nargs, + **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + info = values.split(',') + if len(info) != 3: + raise argparse.ArgumentError(self, + "Incorrect number of parameters") + env_name, filename, realm = info + filepath = os.path.abspath(filename) + auths = getattr(namespace, self.dest) + if env_name in auths: + printerr("Ignoring duplicate authentication option for " + "project: %s" % env_name) + else: + auths.update({env_name: self.cls(filepath, realm)}) + setattr(namespace, self.dest, auths) + + class _PathAction(argparse.Action): + + def __call__(self, parser, namespace, values, option_string=None): + if isinstance(values, list): + paths = [os.path.abspath(paths) for paths in values] + else: + paths = os.path.abspath(values) + setattr(namespace, self.dest, paths) + + parser.add_argument('--version', action='version', + version='%%(prog)s %s' % VERSION) + parser.add_argument('envs', action=_PathAction, nargs='*', + help="path of the project environment(s)") + + parser_group = parser.add_mutually_exclusive_group() + parser_group.add_argument('-e', '--env-parent-dir', action=_PathAction, + metavar='PARENTDIR', + help="parent directory of the project " + "environments") + parser_group.add_argument('-s', '--single-env', action='store_true', + help="only serve a single project without the " + "project list") + + parser_group = parser.add_mutually_exclusive_group() + parser_group.add_argument('-a', '--auth', default={}, + metavar='DIGESTAUTH', dest='auths', + action=_AuthAction, cls=DigestAuthentication, + help="[projectdir],[htdigest_file],[realm]") + parser_group.add_argument('--basic-auth', default={}, + metavar='BASICAUTH', dest='auths', + action=_AuthAction, cls=BasicAuthentication, + help="[projectdir],[htpasswd_file],[realm]") + + parser.add_argument('-p', '--port', type=int, + help="the port number to bind to") + parser.add_argument('-b', '--hostname', default='', + help="the host name or IP address to bind to") + parser.add_argument('--protocol', default='http', + choices=('http', 'scgi', 'ajp', 'fcgi'), + help="the server protocol (default: http)") + parser.add_argument('-q', '--unquote', action='store_true', + help="unquote PATH_INFO (may be needed when using " + "the ajp protocol)") + parser.add_argument('--base-path', default='', # XXX call this url_base_path? + help="the initial portion of the request URL's " + "\"path\"") + + parser_group = parser.add_mutually_exclusive_group() + parser_group.add_argument('--http10', action='store_false', dest='http11', + help="use HTTP/1.0 protocol instead of " + "HTTP/1.1") + parser_group.add_argument('--http11', action='store_true', default=True, + help="use HTTP/1.1 protocol (default)") if os.name == 'posix': - parser.add_option('-d', '--daemonize', action='store_true', - dest='daemonize', - help='run in the background as a daemon') - parser.add_option('--pidfile', action='store', - dest='pidfile', - help='when daemonizing, file to which to write pid') - parser.add_option('--umask', action='callback', type='string', - dest='umask', metavar='MASK', callback=_octal, - help='when daemonizing, file mode creation mask ' - 'to use, in octal notation (default 022)') - - try: - import grp, pwd - - def _group(option, opt_str, value, parser): + class _GroupAction(argparse.Action): + + def __call__(self, parser, namespace, values, option_string=None): + import grp try: - value = int(value) + value = int(values) except ValueError: try: - value = grp.getgrnam(value)[2] + value = grp.getgrnam(values)[2] except KeyError: - raise OptionValueError('group not found: %r' % value) - setattr(parser.values, option.dest, value) + raise argparse.ArgumentError(self, "group not found: " + "%r" % values) + setattr(namespace, self.dest, value) + + class _UserAction(argparse.Action): - def _user(option, opt_str, value, parser): + def __call__(self, parser, namespace, values, option_string=None): + import pwd try: - value = int(value) + value = int(values) except ValueError: try: - value = pwd.getpwnam(value)[2] + value = pwd.getpwnam(values)[2] except KeyError: - raise OptionValueError('user not found: %r' % value) - setattr(parser.values, option.dest, value) - - parser.add_option('--group', action='callback', type='string', - dest='group', metavar='GROUP', callback=_group, - help='the group to run as') - parser.add_option('--user', action='callback', type='string', - dest='user', metavar='USER', callback=_user, - help='the user to run as') - except ImportError: - pass - - parser.set_defaults(port=None, hostname='', base_path='', daemonize=False, - protocol='http', http11=True, umask=022, user=None, - group=None) - options, args = parser.parse_args() - - if not args and not options.env_parent_dir: - parser.error('either the --env-parent-dir option or at least one ' - 'environment must be specified') - if options.single_env: - if options.env_parent_dir: - parser.error('the --single-env option cannot be used with ' - '--env-parent-dir') - elif len(args) > 1: - parser.error('the --single-env option cannot be used with ' - 'more than one enviroment') - if options.daemonize and options.autoreload: - parser.error('the --auto-reload option cannot be used with ' - '--daemonize') - - if options.port is None: - options.port = { + raise argparse.ArgumentError(self, "user not found: " + "%r" % values) + setattr(namespace, self.dest, value) + + class _OctalValueAction(argparse.Action): + + octal = functools.partial(int, base=8) + + def __call__(self, parser, namespace, values, option_string=None): + try: + value = self.octal(values) + except ValueError: + raise argparse.ArgumentError(self, "Invalid octal umask " + "value: %r" % values) + setattr(namespace, self.dest, value) + + parser_group = parser.add_mutually_exclusive_group() + parser_group.add_argument('-r', '--auto-reload', action='store_true', + help="restart automatically when sources " + "are modified") + parser_group.add_argument('-d', '--daemonize', action='store_true', + help="run in the background as a daemon") + parser.add_argument('--pidfile', action=_PathAction, + help="file to write pid when daemonizing") + parser.add_argument('--umask', action=_OctalValueAction, + default=0o022, metavar='MASK', + help="when daemonizing, file mode creation mask " + "to use, in octal notation (default: 022)") + parser.add_argument('--group', action=_GroupAction, + help="the group to run as") + parser.add_argument('--user', action=_UserAction, + help="the user to run as") + else: + parser.add_argument('-r', '--auto-reload', action='store_true', + help="restart automatically when sources are " + "modified") + + parser.set_defaults(daemonize=False, user=None, group=None) + args = parser.parse_args(args) + + if not args.env_parent_dir and not args.envs: + parser.error("either the --env-parent-dir (-e) option or at least " + "one environment must be specified") + if args.single_env and len(args.envs) > 1: + parser.error("the --single-env (-s) option cannot be used with more " + "than one environment") + + if args.port is None: + args.port = { 'http': 80, 'scgi': 4000, 'ajp': 8009, 'fcgi': 8000, - }[options.protocol] - server_address = (options.hostname, options.port) - - # relative paths don't work when daemonized - args = [os.path.abspath(a) for a in args] - if options.env_parent_dir: - options.env_parent_dir = os.path.abspath(options.env_parent_dir) - if parser.has_option('pidfile') and options.pidfile: - options.pidfile = os.path.abspath(options.pidfile) - - wsgi_app = TracEnvironMiddleware(dispatch_request, - options.env_parent_dir, args, - options.single_env) - if auths: - if options.single_env: - project_name = os.path.basename(args[0]) - wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) + }[args.protocol] + + return args + + +def main(): + args = parse_args() + + wsgi_app = TracEnvironMiddleware(dispatch_request, args.env_parent_dir, + args.envs, args.single_env) + if args.auths: + if args.single_env: + project_name = os.path.basename(args.envs[0]) + wsgi_app = AuthenticationMiddleware(wsgi_app, args.auths, + project_name) else: - wsgi_app = AuthenticationMiddleware(wsgi_app, auths) - base_path = options.base_path.strip('/') + wsgi_app = AuthenticationMiddleware(wsgi_app, args.auths) + base_path = args.base_path.strip('/') if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) - if options.protocol == 'http': + server_address = (args.hostname, args.port) + if args.protocol == 'http': def serve(): addr, port = server_address if not addr or addr == '0.0.0.0': @@ -287,8 +307,8 @@ def serve(): try: httpd = TracHTTPServer(server_address, wsgi_app, - options.env_parent_dir, args, - use_http_11=options.http11) + args.env_parent_dir, args.envs, + use_http_11=args.http11) except socket.error as e: print("Error starting Trac server on %s" % loc) print("[Errno %s] %s" % e.args) @@ -296,39 +316,38 @@ def serve(): print("Server starting in PID %s." % os.getpid()) print("Serving on %s" % loc) - if options.http11: + if args.http11: print("Using HTTP/1.1 protocol version") httpd.serve_forever() - elif options.protocol in ('scgi', 'ajp', 'fcgi'): + elif args.protocol in ('scgi', 'ajp', 'fcgi'): def serve(): - server_cls = __import__('flup.server.%s' % options.protocol, + server_cls = __import__('flup.server.%s' % args.protocol, None, None, ['']).WSGIServer flup_app = wsgi_app - if options.unquote: + if args.unquote: from trac.web.fcgi_frontend import FlupMiddleware flup_app = FlupMiddleware(flup_app) ret = server_cls(flup_app, bindAddress=server_address).run() - sys.exit(42 if ret else 0) # if SIGHUP exit with status 42 + sys.exit(42 if ret else 0) # if SIGHUP exit with status 42 try: - if options.daemonize: - daemon.daemonize(pidfile=options.pidfile, progname='tracd', - umask=options.umask) - if options.group is not None: - os.setgid(options.group) - if options.user is not None: - os.setuid(options.user) - - if options.autoreload: + if args.daemonize: + daemon.daemonize(pidfile=args.pidfile, progname='tracd', + umask=args.umask) + if args.group is not None: + os.setgid(args.group) + if args.user is not None: + os.setuid(args.user) + + if args.auto_reload: def modification_callback(file): - print("Detected modification of %s, restarting." % file, - file=sys.stderr) + printerr("Detected modification of %s, restarting." % file) autoreload.main(serve, modification_callback) else: serve() except OSError as e: - print("%s: %s" % (e.__class__.__name__, e), file=sys.stderr) + printerr("%s: %s" % (e.__class__.__name__, e)) sys.exit(1) except KeyboardInterrupt: pass