summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Brewer <fumanchu@aminus.org>2008-03-18 17:47:35 +0000
committerRobert Brewer <fumanchu@aminus.org>2008-03-18 17:47:35 +0000
commit573102df129892f925b349ebf24ec580c2527547 (patch)
tree70e5ee5f7900df15a6c8a4b83375b1fd574a4c3f
parent8f61db36c144df4eb3765676e14866f621f8f08d (diff)
downloadcherrypy-573102df129892f925b349ebf24ec580c2527547.tar.gz
Working cherryd daemon script. New FlupFCGIServer wrapper in servers.py. Also added a config arg to cherrypy.Application.
-rw-r--r--cherrypy/_cpconfig.py4
-rw-r--r--cherrypy/_cptree.py4
-rw-r--r--cherrypy/cherryd66
-rw-r--r--cherrypy/cherryd.py87
-rw-r--r--cherrypy/process/restctl.sh71
-rw-r--r--cherrypy/process/restd.py69
-rw-r--r--cherrypy/process/servers.py32
-rw-r--r--cherrypy/scaffold/__init__.py2
-rw-r--r--cherrypy/scaffold/cpdeploy.py49
-rw-r--r--cherrypy/scaffold/example.conf8
-rw-r--r--cherrypy/scaffold/site.conf8
11 files changed, 113 insertions, 287 deletions
diff --git a/cherrypy/_cpconfig.py b/cherrypy/_cpconfig.py
index fcc74334..aeaec512 100644
--- a/cherrypy/_cpconfig.py
+++ b/cherrypy/_cpconfig.py
@@ -65,6 +65,8 @@ Current namespaces:
engine: Controls the 'application engine', including autoreload.
These can only be declared in the global config.
+ tree: Grafts cherrypy.Application objects onto cherrypy.tree.
+ These can only be declared in the global config.
hooks: Declares additional request-processing functions.
log: Configures the logging for each application.
These can only be declared in the global or / config.
@@ -314,7 +316,7 @@ Config.namespaces["engine"] = _engine_namespace_handler
def _tree_namespace_handler(k, v):
"""Namespace handler for the 'tree' config namespace."""
cherrypy.tree.graft(v, v.script_name)
- cherrypy.engine.log("Mounted: %s on %s" % (v, v.script_name))
+ cherrypy.engine.log("Mounted: %s on %s" % (v, v.script_name or "/"))
Config.namespaces["tree"] = _tree_namespace_handler
diff --git a/cherrypy/_cptree.py b/cherrypy/_cptree.py
index f074c0e6..a58a5267 100644
--- a/cherrypy/_cptree.py
+++ b/cherrypy/_cptree.py
@@ -45,7 +45,7 @@ class Application(object):
relative_urls = False
- def __init__(self, root, script_name=""):
+ def __init__(self, root, script_name="", config=None):
self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root)
self.root = root
self.script_name = script_name
@@ -56,6 +56,8 @@ class Application(object):
self.namespaces["wsgi"] = self.wsgiapp.namespace_handler
self.config = self.__class__.config.copy()
+ if config:
+ self.merge(config)
def __repr__(self):
return "%s.%s(%r, %r)" % (self.__module__, self.__class__.__name__,
diff --git a/cherrypy/cherryd b/cherrypy/cherryd
new file mode 100644
index 00000000..9d6402b0
--- /dev/null
+++ b/cherrypy/cherryd
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+"""The CherryPy daemon."""
+
+import cherrypy
+from cherrypy.process import plugins, servers
+
+
+def start(configfile=None, daemonize=False, environment=None,
+ fastcgi=False, pidfile=None):
+ """Subscribe all engine plugins and start the engine."""
+ if configfile:
+ cherrypy.config.update(configfile)
+
+ engine = cherrypy.engine
+
+ if environment is not None:
+ cherrypy.config.update({'environment': environment})
+
+ # Only daemonize if asked to.
+ if daemonize:
+ # Don't print anything to stdout/sterr.
+ cherrypy.config.update({'log.screen': False})
+ plugins.Daemonizer(engine).subscribe()
+
+ if pidfile:
+ plugins.PIDFile(engine, pidfile).subscribe()
+
+ cherrypy.signal_handler.subscribe()
+
+ if fastcgi:
+ # turn off autoreload when using fastcgi
+ cherrypy.config.update({'autoreload.on': False})
+
+ cherrypy.server.unsubscribe()
+
+ fastcgi_port = cherrypy.config.get('server.socket_port', 4000)
+ fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0')
+ bindAddress = (fastcgi_bindaddr, fastcgi_port)
+ f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress)
+ s = servers.ServerAdapter(engine, httpserver=f, bind_addr=bindAddress)
+ s.subscribe()
+
+ # Always start the engine; this will start all other services
+ engine.start()
+ engine.block()
+
+
+if __name__ == '__main__':
+ from optparse import OptionParser
+
+ p = OptionParser()
+ p.add_option('-c', '--config', dest='config',
+ help="specify a config file")
+ p.add_option('-d', action="store_true", dest='daemonize',
+ help="run the server as a daemon")
+ p.add_option('-e', '--environment', dest='environment', default=None,
+ help="apply the given config environment")
+ p.add_option('-f', action="store_true", dest='fastcgi',
+ help="start a fastcgi server instead of the default HTTP server")
+ p.add_option('-p', '--pidfile', dest='pidfile', default=None,
+ help="store the process id in the given file")
+ options, args = p.parse_args()
+
+ start(options.config, options.daemonize,
+ options.environment, options.fastcgi, options.pidfile)
+
diff --git a/cherrypy/cherryd.py b/cherrypy/cherryd.py
deleted file mode 100644
index 011fa353..00000000
--- a/cherrypy/cherryd.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#! /usr/bin/env python
-"""The CherryPy daemon."""
-
-import getopt
-import sys
-
-import cherrypy
-from cherrypy.process import plugins
-
-
-shortopts = ["d", "e"]
-longopts = []
-
-# Help for restd command-line options.
-help = """
-cherryd. Start the cherrypy daemon.
-
-Usage:
- cherryd <config filename>
-
-"""
-
-
-def start(options, configfile, *args):
- engine = cherrypy.engine
-
- siteconf = {}
- cherrypy._cpconfig.merge(siteconf, configfile)
-
- cherrypy.config.update(configfile)
-
- if options.has_key('-e'):
- cherrypy.config.update({'environment': options['-e']})
-
- # TODO: Make sure that log files are configurable from the conf file.
-
- # Only daemonize if asked to.
- if options.has_key('-d'):
- # Don't print anything to stdout/sterr.
- cherrypy.config.update({'log.screen': False})
- plugins.Daemonizer(engine).subscribe()
-
- if options.has_key('--pidfile'):
- plugins.PIDFile(engine, options['--pidfile']).subscribe()
-
- cherrypy.signal_handler.subscribe()
-
- # TODO: call a 'site setup' function (probably passing it siteconf).
-
- if options.has_key('--fastcgi'):
- # turn off autoreload when using fastcgi
- cherrypy.config.update({'autoreload.on': False})
-
- cherrypy.server.unsubscribe()
-
- fastcgi_port = cherrypy.config.get('server.socket_port', 4000)
- fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0')
- bindAddress = (fastcgi_bindaddr, fastcgi_port)
- try:
- # Always start the engine; this will start all other services
- engine.start()
-
- from flup.server.fcgi import WSGIServer
- engine.log('Serving FastCGI on %s:%d' % bindAddress)
- engine.fcgi = WSGIServer(application=wsgiapp,
- bindAddress=bindAddress)
- engine.fcgi.run()
- engine.log('FastCGI Server on %s:%d shut down' % bindAddress)
- finally:
- engine.stop()
- else:
- # Always start the engine; this will start all other services
- s = cherrypy.server
- s.httpserver, s.bind_addr = s.httpserver_from_self()
- s.httpserver.wsgi_app = wsgiapp
- engine.start()
- engine.block()
-
-
-if __name__ == '__main__':
- try:
- opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
- except getopt.GetoptError:
- print help
- sys.exit(2)
-
- start(dict(opts), *tuple(args))
diff --git a/cherrypy/process/restctl.sh b/cherrypy/process/restctl.sh
deleted file mode 100644
index cbdf8a6c..00000000
--- a/cherrypy/process/restctl.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/sh
-#
-# Control script for the restsrv daemon
-
-ERROR=0
-PYTHON=python
-RESTD=restd.py
-PIDFILE=/var/log/restsrv/restd.pid
-
-# Determine if restsrv is already running.
-RUNNING=0
-if [ -f $PIDFILE ]; then
- PID=`cat $PIDFILE`
- if [ "x$PID" != "x" ]; then
- if kill -0 $PID 2>/dev/null ; then
- # a process using PID is running
- if ps -p $PID -o args | grep restsrv > /dev/null 2>&1; then
- # that process is restsrv itself
- RUNNING=1
- fi
- fi
- fi
- if ["$RUNNING" = "0"]; then
- STATUS="restsrv (stale pid file removed) not running"
- rm -f $PIDFILE
- fi
-else
- STATUS="restsrv (no pid) not running"
-fi
-
-ARGS=""
-COMMAND=""
-for ARG in $@; do
- case $ARG in
- start|stop|restart|graceful|status)
- COMMAND=$ARG
- ;;
- *)
- ARGS="$ARGS $ARG"
- esac
- fi
-done
-
-case $COMMAND in
-start)
- echo "Starting restd"
- $RESTD $ARGS
- ERROR=$?
- ;;
-stop)
- echo "Stopping restd"
- kill -TERM `cat $PIDFILE`
- ERROR=$?
- ;;
-restart)
- echo "Restarting restd"
- kill -HUP `cat $PIDFILE`
- ;;
-graceful)
- echo "Gracefully restarting restd"
- kill -USR1 `cat $PIDFILE`
- ;;
-status)
- echo $STATUS
- ;;
-*)
- $RESTD $ARGS
- ERROR=$?
-esac
-
-exit $ERROR \ No newline at end of file
diff --git a/cherrypy/process/restd.py b/cherrypy/process/restd.py
deleted file mode 100644
index b1f3ac79..00000000
--- a/cherrypy/process/restd.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""The restsrv daemon."""
-
-import getopt
-import sys
-
-from cherrypy import restsrv
-
-
-class _Optionset(object):
- host = '0.0.0.0'
- port = 80
- protocol = 'HTTP/1.1'
- scheme = 'http'
-options = _Optionset()
-
-shortopts = []
-longopts = [
- # someday: 'cover', 'profile', 'validate', 'conquer',
- 'host=', 'port=', '1.0', 'ssl',
- 'project=', 'help',
- ]
-
-
-def help():
- """Print help for restd command-line options."""
-
- print """
-restd. Start the restsrv daemon.
-
-Usage:
- restd [options]
-
-Options:
- --host=<name or IP addr>: use a host other than the default (%s).
- --port=<int>: use a port other than the default (%s)
- --1.0: use HTTP/1.0 servers instead of default HTTP/1.1
- --ssl: use HTTPS instead of default HTTP
- --project=<module name>: import a module to set up the project
- --help: print this usage message and exit
-""" % (options.host, options.port)
-
-
-def start(opts):
- if '--project' in opts:
- # delay import until after daemonize has a chance to run
- def _import():
- __import__(opts['--project'], {}, {}, [''])
- _import.priority = 20
- restsrv.bus.subscribe('start', _import)
-
- if 'win' not in sys.platform:
- restsrv.bus.subscribe('start', restsrv.plugins.daemonize)
-
- restsrv.bus.start()
- restsrv.bus.block()
-
-
-if __name__ == '__main__':
- try:
- opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
- except getopt.GetoptError:
- help()
- sys.exit(2)
-
- if "--help" in opts:
- help()
- sys.exit(0)
-
- start(dict(opts))
diff --git a/cherrypy/process/servers.py b/cherrypy/process/servers.py
index 8405b529..0181d83c 100644
--- a/cherrypy/process/servers.py
+++ b/cherrypy/process/servers.py
@@ -121,6 +121,38 @@ class ServerAdapter(object):
self.start()
+class FlupFCGIServer(object):
+ """Adapter for a flup.server.fcgi.WSGIServer."""
+
+ def __init__(self, *args, **kwargs):
+ from flup.server.fcgi import WSGIServer
+ self.fcgiserver = WSGIServer(*args, **kwargs)
+ # TODO: report this bug upstream to flup.
+ # If we don't set _oldSIGs on Windows, we get:
+ # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
+ # line 108, in run
+ # self._restoreSignalHandlers()
+ # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
+ # line 156, in _restoreSignalHandlers
+ # for signum,handler in self._oldSIGs:
+ # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs'
+ self.fcgiserver._oldSIGs = []
+ self.ready = False
+
+ def start(self):
+ """Start the FCGI server."""
+ self.ready = True
+ self.fcgiserver.run()
+
+ def stop(self):
+ """Stop the HTTP server."""
+ self.ready = False
+ # Forcibly stop the fcgi server main event loop.
+ self.fcgiserver._keepGoing = False
+ # Force all worker threads to die off.
+ self.fcgiserver._threadPool.maxSpare = 0
+
+
def client_host(server_host):
"""Return the host on which a client can connect to the given listener."""
if server_host == '0.0.0.0':
diff --git a/cherrypy/scaffold/__init__.py b/cherrypy/scaffold/__init__.py
index cc5f1df8..026267ae 100644
--- a/cherrypy/scaffold/__init__.py
+++ b/cherrypy/scaffold/__init__.py
@@ -8,7 +8,7 @@ then tweak as desired.
Even before any tweaking, this should serve a few demonstration pages.
Change to this directory and run:
- python cpdeploy.py --config=example.conf
+ python cherrypy\cherryd cherrypy\scaffold\site.conf
"""
diff --git a/cherrypy/scaffold/cpdeploy.py b/cherrypy/scaffold/cpdeploy.py
deleted file mode 100644
index 1fc9378a..00000000
--- a/cherrypy/scaffold/cpdeploy.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#! /usr/bin/env python
-"""Deployment script for <MyProject> (a CherryPy application).
-
-Run this from the command-line and give it a --config argument:
-
- python cpdeploy.py --config=example.conf
-
-"""
-
-import os
-local_dir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-import cherrypy
-from cherrypy.process.plugins import Daemonizer, PIDFile
-
-# TODO: Change this to import your project root.
-from cherrypy import scaffold
-
-
-if __name__ == "__main__":
- from optparse import OptionParser
-
- p = OptionParser()
- p.add_option('-c', '--config', dest='config_file',
- help="specify a config file")
- p.add_option('-D', '--daemonize', action="store_true", dest='daemonize',
- help="run the server as a daemon")
- options, args = p.parse_args()
- cherrypy.config.update(options.config_file)
-
- # Only daemonize if asked to.
- if options.daemonize:
- # Don't print anything to stdout/sterr.
- cherrypy.config.update({'log.screen': False})
-
- d = Daemonizer(cherrypy.engine)
- d.subscribe()
-
- pidfile = cherrypy.config.get('pidfile')
- if pidfile:
- PIDFile(cherrypy.engine, pidfile).subscribe()
-
- # You can replace the next 4 lines with:
- # cherrypy.quickstart(scaffold.root, "/", options.config_file)
- cherrypy.signal_handler.subscribe()
- cherrypy.tree.mount(scaffold.root, "/", options.config_file)
- cherrypy.engine.start()
- cherrypy.engine.block()
-
diff --git a/cherrypy/scaffold/example.conf b/cherrypy/scaffold/example.conf
index ca3dc112..93a6e53c 100644
--- a/cherrypy/scaffold/example.conf
+++ b/cherrypy/scaffold/example.conf
@@ -1,11 +1,3 @@
-[global]
-# Uncomment this when you're done developing
-#environment: "production"
-
-server.socket_host: "0.0.0.0"
-server.socket_port: 8088
-
-
[/]
log.error_file: "error.log"
log.access_file: "access.log" \ No newline at end of file
diff --git a/cherrypy/scaffold/site.conf b/cherrypy/scaffold/site.conf
new file mode 100644
index 00000000..6fc8f4ec
--- /dev/null
+++ b/cherrypy/scaffold/site.conf
@@ -0,0 +1,8 @@
+[global]
+# Uncomment this when you're done developing
+#environment: "production"
+
+server.socket_host: "0.0.0.0"
+server.socket_port: 8088
+
+tree.myapp: cherrypy.Application(scaffold.root, "/", "cherrypy/scaffold/example.conf")