Commits

Robert Brewer  committed d7a1ce5

Working cherryd daemon script. New FlupFCGIServer wrapper in servers.py. Also added a config arg to cherrypy.Application.

  • Participants
  • Parent commits af30811

Comments (0)

Files changed (11)

File cherrypy/_cpconfig.py

 
     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.
 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
 
 

File cherrypy/_cptree.py

     
     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
         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__,

File cherrypy/cherryd

+#! /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)
+

File cherrypy/cherryd.py

-#! /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))

File cherrypy/process/restctl.sh

-#!/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

File cherrypy/process/restd.py

-"""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))

File cherrypy/process/servers.py

         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':

File cherrypy/scaffold/__init__.py

 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
 
 """
 

File cherrypy/scaffold/cpdeploy.py

-#! /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()
-

File cherrypy/scaffold/example.conf

-[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"

File cherrypy/scaffold/site.conf

+[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")