Package Gnumed :: Module gnumed
[frames] | no frames]

Source Code for Module Gnumed.gnumed

  1  #!/usr/bin/env python 
  2   
  3  __doc__ = """GNUmed client launcher. 
  4   
  5  This is the launcher for the GNUmed GUI client. It takes 
  6  care of all the pre- and post-GUI runtime environment setup. 
  7   
  8  --quiet 
  9   Be extra quiet and show only _real_ errors in the log. 
 10  --debug 
 11   Pre-set the [debug mode] checkbox in the login dialog to 
 12   increase verbosity in the log file. Useful for, well, debugging :-) 
 13  --slave 
 14   Pre-set the [enable remote control] checkbox in the login 
 15   dialog to enable the XML-RPC remote control feature. 
 16  --hipaa 
 17   Enable HIPAA functionality which has user impact. 
 18  --profile=<file> 
 19   Activate profiling and write profile data to <file>. 
 20  --text-domain=<text domain> 
 21   Set this to change the name of the language file to be loaded. 
 22   Note, this does not change the directory the file is searched in, 
 23   only the name of the file where messages are loaded from. The 
 24   standard textdomain is, of course, "gnumed.mo". 
 25  --log-file=<file> 
 26   Use this to change the name of the log file. 
 27   See gmLog2.py to find out where the standard log file would 
 28   end up. 
 29  --conf-file=<file> 
 30   Use configuration file <file> instead of searching for it in 
 31   standard locations. 
 32  --lang-gettext=<language> 
 33   Explicitly set the language to use in gettext translation. The very 
 34   same effect can be achieved by setting the environment variable $LANG 
 35   from a launcher script. 
 36  --override-schema-check 
 37   Continue loading the client even if the database schema version 
 38   and the client software version cannot be verified to be compatible. 
 39  --skip-update-check 
 40   Skip checking for client updates. This is useful during development 
 41   and when the update check URL is unavailable (down). 
 42  --local-import 
 43   Adjust the PYTHONPATH such that GNUmed can be run from a local source tree. 
 44  --ui=<ui type> 
 45   Start an alternative UI. Defaults to wxPython if not specified. 
 46   Valid values: chweb (CherryPy), wxp (wxPython), web (ProxiedWeb) 
 47  --version, -V 
 48   Show version information. 
 49  --help, -h, or -? 
 50   Show this help. 
 51  """ 
 52  #========================================================== 
 53  __version__ = "$Revision: 1.169 $" 
 54  __author__  = "H. Herb <hherb@gnumed.net>, K. Hilbert <Karsten.Hilbert@gmx.net>, I. Haywood <i.haywood@ugrad.unimelb.edu.au>" 
 55  __license__ = "GPL (details at http://www.gnu.org)" 
 56   
 57  # standard library 
 58  import sys, os, os.path, signal, logging, platform 
 59   
 60   
 61  # do not run as module 
 62  if __name__ != "__main__": 
 63          print "GNUmed startup: This is not intended to be imported as a module !" 
 64          print "-----------------------------------------------------------------" 
 65          print __doc__ 
 66          sys.exit(1) 
 67   
 68   
 69  # do not run as root 
 70  if os.name in ['posix'] and os.geteuid() == 0: 
 71          print """ 
 72  GNUmed startup: GNUmed should not be run as root. 
 73  ------------------------------------------------- 
 74   
 75  Running GNUmed as <root> can potentially put all 
 76  your medical data at risk. It is strongly advised 
 77  against. Please run GNUmed as a non-root user. 
 78  """ 
 79          sys.exit(1) 
 80   
 81  #---------------------------------------------------------- 
 82  #current_client_version = u'0.7.rc1' 
 83  current_client_version = u'GIT HEAD' 
 84  #current_client_branch = u'0.7' 
 85  current_client_branch = u'GIT tree' 
 86   
 87  _log = None 
 88  _cfg = None 
 89  _old_sig_term = None 
 90  _known_short_options = u'h?V' 
 91  _known_long_options = [ 
 92          u'debug', 
 93          u'slave', 
 94          u'skip-update-check', 
 95          u'profile=', 
 96          u'text-domain=', 
 97          u'log-file=', 
 98          u'conf-file=', 
 99          u'lang-gettext=', 
100          u'ui=', 
101          u'override-schema-check', 
102          u'local-import', 
103          u'help', 
104          u'version', 
105          u'hipaa' 
106  ] 
107   
108  _known_ui_types = [ 
109          u'web', 
110          u'wxp', 
111          u'chweb' 
112  ] 
113   
114  import_error_sermon = """ 
115  GNUmed startup: Cannot load GNUmed Python modules ! 
116  --------------------------------------------------- 
117  CRITICAL ERROR: Program halted. 
118   
119  Please make sure you have: 
120   
121   1) the required third-party Python modules installed 
122   2) the GNUmed Python modules linked or installed into site-packages/ 
123      (if you do not run from a CVS tree the installer should have taken care of that) 
124   3) your PYTHONPATH environment variable set up correctly 
125   
126  sys.path is currently set to: 
127   
128   %s 
129   
130  If you are running from a copy of the CVS tree make sure you 
131  did run gnumed/check-prerequisites.sh with good results. 
132   
133  If you still encounter errors after checking the above 
134  requirements please ask on the mailing list. 
135  """ 
136   
137   
138  missing_cli_config_file = u""" 
139  GNUmed startup: Missing configuration file. 
140  ------------------------------------------- 
141   
142  You explicitly specified a configuration file 
143  on the command line: 
144   
145          --conf-file=%s 
146   
147  The file does not exist, however. 
148  """ 
149   
150   
151  no_config_files = u""" 
152  GNUmed startup: Missing configuration files. 
153  -------------------------------------------- 
154   
155  None of the below candidate configuration 
156  files could be found: 
157   
158   %s 
159   
160  Cannot run GNUmed without any of them. 
161  """ 
162  #========================================================== 
163  # convenience functions 
164  #========================================================== 
165 -def setup_python_path():
166 167 if not u'--local-import' in sys.argv: 168 return 169 170 print "GNUmed startup: Running from local source tree." 171 print "-----------------------------------------------" 172 173 local_python_base_dir = os.path.dirname ( 174 os.path.abspath(os.path.join(sys.argv[0], '..')) 175 ) 176 177 # does the path exist at all, physically ? 178 # (*broken* links are reported as False) 179 link_name = os.path.join(local_python_base_dir, 'Gnumed') 180 if not os.path.exists(link_name): 181 real_dir = os.path.join(local_python_base_dir, 'client') 182 print "Creating module import symlink ..." 183 print ' real dir:', real_dir 184 print ' link:', link_name 185 os.symlink(real_dir, link_name) 186 187 print "Adjusting PYTHONPATH ..." 188 sys.path.insert(0, local_python_base_dir)
189 #==========================================================
190 -def setup_logging():
191 try: 192 from Gnumed.pycommon import gmLog2 as _gmLog2 193 except ImportError: 194 sys.exit(import_error_sermon % '\n '.join(sys.path)) 195 196 global gmLog2 197 gmLog2 = _gmLog2 198 199 global _log 200 _log = logging.getLogger('gm.launcher')
201 #==========================================================
202 -def log_startup_info():
203 _log.info('Starting up as main module (%s).', __version__) 204 _log.info('GNUmed client version [%s] on branch [%s]', current_client_version, current_client_branch) 205 _log.info('Platform: %s', platform.uname()) 206 _log.info('Python %s on %s (%s)', sys.version, sys.platform, os.name) 207 try: 208 import lsb_release 209 _log.info('%s' % lsb_release.get_distro_information()) 210 except ImportError: 211 pass
212 #==========================================================
213 -def setup_console_exception_handler():
214 from Gnumed.pycommon.gmTools import handle_uncaught_exception_console 215 216 sys.excepthook = handle_uncaught_exception_console
217 #==========================================================
218 -def setup_cli():
219 from Gnumed.pycommon import gmCfg2 220 221 global _cfg 222 _cfg = gmCfg2.gmCfgData() 223 _cfg.add_cli ( 224 short_options = _known_short_options, 225 long_options = _known_long_options 226 ) 227 228 val = _cfg.get(option = '--debug', source_order = [('cli', 'return')]) 229 if val is None: 230 val = False 231 _cfg.set_option ( 232 option = u'debug', 233 value = val 234 ) 235 236 val = _cfg.get(option = '--slave', source_order = [('cli', 'return')]) 237 if val is None: 238 val = False 239 _cfg.set_option ( 240 option = u'slave', 241 value = val 242 ) 243 244 val = _cfg.get(option = '--skip-update-check', source_order = [('cli', 'return')]) 245 if val is None: 246 val = False 247 _cfg.set_option ( 248 option = u'skip-update-check', 249 value = val 250 ) 251 252 val = _cfg.get(option = '--hipaa', source_order = [('cli', 'return')]) 253 if val is None: 254 val = False 255 _cfg.set_option ( 256 option = u'hipaa', 257 value = val 258 ) 259 260 val = _cfg.get(option = '--local-import', source_order = [('cli', 'return')]) 261 if val is None: 262 val = False 263 _cfg.set_option ( 264 option = u'local-import', 265 value = val 266 ) 267 268 _cfg.set_option ( 269 option = u'client_version', 270 value = current_client_version 271 ) 272 273 _cfg.set_option ( 274 option = u'client_branch', 275 value = current_client_branch 276 )
277 278 #==========================================================
279 -def handle_sig_term(signum, frame):
280 _log.critical('SIGTERM (SIG%s) received, shutting down ...' % signum) 281 gmLog2.flush() 282 print 'GNUmed: SIGTERM (SIG%s) received, shutting down ...' % signum 283 if frame is not None: 284 print '%s::%s@%s' % (frame.f_code.co_filename, frame.f_code.co_name, frame.f_lineno) 285 286 # FIXME: need to do something useful here 287 288 if _old_sig_term in [None, signal.SIG_IGN]: 289 sys.exit(signal.SIGTERM) 290 else: 291 _old_sig_term(signum, frame)
292 #----------------------------------------------------------
293 -def setup_signal_handlers():
294 global _old_sig_term 295 old_sig_term = signal.signal(signal.SIGTERM, handle_sig_term)
296 #==========================================================
297 -def setup_locale():
298 gmI18N.activate_locale() 299 300 td = _cfg.get(option = '--text-domain', source_order = [('cli', 'return')]) 301 l = _cfg.get(option = '--lang-gettext', source_order = [('cli', 'return')]) 302 gmI18N.install_domain(domain = td, language = l, prefer_local_catalog = _cfg.get(option = u'local-import')) 303 304 # make sure we re-get the default encoding 305 # in case it changed 306 gmLog2.set_string_encoding()
307 #==========================================================
308 -def handle_help_request():
309 src = [(u'cli', u'return')] 310 311 help_requested = ( 312 _cfg.get(option = u'--help', source_order = src) or 313 _cfg.get(option = u'-h', source_order = src) or 314 _cfg.get(option = u'-?', source_order = src) 315 ) 316 317 if help_requested: 318 print _( 319 'Help requested\n' 320 '--------------' 321 ) 322 print __doc__ 323 sys.exit(0)
324 #==========================================================
325 -def handle_version_request():
326 src = [(u'cli', u'return')] 327 328 version_requested = ( 329 _cfg.get(option = u'--version', source_order = src) or 330 _cfg.get(option = u'-V', source_order = src) 331 ) 332 333 if version_requested: 334 335 from Gnumed.pycommon.gmPG2 import map_client_branch2required_db_version, known_schema_hashes 336 337 print 'GNUmed version information' 338 print '--------------------------' 339 print 'client : %s on branch [%s]' % (current_client_version, current_client_branch) 340 print 'database : %s' % map_client_branch2required_db_version[current_client_branch] 341 print 'schema hash: %s' % known_schema_hashes[map_client_branch2required_db_version[current_client_branch]] 342 sys.exit(0)
343 344 #==========================================================
345 -def setup_paths_and_files():
346 """Create needed paths in user home directory.""" 347 348 gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'scripts'))) 349 gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'spellcheck'))) 350 gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'tmp'))) 351 gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'docs'))) 352 gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'xDT'))) 353 gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'EMR'))) 354 gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed', 'xDT'))) 355 gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed', 'logs'))) 356 357 paths = gmTools.gmPaths(app_name = u'gnumed') 358 359 open(os.path.expanduser(os.path.join('~', '.gnumed', 'gnumed.conf')), 'a+').close()
360 #==========================================================
361 -def setup_date_time():
362 gmDateTime.init()
363 #==========================================================
364 -def setup_cfg():
365 """Detect and setup access to GNUmed config file. 366 367 Parts of this will have limited value due to 368 wxPython not yet being available. 369 """ 370 371 enc = gmI18N.get_encoding() 372 paths = gmTools.gmPaths(app_name = u'gnumed') 373 374 candidates = [ 375 # the current working dir 376 [u'workbase', os.path.join(paths.working_dir, 'gnumed.conf')], 377 # /etc/gnumed/ 378 [u'system', os.path.join(paths.system_config_dir, 'gnumed-client.conf')], 379 # ~/.gnumed/ 380 [u'user', os.path.join(paths.user_config_dir, 'gnumed.conf')], 381 # CVS/tgz tree .../gnumed/client/ (IOW a local installation) 382 [u'local', os.path.join(paths.local_base_dir, 'gnumed.conf')] 383 ] 384 # --conf-file= 385 explicit_fname = _cfg.get(option = u'--conf-file', source_order = [(u'cli', u'return')]) 386 if explicit_fname is None: 387 candidates.append([u'explicit', None]) 388 else: 389 candidates.append([u'explicit', explicit_fname]) 390 391 for candidate in candidates: 392 _cfg.add_file_source ( 393 source = candidate[0], 394 file = candidate[1], 395 encoding = enc 396 ) 397 398 # --conf-file given but does not actually exist ? 399 if explicit_fname is not None: 400 if _cfg.source_files['explicit'] is None: 401 _log.error('--conf-file argument does not exist') 402 sys.exit(missing_cli_config_file % explicit_fname) 403 404 # any config file found at all ? 405 found_any_file = False 406 for f in _cfg.source_files.values(): 407 if f is not None: 408 found_any_file = True 409 break 410 if not found_any_file: 411 _log.error('no config file found at all') 412 sys.exit(no_config_files % '\n '.join(candidates)) 413 414 # mime type handling sources 415 fname = u'mime_type2file_extension.conf' 416 _cfg.add_file_source ( 417 source = u'user-mime', 418 file = os.path.join(paths.user_config_dir, fname), 419 encoding = enc 420 ) 421 _cfg.add_file_source ( 422 source = u'system-mime', 423 file = os.path.join(paths.system_config_dir, fname), 424 encoding = enc 425 )
426 #==========================================================
427 -def setup_ui_type():
428 global ui_type 429 430 ui_type = _cfg.get(option = u'--ui', source_order = [(u'cli', u'return')]) 431 432 if ui_type in [True, False, None]: 433 ui_type = 'wxp' 434 435 ui_type = ui_type.strip() 436 437 if ui_type not in _known_ui_types: 438 _log.error('unknown UI type: %s', ui_type) 439 _log.debug('known UI types: %s', str(_known_ui_types)) 440 print "GNUmed startup: Unknown UI type (%s). Defaulting to wxPython client." % ui_type 441 ui_type = 'wxp' 442 443 _log.debug('UI type: %s', ui_type)
444 #==========================================================
445 -def setup_backend():
446 _log.info('client expects database version [%s]', gmPG2.map_client_branch2required_db_version[current_client_branch]) 447 448 # set up database connection timezone 449 timezone = _cfg.get ( 450 group = u'backend', 451 option = 'client timezone', 452 source_order = [ 453 ('explicit', 'return'), 454 ('workbase', 'return'), 455 ('local', 'return'), 456 ('user', 'return'), 457 ('system', 'return') 458 ] 459 ) 460 if timezone is not None: 461 gmPG2.set_default_client_timezone(timezone)
462 #==========================================================
463 -def shutdown_backend():
464 gmPG2.shutdown()
465 #==========================================================
466 -def shutdown_logging():
467 468 # if _cfg.get(option = u'debug'): 469 # import types 470 471 # def get_refcounts(): 472 # refcount = {} 473 # # collect all classes 474 # for module in sys.modules.values(): 475 # for sym in dir(module): 476 # obj = getattr(module, sym) 477 # if type(obj) is types.ClassType: 478 # refcount[obj] = sys.getrefcount(obj) 479 # # sort by refcount 480 # pairs = map(lambda x: (x[1],x[0]), refcount.items()) 481 # pairs.sort() 482 # pairs.reverse() 483 # return pairs 484 485 # rcfile = open('./gm-refcount.lst', 'wb') 486 # for refcount, class_ in get_refcounts(): 487 # if not class_.__name__.startswith('wx'): 488 # rcfile.write('%10d %s\n' % (refcount, class_.__name__)) 489 # rcfile.close() 490 491 # do not choke on Windows 492 logging.raiseExceptions = False
493 494 #========================================================== 495 # main - launch the GNUmed wxPython GUI client 496 #---------------------------------------------------------- 497 setup_python_path() 498 setup_logging() 499 log_startup_info() 500 setup_console_exception_handler() 501 setup_cli() 502 setup_signal_handlers() 503 504 from Gnumed.pycommon import gmI18N, gmTools, gmDateTime, gmHooks 505 setup_locale() 506 handle_help_request() 507 handle_version_request() 508 setup_paths_and_files() 509 setup_date_time() 510 setup_cfg() 511 setup_ui_type() 512 513 from Gnumed.pycommon import gmPG2 514 if ui_type in [u'web']: 515 gmPG2.auto_request_login_params = False 516 setup_backend() 517 518 519 gmHooks.run_hook_script(hook = u'startup-before-GUI') 520 521 if ui_type == u'wxp': 522 from Gnumed.wxpython import gmGuiMain 523 profile_file = _cfg.get(option = u'--profile', source_order = [(u'cli', u'return')]) 524 if profile_file is not None: 525 _log.info('writing profiling data into %s', profile_file) 526 import profile 527 profile.run('gmGuiMain.main()', profile_file) 528 else: 529 gmGuiMain.main() 530 elif ui_type == u'web': 531 from Gnumed.proxiedpyjamas import gmWebGuiServer 532 gmWebGuiServer.main() 533 534 elif ui_type == u'chweb': 535 from Gnumed.CherryPy import gmGuiWeb 536 gmGuiWeb.main() 537 538 gmHooks.run_hook_script(hook = u'shutdown-post-GUI') 539 540 shutdown_backend() 541 _log.info('Normally shutting down as main module.') 542 shutdown_logging() 543 544 #========================================================== 545