Package flumotion :: Package common :: Module boot
[hide private]

Source Code for Module flumotion.common.boot

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  """boostrapping functions for flumotion""" 
 19   
 20  import os 
 21  import sys 
 22   
 23  from flumotion.common.log import safeprintf 
 24   
 25  __version__ = "$Rev$" 
 26  # Keep in sync with configure.ac 
 27  PYGTK_REQ = (2, 10, 0) 
 28  KIWI_REQ = (1, 9, 13) 
 29  GST_REQ = {'0.10': {'gstreamer': (0, 10, 10), 
 30                      'gst-python': (0, 10, 4)}} 
 31  USE_GOPTION_PARSER = False 
 32  USE_GTK = False 
 33  USE_GST = True 
 34   
 35   
36 -def init_gobject():
37 """ 38 Initialize pygobject. A missing or too-old pygobject will cause a 39 SystemExit exception to be raised. 40 """ 41 try: 42 import pygtk 43 pygtk.require('2.0') 44 45 import gobject 46 except ImportError: 47 raise SystemExit('ERROR: PyGTK could not be found') 48 49 if gobject.pygtk_version < PYGTK_REQ: 50 raise SystemExit('ERROR: PyGTK %s or higher is required' 51 % '.'.join(map(str, PYGTK_REQ))) 52 53 gobject.threads_init()
54 55
56 -def _init_gst_version(gst_majorminor):
57 58 def tup2version(tup): 59 return '.'.join(map(str, tup))
60 61 if gst_majorminor not in GST_REQ: 62 raise SystemExit('ERROR: Invalid FLU_GST_VERSION: %r (expected ' 63 'one of %r)' % (gst_majorminor, GST_REQ.keys())) 64 65 pygst_req = GST_REQ[gst_majorminor]['gst-python'] 66 gst_req = GST_REQ[gst_majorminor]['gstreamer'] 67 68 try: 69 import pygst 70 pygst.require(gst_majorminor) 71 import gst 72 except ImportError: 73 return False 74 except AssertionError: 75 return False 76 77 try: 78 gst_version = gst.get_gst_version() 79 pygst_version = gst.get_pygst_version() 80 except AttributeError: 81 # get_foo_version() added in 0.10.4, fall back 82 gst_version = gst.gst_version 83 pygst_version = gst.pygst_version 84 85 if gst_req[:2] != gst_version[:2]: 86 raise SystemExit( 87 'ERROR: Expected GStreamer %s, but got incompatible %s' 88 % (gst_majorminor, tup2version(gst_version[:2]))) 89 90 if gst_version < gst_req: 91 raise SystemExit( 92 'ERROR: GStreamer %s too old; install %s or newer' 93 % (tup2version(gst_version), tup2version(gst_req))) 94 95 if pygst_version < pygst_req: 96 raise SystemExit( 97 'ERROR: gst-python %s too old; install %s or newer' 98 % (tup2version(pygst_version), tup2version(pygst_req))) 99 100 return True 101 102
103 -def init_gst():
104 """ 105 Initialize pygst. A missing or too-old pygst will cause a 106 SystemExit exception to be raised. 107 """ 108 assert 'gobject' in sys.modules, "Run init_gobject() first" 109 110 gst_majorminor = os.getenv('FLU_GST_VERSION') 111 112 if gst_majorminor: 113 if not _init_gst_version(gst_majorminor): 114 raise SystemExit('ERROR: requested GStreamer version %s ' 115 'not available' % gst_majorminor) 116 else: 117 majorminors = GST_REQ.keys() 118 majorminors.sort() 119 while majorminors: 120 majorminor = majorminors.pop() 121 if _init_gst_version(majorminor): 122 gst_majorminor = majorminor 123 break 124 if not gst_majorminor: 125 raise SystemExit('ERROR: no GStreamer available ' 126 '(looking for versions %r)' % (GST_REQ.keys(), )) 127 128 return gst_majorminor
129 130
131 -def init_kiwi():
132 import gobject 133 134 try: 135 from kiwi.__version__ import version as kiwi_version 136 except ImportError: 137 return False 138 139 if kiwi_version < KIWI_REQ: 140 raise SystemExit('ERROR: Kiwi %s or higher is required' 141 % '.'.join(map(str, KIWI_REQ))) 142 elif gobject.pygobject_version > (2, 26, 0): 143 # Kiwi is not compatible yet with the changes introduced in 144 # http://git.gnome.org/browse/pygobject/commit/?id=84d614 145 # Basically, what we do is to revert the changes in _type_register of 146 # GObjectMeta at least until kiwi works properly with new pygobject 147 from gobject._gobject import type_register 148 149 def _type_register(cls, namespace): 150 ## don't register the class if already registered 151 if '__gtype__' in namespace: 152 return 153 154 if not ('__gproperties__' in namespace or 155 '__gsignals__' in namespace or 156 '__gtype_name__' in namespace): 157 return 158 159 # Do not register a new GType for the overrides, as this would sort 160 # of defeat the purpose of overrides... 161 if cls.__module__.startswith('gi.overrides.'): 162 return 163 164 type_register(cls, namespace.get('__gtype_name__'))
165 166 gobject.GObjectMeta._type_register = _type_register 167 168 return True 169 170
171 -def init_option_parser(gtk, gst):
172 # We should only use the GOption parser if we are already going to 173 # import gobject, and if we can find a recent enough version of 174 # pygobject on our system. There were bugs in the GOption parsing 175 # until pygobject 2.15.0, so just revert to optparse if our 176 # pygobject is too old. 177 global USE_GOPTION_PARSER 178 if not gtk and not gst: 179 USE_GOPTION_PARSER = False 180 else: 181 import gobject 182 if getattr(gobject, 'pygobject_version', ()) >= (2, 15, 0): 183 USE_GOPTION_PARSER = True 184 else: 185 USE_GOPTION_PARSER = False
186 187
188 -def wrap_for_statprof(main, output_file):
189 try: 190 import statprof 191 except ImportError, e: 192 print "Profiling requested, but statprof not available (%s)" % e 193 return main 194 195 def wrapped(*args, **kwargs): 196 statprof.start() 197 try: 198 return main(*args, **kwargs) 199 finally: 200 statprof.stop() 201 statprof.display(OUT=file(output_file, 'wb'))
202 return wrapped 203 204
205 -def wrap_for_builtin_profiler(main, output_file):
206 try: 207 import cProfile as profile 208 except ImportError: 209 import profile 210 211 def wrapped(*args, **kwargs): 212 prof = profile.Profile() 213 try: 214 return prof.runcall(main, *args, **kwargs) 215 finally: 216 prof.dump_stats(output_file)
217 return wrapped 218 219
220 -def wrap_for_profiling(main):
221 222 def generate_output_file(): 223 import tempfile 224 return os.path.join(tempfile.gettempdir(), 225 'flustat.%s.%s.%d' % 226 (main.__module__, main.__name__, os.getpid()))
227 228 if os.getenv('FLU_PROFILE'): 229 return wrap_for_statprof(main, generate_output_file()) 230 elif os.getenv('FLU_BUILTIN_PROFILE'): 231 return wrap_for_builtin_profiler(main, generate_output_file()) 232 else: 233 return main 234 235
236 -def boot(path, gtk=False, gst=True, installReactor=True):
237 # python 2.5 and twisted < 2.5 don't work together 238 pythonMM = sys.version_info[0:2] 239 from twisted.copyright import version 240 twistedMM = tuple([int(n) for n in version.split('.')[0:2]]) 241 if pythonMM >= (2, 5) and twistedMM < (2, 5): 242 raise SystemError( 243 "Twisted versions older than 2.5.0 do not work with " 244 "Python 2.5 and newer. " 245 "Please upgrade Twisted or downgrade Python.") 246 247 if gtk or gst: 248 init_gobject() 249 250 if gtk: 251 init_kiwi() 252 253 if gst: 254 from flumotion.configure import configure 255 configure.gst_version = init_gst() 256 257 global USE_GTK, USE_GST 258 USE_GTK=gtk 259 USE_GST=gst 260 init_option_parser(gtk, gst) 261 262 # installing the reactor could override our packager's import hooks ... 263 if installReactor: 264 from twisted.internet import gtk2reactor 265 try: 266 gtk2reactor.install(useGtk=gtk) 267 except RuntimeError, e: 268 safeprintf(sys.stderr, 'ERROR: %s\n', e) 269 sys.exit(1) 270 from twisted.internet import reactor 271 272 # ... so we install them again here to be safe 273 from flumotion.common import package 274 package.getPackager().install() 275 276 # this monkeypatched var exists to let reconnecting factories know 277 # when they should warn about a connection being closed, and when 278 # they shouldn't because the system is shutting down. 279 # 280 # there is no race condition here -- the reactor doesn't handle 281 # signals until it is run(). 282 reactor.killed = False 283 284 def setkilled(killed): 285 reactor.killed = killed
286 287 reactor.addSystemEventTrigger('before', 'startup', setkilled, False) 288 reactor.addSystemEventTrigger('before', 'shutdown', setkilled, True) 289 290 from flumotion.twisted import reflect 291 from flumotion.common import errors 292 from flumotion.common import setup 293 294 setup.setup() 295 296 from flumotion.common import log 297 log.logTwisted() 298 299 main = reflect.namedAny(path) 300 301 wrapped = wrap_for_profiling(main) 302 wrapped.__name__ = main.__name__ 303 304 try: 305 sys.exit(wrapped(sys.argv)) 306 except (errors.FatalError, SystemError), e: 307 safeprintf(sys.stderr, 'ERROR: %s\n', e) 308 sys.exit(1) 309