"""Launch.py
DESCRIPTION
Python launch script for the WebKit application server.
This launch script will run in its standard location in the Webware/WebKit
directory as well as in a WebKit work directory outside of the Webware tree.
USAGE
Launch.py [StartOptions] [AppServer [AppServerOptions]]
StartOptions:
-d, --work-dir=... Set the path to the app server working directory.
By default this is the directory containing Lauch.py.
-w, --webware-dir=... Set the path to the Webware root directory.
By default this is the parent directory.
-l, --library=... Other directories to be included in the search path.
You may specify this option multiple times.
-p, --run-profile Set this to get profiling going (see Profiler.py).
-o, --log-file=... Redirect standard output and error to this file.
-i, --pid-file=... Set the file path to hold the app server process id.
This option is fully supported under Unix only.
-u, --user=... The name or uid of the user to run the app server.
This option is supported under Unix only.
-g, --group=... The name or gid of the group to run the app server.
This option is supported under Unix only.
AppServer:
The name of the application server module.
By default, the ThreadedAppServer will be used.
AppServerOptions:
Options that shall be passed to the application server.
For instance, the ThreadedAppServer accepts: start, stop, daemon
You can also change configuration settings here by passing
arguments of the form ClassName.SettingName=value
Please note that the default values for the StartOptions and the AppServer
can be easily changed at the top of the Launch.py script.
"""
workDir = None
webwareDir = None
libraryDirs = []
runProfile = 0
logFile = None
pidFile = None
user = None
group = None
appServer = 'ThreadedAppServer'
import os, sys
def usage():
"""Print the docstring and exit with error."""
sys.stdout.write(__doc__)
sys.exit(2)
def launchWebKit(appServer=appServer, workDir=None, args=None):
"""Import and launch the specified WebKit app server.
appServer -- the name of the WebKit app server module
workDir -- the server-side work directory of the app server
args -- other options that will be given to the app server
"""
if args is None:
args = []
if workDir:
args.append('workdir=' + workDir)
if appServer[-3:] == '.py':
appServer = appServer[:-3]
try:
appServerMain = __import__('WebKit.' + appServer, None, None, 'main').main
except ImportError, e:
print 'Error: Cannot import the AppServer module.'
print 'Reason:', str(e)
sys.exit(1)
from WebKit import Profiler
if Profiler.startTime is None:
from time import time
Profiler.startTime = time()
return appServerMain(args)
def main(args=None):
"""Evaluate the command line arguments and call launchWebKit."""
global workDir, webwareDir, libraryDirs, runProfile, \
logFile, pidFile, user, group, appServer
if args is None:
args = sys.argv[1:]
if args and not args[0].startswith('-'):
arg2 = args.pop(0)
else:
arg2 = None
args1 = []
args2 = []
while args:
arg = args.pop(0)
if arg.startswith('--') and \
2 < arg.find('.', 2) < arg.find('=', 5):
args2.append(arg)
else:
args1.append(arg)
from getopt import getopt, GetoptError
try:
opts, args1 = getopt(args1, 'd:w:l:po:i:u:g:', [
'work-dir=', 'webware-dir=', 'library=', 'run-profile',
'log-file=', 'pid-file=', 'user=', 'group='])
except GetoptError, error:
print str(error)
print
usage()
for opt, arg in opts:
if opt in ('-d', '--work-dir'):
workDir = arg
elif opt in ('-w', '--webware-dir'):
webwareDir = arg
elif opt in ('-l', '--library'):
libraryDirs.append(arg)
elif opt in ('-p', '--run-profile'):
runProfile = 1
elif opt in ('-o', '--log-file'):
logFile = arg
elif opt in ('-i', '--pid-file'):
pidFile = arg
elif opt in ('-u', '--user'):
user = arg
elif opt in ('-g', '--group'):
group = arg
if arg2:
appServer = arg2
elif args1 and not args1[0].startswith('-') \
and args1[0].find('=') < 0:
appServer = args1.pop(0)
args = args2 + args1
gid = group
if gid is not None:
try:
gid = int(gid)
except ValueError:
try:
import grp
entry = grp.getgrnam(gid)
except KeyError:
print 'Error: Group %r does not exist.' % gid
sys.exit(2)
except ImportError:
print 'Error: Group names are not supported.'
sys.exit(2)
gid = entry[2]
uid = user
if uid is not None:
try:
uid = int(uid)
except ValueError:
try:
import pwd
entry = pwd.getpwnam(uid)
except KeyError:
print 'Error: User %r does not exist.' % uid
sys.exit(2)
except ImportError:
print 'Error: User names are not supported.'
sys.exit(2)
if not gid:
gid = entry[3]
uid = entry[2]
if workDir:
workDir = os.path.expanduser(workDir)
else:
scriptName = sys.argv and sys.argv[0]
if not scriptName or scriptName == '-c':
scriptName = 'Launch.py'
workDir = os.path.dirname(os.path.abspath(scriptName))
try:
os.chdir(workDir)
except OSError, error:
print 'Error: Could not set working directory.'
print 'The path %r cannot be used.' % workDir
print error.strerror
print 'Check the --work-dir option.'
sys.exit(1)
workDir = os.curdir
if webwareDir:
webwareDir = os.path.expanduser(webwareDir)
else:
webwareDir = os.pardir
if libraryDirs:
libraryDirs = map(os.path.expanduser, libraryDirs)
global __name__, __package__
name = __name__.split('.')[-1]
if name != __name__:
sys.modules[name] = sys.modules[__name__]
del sys.modules[__name__]
__name__ = name
__package__ = None
sysPath = sys.path
sys.path = [webwareDir]
try:
from Properties import name as webwareName
from WebKit.Properties import name as webKitName
except ImportError:
webwareName = None
if webwareName != 'Webware for Python' or webKitName != 'WebKit':
print 'Error: Cannot find the Webware directory.'
print 'The path %r seems to be wrong.' % webwareDir
print 'Check the --webware-dir option.'
sys.exit(1)
if not os.path.exists(os.path.join(webwareDir, 'install.log')):
print 'Error: Webware has not been installed.'
print 'Please run install.py in the Webware directory:'
print '> cd', os.path.abspath(webwareDir)
print '> python install.py'
sys.exit(1)
path = []
webKitDir = os.path.abspath(os.path.join(webwareDir, 'WebKit'))
for p in [workDir, webwareDir] + libraryDirs + sysPath:
if not p:
continue
p = os.path.abspath(p)
if p == webKitDir or p in path or not os.path.exists(p):
continue
path.append(p)
sys.path = path
args = (appServer, workDir, args)
if 'stop' in args[2]:
print 'Stopping WebKit.%s...' % appServer
errorlevel = launchWebKit(*args)
if not errorlevel:
if pidFile and os.path.exists(pidFile):
try:
os.remove(pidFile)
except Exception:
print 'The pid file could not be removed.'
print
sys.exit(errorlevel)
if pidFile:
pidFile = os.path.expanduser(pidFile)
try:
pid = int(open(pidFile).read())
except Exception:
pid = None
if pid is not None:
print 'According to the pid file, the server is still running.'
killed = 0
try:
from signal import SIGTERM, SIGKILL
print 'Trying to terminate the server with pid %d...' % pid
os.kill(pid, SIGTERM)
except OSError, error:
from errno import ESRCH
if error.errno == ESRCH:
print 'The pid file was stale, continuing with startup...'
killed = 1
else:
print 'Cannot terminate server with pid %d.' % pid
print error.strerror
sys.exit(1)
except (ImportError, AttributeError):
print 'Cannot check or terminate server with pid %d.' % pid
sys.exit(1)
if not killed:
from time import sleep
try:
for i in range(100):
sleep(0.1)
os.kill(pid, SIGTERM)
except OSError, error:
from errno import ESRCH
if error.errno == ESRCH:
print 'Server with pid %d has been terminated.' % pid
killed = 1
if not killed:
try:
for i in range(100):
sleep(0.1)
os.kill(pid, SIGKILL)
except OSError, error:
from errno import ESRCH
if error.errno == ESRCH:
print 'Server with pid %d has been killed by force.' % pid
killed = 1
if not killed:
print 'Server with pid %d cannot be terminated.' % pid
sys.exit(1)
try:
open(pidFile, 'w').write(str(os.getpid()))
except Exception:
print 'The pid file %r could not be written.' % pidFile
sys.exit(1)
olduid = oldgid = stdout = stderr = log = None
errorlevel = 1
try:
if gid is not None:
try:
oldgid = os.getgid()
if gid != oldgid:
os.setgid(gid)
if group:
print 'Changed server process group to %r.' % group
else:
oldgid = None
except Exception:
if group:
print 'Could not set server process group to %r.' % group
oldgid = None
sys.exit(1)
if uid is not None:
try:
olduid = os.getuid()
if uid != olduid:
os.setuid(uid)
print 'Changed server process user to %r.' % user
else:
olduid = None
except Exception:
print 'Could not change server process user to %r.' % user
olduid = None
sys.exit(1)
msg = 'WebKit.' + appServer
if args[2]:
msg = '%s %s' % (msg, ' '.join(args[2]))
else:
msg = 'Starting %s...' % msg
print msg
if logFile:
logFile = os.path.expanduser(logFile)
try:
log = open(logFile, 'a', 1)
print 'Output has been redirected to %r...' % logFile
stdout, stderr = sys.stdout, sys.stderr
sys.stdout = sys.stderr = log
except IOError, error:
print 'Cannot redirect output to %r.' % logFile
print error.strerror
log = None
sys.exit(1)
else:
print
from WebKit import Profiler
if Profiler.startTime is None:
from time import time
Profiler.startTime = time()
if runProfile:
print 'Profiling is on.', \
'See docstring in Profiler.py for more info.'
print
from profile import Profile
profiler = Profile()
Profiler.profiler = profiler
errorlevel = Profiler.runCall(launchWebKit, *args)
print
print 'Writing profile stats to %s...' % Profiler.statsFilename
Profiler.dumpStats()
print 'WARNING: Applications run much slower when profiled,'
print 'so turn off profiling in Launch.py when you are finished.'
else:
errorlevel = launchWebKit(*args)
finally:
print
if log:
sys.stdout, sys.stderr = stdout, stderr
log.close()
if oldgid is not None:
try:
os.setgid(oldgid)
except Exception:
pass
else:
oldgid = None
if olduid is not None:
try:
os.setuid(olduid)
except Exception:
pass
else:
olduid = None
if pidFile and os.path.exists(pidFile):
try:
os.remove(pidFile)
except Exception:
if oldgid is None and olduid is None:
print 'The pid file could not be removed.'
print
sys.exit(errorlevel)
if __name__ == '__main__':
main()