summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorianb <devnull@localhost>2005-05-18 07:37:44 +0000
committerianb <devnull@localhost>2005-05-18 07:37:44 +0000
commit0f2e939f36746f130b1bd67a1797b58688d5ac1c (patch)
treeb43210578bae15f5b8786342e97432555625927b
parent430c3392dc166a4f9bec48f70c8bf7b6b140560d (diff)
downloadpaste-0f2e939f36746f130b1bd67a1797b58688d5ac1c.tar.gz
Made app_templates pluggable; added serve command to paste-setup
-rw-r--r--paste/app_setup.py137
-rwxr-xr-xpaste/server.py52
-rw-r--r--paste/servers/ajp_threaded_server.py17
-rw-r--r--paste/servers/console_server.py11
-rw-r--r--paste/servers/fastcgi_threaded_server.py17
-rw-r--r--paste/servers/scgi_server/__init__.py9
-rw-r--r--paste/servers/scgi_threaded_server.py17
-rw-r--r--paste/servers/wsgiutils_server.py9
-rw-r--r--paste/util/plugin.py7
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