[Zope-Checkins] CVS: Zope2 - zctl_lib.py:1.1.2.1

evan@serenade.digicool.com evan@serenade.digicool.com
Thu, 19 Apr 2001 16:45:50 -0400


Update of /cvs-repository/Zope2/utilities
In directory serenade.digicool.com:/home/evan/Zope/trunk/utilities

Added Files:
      Tag: evan-makefile-branch
	zctl_lib.py 
Log Message:
Allow directories to opt out of module compilation with a .no_pycompile file.



--- Added File zctl_lib.py in package Zope2 ---
def zctl_usage(args):
    print """Control Zope, and ZEO server if it's configured

Usage:

    zctl.py start [--zeo -arg ... [--zope]] -arg ...

      Start Zope, checking that ZEO is up and starting it, if necessary.

    zctl.py stop

      Stop Zope.  Does not stop ZEO.

    zctl.py debug

      Open an interactive Python session with Zope loaded.

    zctl.py test filename

    zctl.py script filename

      Load Zope environment, then execute file as a Python program.

    zctl.py do [-i] [-f filename]* commands

      Execute Python commands and zero or more files.

    zctl.py stop_all

      Stop Zope, and run ZEO stop script if possible.

    zctl.py start_zeo

      Run ZEO start script if possible.

    zctl.py stop_zeo

      Run ZEO stop script if possible.

    zctl.py status

      Show the status of Zope, and possibly ZEO.

    zctl.py make_cgi [filename]

      Write a Zope.cgi file for use with PCGI.

    zctl.py usage | --help

      Print this information.

'zctl.py' contains configuration information for Zope, and optionally
for connecting to ZEO, for a single Zope instance.  The directory
containing the file 'zctl.py' is the INSTANCE_HOME.  More than one
INSTANCE_HOME can be set up to use the same copy of the Zope software,
and each one can have its own Zope database(s), Products, and
Extensions.

If an instance uses a ZEO server, then you can run a 'zctl.py debug'
session without stopping the Zope instance.
"""

import sys, os, socket, time, string
from os.path import isfile, isdir, abspath
pjoin = os.path.join
psplit = os.path.split
env = os.environ
run = os.system

# Find out where we are, and where Python is.
if not sys.argv[0]: HERE = os.curdir()
else: HERE = psplit(sys.argv[0])[0]
HERE = abspath(HERE)
ZOPE_HOME = abspath(ZOPE_HOME)
CLIENT_HOME = pjoin(HERE, 'var')

PYTHON = '"%s"' % sys.executable
ZOPE = {}
ZOPE_ENV = {}
ZEO = {} # ZEO is off by default

# Define 'constants'
OPTS, PORT, LOG, WAIT, SOCKET, CONTROL = (
  'OPTS', 'PORT', 'LOG', 'WAIT', 'SOCKET', 'CONTROL')

# Commands

def zctl_start(args):
    """Start Zope when ZEO is reachable, starting ZEO first if necessary."""
    pidf = pjoin(CLIENT_HOME, 'Z2.pid')
    running = _check_pids(pidf)
    if running:
        for pid, up in running.items():
            if up:
                print 'There appears to be a Zope instance already running.'
                print 'Either stop it, or delete "%s".' % pidf
                return

    zeo_args = []
    zope_args = []

    app = zope_args.append
    while args:
        arg = args.pop(0)
        if arg[:2] == '--':
            argmap = {'zeo': zeo_args, 'zope': zope_args}.get(arg[2:])
            if argmap is None:
                app(arg)
            else:
                app = argmap.append
        else:
            app(arg)

    cmd = '%s "%s/z2.py" %%s' % (PYTHON, ZOPE_HOME)
    args = list(zope_args)
    if ZOPE.get(OPTS):
        args.insert(0, ZOPE[OPTS])
    if ZOPE.get(PORT):
        args.insert(0, '-P %s' % ZOPE[PORT])
    if ZOPE.get(LOG):
        args.append('"STUPID_LOG_FILE=%s"' % ZOPE[LOG])
    for k,v in ZOPE_ENV.items():
        env[k] = str(v)
    env['INSTANCE_HOME'] = HERE
    if ZEO:
        zctl_start_zeo(zeo_args)
        env['ZEO_SOCKET'] = ZEO[SOCKET]
    cmd = cmd % string.join(args)
    print 'Starting Zope, using:'
    print cmd
    run(cmd)
        
def zctl_start_zeo(args):
    """Try to start ZEO."""
    zeosocket = ZEO.get(SOCKET)
    if zeosocket is None:
        print 'Error: ZEO[SOCKET] is not defined.'
        return
    elif ':' in zeosocket:
        zeosocket = tuple(string.split(zeosocket, ':'))
        host, port = zeosocket

    if ZEO.get(CONTROL) and not _check_for_service(zeosocket):
        run(ZEO[CONTROL] + ' start ' + ZEO.get(OPTS, ''))

    count = 0
    ZEO_WAIT_BAILOUT = ZEO.get(WAIT, 60)
    while not _check_for_service(zeosocket):
        count = count + 1
        if count > ZEO_WAIT_BAILOUT:
            print ("ZEO connect failure, on %s after %d seconds"
                   % (zeosocket, ZEO_WAIT_BAILOUT))
            sys.exit(1)
        print "waiting for ZEO server to start %d/%d" % (count,
                                                         ZEO_WAIT_BAILOUT)
        time.sleep(1)

    if host == 'localhost' and not _check_for_service(host, port):
        print "Starting ZEO server on", port
        cmd = '%s %s/lib/python/ZEO/start.py -p %s %s &' % (
            PYTHON, ZOPE_HOME, port, string.join(args)
            )
        run(cmd)

