Package sparked :: Module launcher
[hide private]
[frames] | no frames]

Source Code for Module sparked.launcher

  1  # Copyright (c) 2010 Arjan Scherpenisse 
  2  # See LICENSE for details. 
  3   
  4  """ 
  5  The Sparked application launcher. 
  6   
  7  Sparked applications are launched in a subprocess: so that if the 
  8  application crashes, it is started again. 
  9  """ 
 10   
 11  import os 
 12  import subprocess 
 13  import sys 
 14  import time 
 15   
 16  from twisted.internet import reactor 
 17  from twisted.python import usage, log 
 18  from twisted.application import service, app 
 19   
 20  from sparked import application, __version__ 
 21   
 22   
23 -class Options(usage.Options):
24 25 longdesc = """The <application> argument specifies a Python module which is executed as the main sparked class. To see which options hold for an application, start: 26 27 # sparkd <application> --help 28 """ 29 30 optFlags = [["debug", "d", "Debug mode"], 31 ["no-subprocess", "N", "Do not start a subprocess for crash prevention"], 32 ] 33 34 optParameters = [ 35 ('id', None, None, 'Application id (defaults to the sparked module name)'), 36 ('pidfile', None, None, 'Pidfile location (defaults to /tmp/<id>/sparkd.pid)'), 37 ('logfile', None, None, 'Pidfile location (defaults to /tmp/<id>/sparkd.log)') 38 ] 39 40
41 - def getSynopsis(self):
42 return "sparkd [options] <application> [app_options]"
43
44 - def opt_version(self):
45 print os.path.basename(sys.argv[0]), __version__ 46 exit(0)
47 48
49 -class QuitFlag:
50 """ 51 @ivar file: A C{FilePath} pointing to the quit-flag file. 52 """
53 - def __init__(self, file):
54 self.file = file
55 56
57 - def set(self):
58 f = self.file.open("w") 59 f.write("quit") 60 f.close()
61 62
63 - def reset(self):
64 try: 65 self.file.remove() 66 except: 67 pass
68 69
70 - def isSet(self):
71 try: 72 return self.file.open("r").readlines()[0] == "quit" 73 except: 74 return False
75 76 77 78
79 -def splitOptions(args):
80 try: 81 app = [a for a in args if a[0] != "-"][0] 82 except IndexError: 83 return args, None, [] 84 i = args.index(app) 85 return (args[0:i], app, args[i+1:])
86 87
88 -def run(appName):
89 application = service.Application(appName) 90 91 from sparked import tap 92 config = tap.Options() 93 config.parseOptions(sys.argv[1:]) 94 svc = tap.makeService(config) 95 svc.setServiceParent(application) 96 97 app.startApplication(application, False) 98 log.addObserver(log.FileLogObserver(sys.stdout).emit) 99 100 reactor.run()
101 102
103 -def launch(baseOptions, env):
104 argv = [] 105 argv.append("twistd") 106 argv.append("--pidfile") 107 argv.append(baseOptions['pidfile']) 108 argv.append('-r') 109 argv.append('gtk2') 110 argv.append('-n') 111 argv.append('sparked') 112 argv = argv + sys.argv[1:] 113 114 return subprocess.call(argv, env=env)
115 116
117 -def launchLoop(app, options, env, appPath):
118 quitFlag = QuitFlag(appPath.child("quitflag")) 119 quitFlag.reset() 120 respawned = False 121 while True: 122 start = time.time() 123 launch(options, env) 124 if time.time() - start < 5: 125 if respawned: 126 print "*** %s: respawning too fast ***" % app 127 break 128 if quitFlag.isSet(): 129 break 130 respawned = True 131 132 quitFlag.reset()
133 134 135
136 -def loadModule(app):
137 args = sys.argv[:] 138 sys.argv = [] 139 if app[-3:] == ".py" and os.path.exists(app): 140 path = os.path.dirname(app) 141 if not path: path = "." 142 sys.path.insert(0, path) 143 app = os.path.basename(app)[:-3] 144 145 try: 146 mod = __import__(app, None, None, app.split(".")[-1]) 147 except ImportError, e: 148 log.err(e) 149 raise usage.UsageError("Application not found: " + app) 150 sys.argv = args 151 return mod, app
152 153
154 -def launchHelp(app):
155 print "This file is a Sparked application, and is meant to run like this:" 156 print 157 print " sparkd " + app 158 print 159 exit(1)
160 161
162 -def main():
163 164 env = os.environ 165 166 try: 167 options = Options() 168 sparkedOpts, appName, appOpts = splitOptions(sys.argv[1:]) 169 options.parseOptions(sparkedOpts) 170 171 if not appName: 172 options.opt_help() 173 174 appModule, appName = loadModule(appName) 175 176 appPath = application.getTempPath(appName, options['id']) 177 178 if hasattr(appModule, 'Options'): 179 opts = appModule.Options() 180 else: 181 opts = application.Options() 182 183 opts.appName = appName 184 if not hasattr(opts, 'longdesc'): 185 opts.longdesc = appModule.__doc__ 186 opts.parseOptions(appOpts) 187 188 if not options['pidfile']: 189 options['pidfile'] = appPath.child("sparkd.pid").path 190 191 192 if options['no-subprocess']: 193 run(appName) 194 else: 195 launchLoop(appName, options, env, appPath) 196 197 198 except usage.UsageError, errortext: 199 print '%s: %s' % (sys.argv[0], errortext) 200 print '%s: Try --help for usage details.' % (sys.argv[0]) 201 sys.exit(1)
202