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