def zctl_stop_zeo(args):
    """Stop the ZEO server."""
    if not ZEO.get(CONTROL):
        print 'Error: ZEO[CONTROL] is not defined.'
        return
    run(ZEO[CONTROL] + ' stop')

def zctl_stop(args):
    """Stop client."""
    pidf = pjoin(CLIENT_HOME, 'Z2.pid')
    if not isfile(pidf):
        print '"%s" was not found' % pidf
        return
    for pid in string.split(open(pidf).read()):
        print 'Stopping Zope process %s' % pid
        os.kill(int(pid), 15)

def zctl_stop_all(args):
    "Stop client and ZEO server"
    zctl_stop(args)
    zctl_stop_zeo(args)

def zctl_status(args):
    """Print status."""
    pidf = pjoin(CLIENT_HOME, 'Z2.pid')
    running = _check_pids(pidf)
    if running is None:
        print 'No Zope process found.'
        return

    for pid, up in running.items():
        if up is None:
            print '%s is in pid file.' % pid
        elif up:
            print '%s is running.' % pid
        else:
            print '%s is in pid file, but not running.' % pid

def zctl_make_cgi(args):
    """Create a PCGI parameter file."""
    if args:
        fname = args.pop(0)
    else:
        fname = 'Zope.cgi'
    write = open(fname, 'w').write
    write('''\
#!%(ZOPE_HOME)s/pcgi/pcgi-wrapper
PCGI_NAME=Zope
PCGI_MODULE_PATH=%(ZOPE_HOME)s/lib/python/Zope
PCGI_PUBLISHER=%(ZOPE_HOME)s/pcgi/pcgi_publisher.py
PCGI_EXE=%(PYTHON)s
PCGI_SOCKET_FILE=%(CLIENT_HOME)s/pcgi.soc
PCGI_PID_FILE=%(CLIENT_HOME)s/pcgi.pid
PCGI_ERROR_LOG=%(CLIENT_HOME)s/pcgi.log
PCGI_DISPLAY_ERRORS=1
BOBO_REALM=Zope
BOBO_DEBUG_MODE=1
INSTANCE_HOME=%(HERE)s
''' % globals())
    
def zctl_do(args):
    """Execute python commands"""
    if ZEO:
        start_zeo([])
    for k,v in ZOPE_ENV.items():
        env[k] = str(v)
    env['INSTANCE_HOME'] = HERE
    cwd = os.getcwd()
    os.chdir(pjoin(ZOPE_HOME, 'lib', 'python'))
    msg = """
          Zope debugging session for %s
          The root application object is bound to name 'app'.
          To let other people see your changes, you must:
            get_transaction().commit()
          To see other people's changes, you must:
            app._p_jar.sync()""" % HERE
    options = "-c"
    if not args or '-i' in args:
        options = '-i ' + options
        if args:
            args.remove('-i')
        print msg
    while '-f' in args:
        fpos = args.index('-f')
        args.pop(fpos)
        args[fpos] = 'execfile("%s");' % args[fpos]
    imports = 'import Zope'
    if not (os.path.samefile(cwd, os.getcwd()) or
            os.path.samefile(cwd, HERE)):
        imports = '%s; import sys; sys.path.append("%s")' % (
            imports, cwd)
    cmd = ("%s %s '%s; app=Zope.app(); %s'"
           % (PYTHON, options, imports, string.join(args, " ")))
    run(cmd)

def zctl_debug(args):
    """Start an interactive debugging session"""
    args.insert(0, '-i')
    zctl_do(args)

def zctl_script(args):
    """Execute a Python script"""
    args[0] = os.path.abspath(args[0])
    args.insert(0, '-f')
    zctl_do(args)

def zctl_test(args):
    """Run a test"""
    zctl_script(args)

# Internal helper functions

def _check_pids(pidfile):
    """Return dictionary of pids, or None if pidfile not found.

    The value for each pid indicates whether the process is running.
    """
    if isfile(pidfile):
        pids = string.split(open(pidfile, 'r').read())
    else:
        return
    running = {}
    if isdir('/proc'):
        for pid in pids:
            running[pid] = isdir('/proc/%s' % pid)
    else:
        for pid in pids:
            running[pid] = None
    return running

def _check_for_service(ssock):
    """Return 1 if server is found, 0 otherwise."""
    try:
        if type(ssock) is type(()):
            stype = socket.AF_INET
        else:
            stype = socket.AF_UNIX
        s = socket.socket(stype, socket.SOCK_STREAM)
        s.connect(ssock)
        return 1
    except socket.error:
        return 0

def main():
    """Dispatch command line invocation."""
    if len(sys.argv) == 1:
        print """\
    start [--zeo -arg ... [--zope]] -arg ...
    stop
    stop_all
    start_zeo
    stop_zeo
    status
    make_cgi [filename]
    debug
    test filename
    do [-i] [-f filename]* commands
    script filename
    usage
"""
        args = string.split(raw_input('command: '))
    else:
        args = sys.argv[1:]
    action = string.lower(args.pop(0))
    if action == '--help':
        action = 'usage'
    if not globals().has_key('zctl_'+action):
        print 'Unknown command "%s"' % action
        sys.exit(1)
    for k, v in ZEO.items():
        env['ZEO_'+k] = str(v)
    globals()['zctl_'+action](args)