diff options
| author | ianb <devnull@localhost> | 2005-05-18 07:37:44 +0000 |
|---|---|---|
| committer | ianb <devnull@localhost> | 2005-05-18 07:37:44 +0000 |
| commit | 0f2e939f36746f130b1bd67a1797b58688d5ac1c (patch) | |
| tree | b43210578bae15f5b8786342e97432555625927b | |
| parent | 430c3392dc166a4f9bec48f70c8bf7b6b140560d (diff) | |
| download | paste-0f2e939f36746f130b1bd67a1797b58688d5ac1c.tar.gz | |
Made app_templates pluggable; added serve command to paste-setup
| -rw-r--r-- | paste/app_setup.py | 137 | ||||
| -rwxr-xr-x | paste/server.py | 52 | ||||
| -rw-r--r-- | paste/servers/ajp_threaded_server.py | 17 | ||||
| -rw-r--r-- | paste/servers/console_server.py | 11 | ||||
| -rw-r--r-- | paste/servers/fastcgi_threaded_server.py | 17 | ||||
| -rw-r--r-- | paste/servers/scgi_server/__init__.py | 9 | ||||
| -rw-r--r-- | paste/servers/scgi_threaded_server.py | 17 | ||||
| -rw-r--r-- | paste/servers/wsgiutils_server.py | 9 | ||||
| -rw-r--r-- | paste/util/plugin.py | 7 |
9 files changed, 218 insertions, 58 deletions
diff --git a/paste/app_setup.py b/paste/app_setup.py index a0b6047..6516c1c 100644 --- a/paste/app_setup.py +++ b/paste/app_setup.py @@ -6,11 +6,15 @@ import os import sys from cStringIO import StringIO import re +import textwrap from paste.util.thirdparty import load_new_module string = load_new_module('string', (2, 4)) from paste import pyconfig from paste import urlparser +from paste import server +from paste import CONFIG +from paste.util import plugin class InvalidCommand(Exception): pass @@ -37,18 +41,10 @@ def find_template_info(args): else: server_conf_fn, template_name = find_template_config(args) if not template_name: - raise InvalidCommand( - 'No template given (provide --template=name or run this command ' - 'from a directory containing server.conf)') - if not re.search(r'^[a-zA-Z_][a-zA-Z0-9_]*$', template_name): - raise InvalidCommand( - 'The template name %r is invalid; template names can contain only ' - 'letters, numbers, and _.' % template_name) - try: - template_mod = load_template(template_name) - except ImportError, e: - raise InvalidCommand( - 'No template exists by the name %r (%s)' % (template_name, e)) + template_name = 'default' + template_mod = plugin.load_plugin_module( + 'app_templates', 'paste.app_templates', + template_name, '_tmpl') return (server_conf_fn, template_name, os.path.dirname(template_mod.__file__), template_mod) @@ -58,7 +54,7 @@ def find_template_option(args): if copy[0] == '--': return None, copy if copy[0] == '-t' or copy[0] == '--template': - if not copy[1:]: + if not copy[1:] or copy[1].startswith('-'): raise InvalidCommand( '%s needs to be followed with a template name' % copy[0]) return copy[1], copy[2:] @@ -72,23 +68,11 @@ def find_template_option(args): def find_template_config(args): conf_fn = os.path.join(os.getcwd(), 'server.conf') if not os.path.exists(conf_fn): - return None + return None, None conf = pyconfig.Config(with_default=True) conf.load(conf_fn) return conf_fn, conf.get('app_template') -def load_template(template_name): - base = os.path.join(os.path.dirname(__file__), 'app_templates') - full_name = 'paste.app_templates.%s.command' % template_name - errors = StringIO() - mod = urlparser.load_module_from_name( - None, os.path.join(base, template_name, 'command'), - full_name, errors) - if mod is None: - raise InvalidCommand( - 'Cannot load module: %s' % errors.getvalue()) - return mod - def run(args): try: server_conf_fn, name, dir, mod = find_template_info(args) @@ -142,6 +126,7 @@ class CommandRunner(object): # @@: these commands shouldn't require a template self.register(CommandHelp) self.register(CommandList) + self.register(CommandServe) ############################################################ ## Command framework @@ -193,13 +178,7 @@ class Command(object): self.template_module = template_module def run(self): - self.parser.usage = "%%prog [options]\n%s" % self.summary - self.parser.prog = '%s %s' % ( - os.path.basename(self.invoked_as), - self.command_name) - if self.description: - self.parser.description = self.description - self.options, self.args = self.parser.parse_args(self.raw_args) + self.parse_args(self.raw_args) if (getattr(self.options, 'simulate', False) and not self.options.verbose): self.options.verbose = 1 @@ -217,6 +196,15 @@ class Command(object): 'You must provide the option %s' % option_name) self.command() + def parse_args(self, args): + self.parser.usage = "%%prog [options]\n%s" % self.summary + self.parser.prog = '%s %s' % ( + os.path.basename(self.invoked_as), + self.command_name) + if self.description: + self.parser.description = self.description + self.options, self.args = self.parser.parse_args(args) + def ask(self, prompt, safe=False, default=True): if self.options.interactive >= 2: default = safe @@ -277,6 +265,89 @@ class CommandList(Command): f.close() return content +class CommandServe(Command): + + name = 'serve' + summary = 'Run server' + parser = standard_parser(simulate=False) + + def command(self): + sys.exit(server.run_commandline(self.args)) + + def parse_args(self, args): + # Unlike most commands, this takes arbitrary options and folds + # them into the configuration + conf, app = server.load_commandline(args) + if conf is None: + sys.exit(app) + if app == 'help': + self.help(conf) + sys.exit() + if conf.get('list_servers'): + self.list_servers(conf) + sys.exit() + CONFIG.push_process_config(conf) + sys.exit(server.run_server(conf, app)) + self.config = conf + + def help(self, config): + # Here we make a fake parser just to get the help + parser = optparse.OptionParser() + group = parser.add_option_group("general options") + group.add_options(server.load_commandline_options()) + extra_help = None + if config.get('server'): + try: + server_mod = server.get_server_mod(config['server']) + except plugin.PluginNotFound, e: + print "Server %s not found" % config['server'] + print " (%s)" % e + sys.exit(1) + ops = getattr(server_mod, 'options', None) + if ops: + group = parser.add_option_group( + "%s options" % server_mod.plugin_name, + description=getattr(server_mod, 'description', None)) + group.add_options(ops) + extra_help = getattr(server_mod, 'help', None) + parser.print_help() + if extra_help: + print + # @@: textwrap kills any special formatting, so maybe + # we just can't use it + #print self.fill_text(extra_help) + print extra_help + + def list_servers(self, config): + server_ops = plugin.find_plugins('servers', '_server') + server_ops.sort() + print 'These servers are available:' + print + for server_name in server_ops: + self.show_server(server_name) + + def show_server(self, server_name): + server_mod = server.get_server_mod(server_name) + print '%s:' % server_mod.plugin_name + desc = getattr(server_mod, 'description', None) + if not desc: + print ' No description available' + else: + print self.fill_text(desc) + + def fill_text(self, text): + try: + width = int(os.environ['COLUMNS']) + except (KeyError, ValueError): + width = 80 + width -= 2 + return textwrap.fill( + text, + width, + initial_indent=' '*4, + subsequent_indent=' '*4) + + class CommandHelp(Command): name = 'help' diff --git a/paste/server.py b/paste/server.py index b018384..1f82124 100755 --- a/paste/server.py +++ b/paste/server.py @@ -63,12 +63,9 @@ def load_commandline(args, allow_reload=True): conf = pyconfig.Config(with_default=True) conf.load_commandline( args, bool_options=['help', 'verbose', 'reload', 'debug', 'quiet', - 'no_verbose'], + 'no_verbose', 'list_servers'], aliases={'h': 'help', 'v': 'verbose', 'f': 'config_file', 'D': 'debug', 'q': 'quiet'}) - if conf.get('help'): - print help() - return None, 0 if conf.get('no_verbose'): conf['verbose'] = False if not conf.get('no_server_conf') and os.path.exists('server.conf'): @@ -77,11 +74,16 @@ def load_commandline(args, allow_reload=True): load_conf(conf, conf['config_file'], True) if conf['quiet']: conf['verbose'] = False + if conf.get('help'): + return conf, 'help' + if conf.get('list_servers'): + return conf, None server = conf.get('server') if not server: server_ops = plugin.find_plugins('servers', '_server') server_ops.sort() - print "Missing --server=name, one of: %s" % ', '.join(server_ops) + print "Missing --server=NAME" + print "Use --list-servers for a description of available servers" return None, 0 if conf['reload'] and allow_reload: if os.environ.get(reloader_environ_key): @@ -97,6 +99,36 @@ def load_commandline(args, allow_reload=True): app = make_app(conf) return conf, app +def load_commandline_options(): + """ + Fake command line options, for use with help messages + """ + from optparse import Option, OptionGroup + return [ + Option('-v', '--verbose', + help="Be verbose", + action="store_true"), + Option('--reload', + help="Activate reloader", + action="store_true"), + Option('-D', '--debug', + help="Turn on debug mode (tracebacks display in browser)", + action="store_true"), + Option('-q', '--quiet', + help="Display as little output as possible", + action="store_true"), + Option('-f', '--config-file', + help="Load the given configuration file (default: server.conf)", + metavar="FILENAME"), + Option('--no-verbose', + help="Suppress verbose (useful if configuration specifies verbose)", + action="store_true"), + Option('--list-servers', + help="List available servers", + action="store_true"), + ] + + def run_commandline(args): conf, app = load_commandline(args) if conf is None: @@ -104,12 +136,12 @@ def run_commandline(args): CONFIG.push_process_config(conf) return run_server(conf, app) -def run_server(conf, app): +def get_server_mod(server_name): try: server_mod = plugin.load_plugin_module( dir='servers', dir_package='paste.servers', - name=conf['server'], + name=server_name, name_extension='_server') except plugin.PluginNotFound, e: print "Error loading server: %s" % e @@ -117,7 +149,11 @@ def run_server(conf, app): server_ops = plugin.find_plugins('servers', '_server') server_ops.sort() print ', '.join(server_ops) - return 1 + sys.exit(1) + return server_mod + +def run_server(conf, app): + server_mod = get_server_mod(conf['server']) if conf['verbose']: print "Starting server." try: diff --git a/paste/servers/ajp_threaded_server.py b/paste/servers/ajp_threaded_server.py index 130baa4..d1e6e92 100644 --- a/paste/servers/ajp_threaded_server.py +++ b/paste/servers/ajp_threaded_server.py @@ -1,3 +1,4 @@ +from optparse import Option from paste.util import thirdparty thirdparty.add_package('flup') from paste import pyconfig @@ -17,10 +18,18 @@ def serve_server(conf, app, server_class): return server.run() options = [ - ('host', 'The host name to bind to (default localhost). Note, if binding to localhost, only local connections will be allowed.'), - ('port', 'The port to bind to (default 8009).'), - ('root_url', 'The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), - ('allowed_servers', 'A list of servers to allow connections from.'), + Option('--host', + metavar="HOST", + help='The host name to bind to (default localhost). Note, if binding to localhost, only local connections will be allowed.'), + Option('--port', + metavar="PORT", + help='The port to bind to (default 8009).'), + Option('--root-url', + metavar="URL", + help='The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), + Option('--allowed-servers', + metavar="IP_LIST", + help='A list of servers to allow connections from.'), ] description = """\ diff --git a/paste/servers/console_server.py b/paste/servers/console_server.py index 92f4456..02512a9 100644 --- a/paste/servers/console_server.py +++ b/paste/servers/console_server.py @@ -1,4 +1,5 @@ from paste import wsgilib +from optparse import Option def serve(conf, app): url = conf.get('url', '/') @@ -30,3 +31,13 @@ def serve(conf, app): if errors: sys.stderr.write('-'*25 + ' Errors ' + '-'*25 + '\n') sys.stderr.write(errors + '\n') + +description = """\ +Displays a single request to stdout +""" + +options = [ + Option('--url', + metavar='URL', + help="The URL (not including domain or port!) to GET"), + ] diff --git a/paste/servers/fastcgi_threaded_server.py b/paste/servers/fastcgi_threaded_server.py index ae3a797..d8857f7 100644 --- a/paste/servers/fastcgi_threaded_server.py +++ b/paste/servers/fastcgi_threaded_server.py @@ -1,4 +1,5 @@ import os +from optparse import Option from paste.util import thirdparty thirdparty.add_package('flup') from paste import pyconfig @@ -26,10 +27,18 @@ def serve_server(conf, app, server_class): return server.run() options = [ - ('socket', 'The filename of a socket to listen to for connections. Default is fcgi_sock in the current directory.'), - ('host', 'The host to bind to when listening for connections over the network. You must also provide port if you provide host.'), - ('port', 'The port to bind to.'), - ('multiplex', 'Option to multiplex connections (default: false).'), + Option('--socket', + metavar="FILENAME", + help='The filename of a socket to listen to for connections. Default is fcgi_sock in the current directory.'), + Option('--host', + metavar="HOST", + help='The host to bind to when listening for connections over the network. You must also provide port if you provide host.'), + Option('--port', + metavar="PORT", + help='The port to bind to.'), + Option('--multiplex', + metavar="true/false", + help='Option to multiplex connections (default: false).'), ] description = """\ diff --git a/paste/servers/scgi_server/__init__.py b/paste/servers/scgi_server/__init__.py index a621f07..9f56609 100644 --- a/paste/servers/scgi_server/__init__.py +++ b/paste/servers/scgi_server/__init__.py @@ -1,3 +1,4 @@ +from optparse import Option from paste.util import thirdparty thirdparty.add_package('scgi') from scgiserver import serve_application @@ -7,8 +8,12 @@ def serve(conf, app): serve_application(app, prefix, port=int(conf.get('port', 4000))) options = [ - ('port', 'Port to serve on (default 4000).'), - ('root_url', 'The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), + Option('--port', + metavar="PORT", + help='Port to serve on (default 4000).'), + Option('--root-url', + metavar="URL", + help='The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), ] description = """\ diff --git a/paste/servers/scgi_threaded_server.py b/paste/servers/scgi_threaded_server.py index 1f22009..9c1f10b 100644 --- a/paste/servers/scgi_threaded_server.py +++ b/paste/servers/scgi_threaded_server.py @@ -1,6 +1,7 @@ from paste.util import thirdparty thirdparty.add_package('flup') from paste import pyconfig +from optparse import Option def serve(conf, app): from flup.server.scgi import WSGIServer @@ -17,10 +18,18 @@ def serve_server(conf, app, server_class): return server.run() options = [ - ('host', 'The host name to bind to (default localhost). Note, if binding to localhost, only local connections will be allowed.'), - ('port', 'The port to bind to (default 4000).'), - ('root_url', 'The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), - ('allowed_servers', 'A list of servers to allow connections from.'), + Option('--host', + metavar='HOST', + help='The host name to bind to (default localhost). Note, if binding to localhost, only local connections will be allowed.'), + Option('--port', + metavar="PORT", + help='The port to bind to (default 4000).'), + Option('--root-url', + metavar="URL", + help='The URL level to expect for incoming connections; if not set and this is not bound to /, then SCRIPT_NAME and PATH_INFO may be incorrect.'), + Option('--allowed-servers', + metavar="URL_LIST", + help='A list of servers to allow connections from.'), ] description = """\ diff --git a/paste/servers/wsgiutils_server.py b/paste/servers/wsgiutils_server.py index 137e41b..ce501f4 100644 --- a/paste/servers/wsgiutils_server.py +++ b/paste/servers/wsgiutils_server.py @@ -1,3 +1,4 @@ +from optparse import Option from paste.util import thirdparty thirdparty.add_package('wsgiutils') from wsgiutils import wsgiServer @@ -14,6 +15,10 @@ threaded server using Python's standard SimpleHTTPServer. """ options = [ - ('port', 'Port to serve on (default: 8080)'), - ('host', 'Host to serve from (default: localhost, which is only accessible from the local computer; use 0.0.0.0 to make your application public)'), + Option('--port', + metavar="PORT", + help='Port to serve on (default: 8080)'), + Option('--host', + metavar="HOST", + help='Host to serve from (default: localhost, which is only accessible from the local computer; use 0.0.0.0 to make your application public)'), ] diff --git a/paste/util/plugin.py b/paste/util/plugin.py index b1863cd..a1a9e75 100644 --- a/paste/util/plugin.py +++ b/paste/util/plugin.py @@ -50,7 +50,12 @@ def load_plugin_module(dir, dir_package, name, name_extension=''): module_name = parse_txt_plugin(os.path.join(dir, txt_name)) else: module_name = dir_package + '.' + name + name_extension - module = import_string.import_module(module_name) + try: + module = import_string.import_module(module_name) + except ImportError, e: + raise PluginNotFound( + "Plugin %s not found (could not be imported: %s)" + % (name, e)) module.plugin_name = name return module |
