"Things to do when TurboGears is imported."

import pkg_resources
import os
import logging
import sys

pkg_resources.require("TurboGears")

import cherrypy

def reloader_thread():
    """Monkeypatch for the reloader provided by CherryPy.
    
    This reloader is designed to reload a single package. This is
    more efficient and, more important, compatible with zipped
    libraries that may not provide access to the individual files."""
    import sys
    import time
    mtimes = {}
    package = cherrypy.config.get("autoreload.package")
    while cherrypy.lib.autoreload.RUN_RELOADER:
        if package:
            modnames = filter(lambda modname: modname.startswith(package), sys.modules.keys())
            modlist = [sys.modules[modname] for modname in modnames]
        else:
            modlist = sys.modules.values()
        for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), modlist)):
            if filename.endswith(".pyc"):
                filename = filename[:-1]
            try:
                mtime = os.stat(filename).st_mtime
            except OSError:
                sys.exit(3) # force reload
            if filename not in mtimes:
                mtimes[filename] = mtime
                continue
            if mtime > mtimes[filename]:
                sys.exit(3) # force reload
        time.sleep(1)

cherrypy.lib.autoreload.reloader_thread = reloader_thread

webpath = ""

DNS_SD = '/usr/bin/dns-sd'
DNS_SD_PID = None

def start_bonjour():
    global DNS_SD_PID
    if DNS_SD_PID:
        return
    if os.path.exists(DNS_SD):
        # bonjour advertise
        if not hasattr(cherrypy, "root") or not cherrypy.root:
            return
        package = cherrypy.root.__module__
        package = package[:package.find(".")]
        args = [
            DNS_SD,
            '-R',
            package + ": " + cherrypy.config.get('server.environment'),
            "_http._tcp",
            cherrypy.config.get('server.socketHost') or '.',
            str(cherrypy.config.get('server.socketPort')),
            "path=/"
        ]
        # it might be nice to use subprocess and redirect IO to /dev/null
        DNS_SD_PID = os.spawnv(os.P_NOWAIT, args[0], args)
        import atexit
        atexit.register(stop_bonjour)

def stop_bonjour():
    if not DNS_SD_PID:
        return
    import signal
    try:
        os.kill(DNS_SD_PID, signal.SIGTERM)
    except OSError:
        pass

def startTurboGears():
    """Handles TurboGears tasks when the CherryPy server starts.
    
    This adds the "tg_js" configuration to make MochiKit accessible.
    It also turns on stdlib logging when in development mode.
    """
    cherrypy.config.update({"/tg_js" : 
            {
            "staticFilter.on" : True, 
            "staticFilter.dir" : 
                os.path.abspath(pkg_resources.resource_filename(__name__, "js")),
            'logDebugInfoFilter.on' : False,
            }
        })
    global webpath
    webpath = cherrypy.config.get("server.webpath", "")
    if webpath.startswith("/"):
        webpath = webpath[1:]
    if webpath and not webpath.endswith("/"):
        webpath = webpath + "/"
    if cherrypy.config.get('server.environment') == 'development':
        log = logging.getLogger()
        log.setLevel(logging.DEBUG)
        fmt = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
        handler = logging.StreamHandler(sys.stdout)
        handler.setLevel(logging.DEBUG)
        handler.setFormatter(fmt)
        log.addHandler(handler)
        
        start_bonjour()
        
def stopTurboGears():
    stop_bonjour()
        
def getObjFromPath(objPathList):
    """For a given objectPathList, return the object (or None) and set
    the application root in the request in the process.

    objPathList should be a list of the form: ['root', 'a', 'b', 'index'].
    """
    from turbogears.controllers import Root
    wp = webpath
    
    root = cherrypy
    cherrypy.request.approot = "/" + wp
    for i in range(0, len(objPathList)):
        # maps virtual filenames to Python identifiers (substitutes '.' for '_')
        objname = objPathList[i].replace('.', '_')
        if getattr(cherrypy, "debug", None):
            cherrypy.log("    Trying: %s.%s" % (root, objname), "DEBUG")
        root = getattr(root, objname, None)
        if isinstance(root, Root):
            cherrypy.request.approot = "/" + wp + "/".join(objPathList[1:i+1])
        if root is None:
            return None
    return root

def check_port(host, port):
    """Raise an error if the given port is not free on the given host."""
    if not host:
        host = 'localhost'

    import socket
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(1)
        s.connect((host, int(port)))
        s.close()
        raise IOError("Port %s is in use on %s; perhaps the previous "
                      "server did not shut down properly." %
                      (repr(port), repr(host)))
    except socket.error:
        pass

# This monkeypatch should be replaced by an extension mechanism 
# within CherryPy
cherrypy._cphttptools.getObjFromPath = getObjFromPath

# This monkeypatch should be replaced by a timeout directly 
# set in the CherryPy code.
cherrypy._cpserver.check_port = check_port

if startTurboGears not in cherrypy.server.onStartServerList:
    cherrypy.server.onStartServerList.append(startTurboGears)
    
if stopTurboGears not in cherrypy.server.onStopServerList:
    cherrypy.server.onStopServerList.append(stopTurboGears)