Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

genconfuser.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Generate _confDb.py files for ConfigurableUser classes.
00004 """
00005 
00006 import os
00007 import sys
00008 import time
00009 import logging
00010 import GaudiKernel.ConfigurableDb
00011 
00012 from pprint import pformat
00013 from glob import glob
00014 from GaudiKernel.ConfigurableDb import cfgDb
00015 
00016 logging.VERBOSE = (logging.INFO + logging.DEBUG) / 2
00017 logging.addLevelName(logging.VERBOSE, "VERBOSE")
00018 logging.verbose = lambda msg, *args, **kwargs: \
00019     apply(logging.log, (logging.VERBOSE, msg) + args, kwargs)
00020 
00021 def _inheritsfrom(derived, basename):
00022     """
00023     Check if the class name 'basename' is anywhere in the base classes of the
00024     class 'derived'.
00025     If 'derived' _is_ 'basename', returns False.
00026     """
00027     for b in derived.__bases__:
00028         if b.__name__ == basename:
00029             return True
00030         else:
00031             if _inheritsfrom(b, basename):
00032                 return True
00033     return False
00034 
00035 def loadConfigurableDb():
00036     '''
00037     Equivalent to GaudiKernel.ConfigurableDb.loadConfigurableDb(), but does a
00038     deep search and executes the '*_confDb.py' files instead of importing them.
00039     '''
00040     # find the '*_confDb.py' files that are not merged ones
00041     for p in sys.path:
00042         for f in [f for f in glob(os.path.join(p, '*', '*_confDb.py'))
00043                   if 'merged' not in f and os.path.isfile(f)]:
00044             logging.verbose('Loading %s', f)
00045             try:
00046                 execfile(f, {}, {})
00047             except:
00048                 # It may happen that the file is found but not completely
00049                 # written, usually during parallel builds, but we do not care.
00050                 pass
00051     # top up with the regular merged confDb (for the used projects)
00052     GaudiKernel.ConfigurableDb.loadConfigurableDb()
00053 
00054 def getConfigurableUsers(modulename, root, mayNotExist = False):
00055     """
00056     Find in the module 'modulename' all the classes that derive from ConfigurableUser.
00057     Return the list of the names.
00058     The flag mayNotExist is used to choose the level of the logging message in case
00059     the requested module does not exist.
00060     """
00061     # remember the old system path
00062     oldpath = list(sys.path)
00063     # we need to hack the sys.path to add the first part of the module name after root
00064     moduleelements = modulename.split('.')
00065     if len(moduleelements) > 1:
00066         moddir = os.sep.join([root] + moduleelements[:-1])
00067     else:
00068         moddir = root
00069     # this is the name of the submodule to import
00070     shortmodname = moduleelements[-1]
00071     # check if the module file actually exists
00072     if not os.path.exists(os.path.join(moddir, shortmodname) + ".py"):
00073         msg = "Module %s does not exist" % modulename
00074         if mayNotExist:
00075             logging.verbose(msg)
00076         else:
00077             logging.error(msg)
00078         # no file -> do not try to import
00079         return []
00080     # prepend moddir to the path
00081     sys.path.insert(0, moddir)
00082     logging.verbose("sys.path prepended with %r", sys.path[0])
00083 
00084     logging.info("Looking for ConfigurableUser in %r", modulename)
00085     g, l = {}, {}
00086     try:
00087         logging.verbose("importing %s", shortmodname)
00088         exec "import %s as mod" % shortmodname in g, l
00089     finally:
00090         # restore old sys.path
00091         logging.verbose("restoring old sys.path")
00092         sys.path = oldpath
00093     mod = l["mod"]
00094     if "__all__" in dir(mod) and mod.__all__:
00095         all = mod.__all__
00096     else:
00097         all = [ n for n in dir(mod) if not n.startswith("_")]
00098     result = []
00099     for name in all:
00100         cfg = cfgDb.get(name)
00101         if cfg and cfg["module"] != modulename:
00102             # This name comes from another module
00103             logging.verbose("Object %r already found in module %r", name, cfg["module"])
00104             continue
00105         t = getattr(mod, name)
00106         if isinstance(t, type) and  _inheritsfrom(t, "ConfigurableUser"):
00107             result.append(name)
00108     logging.verbose("Found %r", result)
00109     return result
00110 
00111 def main():
00112     from optparse import OptionParser
00113     parser = OptionParser(prog = os.path.basename(sys.argv[0]),
00114                           usage = "%prog [options] <PackageName> [<Module1> ...]")
00115     parser.add_option("-o", "--output", action="store", type="string",
00116                       help="output file for confDb data [default = '../genConf/<PackageName>_user_confDb.py'].")
00117     parser.add_option("-r", "--root", action="store", type="string",
00118                       help="root directory of the python modules [default = '../python'].")
00119     parser.add_option("-v", "--verbose", action="store_true",
00120                       help="print some debugging information")
00121     parser.add_option("--debug", action="store_true",
00122                       help="print more debugging information")
00123     parser.add_option("--lockerpath", action="store",
00124                       metavar = "DIRNAME",
00125                       help="directory where to find the module 'locker'")
00126     parser.set_defaults(root = os.path.join("..","python"))
00127 
00128     opts, args = parser.parse_args()
00129 
00130     if opts.debug:
00131         log_level = logging.DEBUG
00132     elif opts.verbose:
00133         log_level = logging.VERBOSE
00134     else:
00135         log_level = logging.INFO
00136     logging.basicConfig(format = "%(levelname)s: %(message)s",
00137                         stream = sys.stdout,
00138                         level = log_level)
00139 
00140     if len(args) < 1:
00141         parser.error("PackageName is required")
00142 
00143     package_name = args.pop(0)
00144 
00145     usingConvention = False
00146     if not args:
00147         # use the conventional module name <package>.Configuration
00148         args = [package_name + ".Configuration"]
00149         usingConvention = True
00150 
00151     genConfDir = os.path.join("..", os.environ.get("CMTCONFIG", ""), "genConf")
00152     if not os.path.exists(genConfDir):
00153         genConfDir = os.path.join("..", "genConf")
00154 
00155     if not opts.output:
00156         outputfile = os.path.join(genConfDir, package_name + '_user_confDb.py')
00157     else:
00158         outputfile = opts.output
00159 
00160 
00161     # The locking ensures that nobody tries to modify the python.zip file while
00162     # we read it.
00163     dbLock = None
00164     if "GAUDI_BUILD_LOCK" in os.environ:
00165         if opts.lockerpath:
00166             sys.path.append(opts.lockerpath)
00167         # Get the LockFile class from the locker module in GaudiPolicy or use a fake
00168         # factory.
00169         try:
00170             from locker import LockFile
00171         except ImportError:
00172             def LockFile(*args, **kwargs):
00173                 return None
00174         # obtain the lock
00175         dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary =  True)
00176 
00177     # We can disable the error on missing configurables only if we can import Gaudi.Configurables
00178     # It must be done at this point because it may conflict with logging.basicConfig
00179     try:
00180         import Gaudi.Configurables
00181         Gaudi.Configurables.ignoreMissingConfigurables = True
00182     except:
00183         pass
00184     # load configurables database to avoid fake duplicates
00185     loadConfigurableDb()
00186     # ensure that local configurables are in the database
00187     try:
00188         # Add the local python directories to the python path to be able to import the local
00189         # configurables
00190         sys.path.insert(0, genConfDir)
00191         sys.path.insert(0, os.path.join("..", "python"))
00192         localConfDb = os.path.join(genConfDir, package_name, package_name + '_confDb.py')
00193         if os.path.exists(localConfDb):
00194             execfile(localConfDb, {}, {})
00195             # Extend the search path of the package module to find the configurables
00196             package_module = __import__(package_name)
00197             package_module.__path__.insert(0, os.path.join(genConfDir, package_name))
00198     except:
00199         pass # ignore failures (not important)
00200     del dbLock # Now we can let the others operate on the install area python directory
00201 
00202     # Collecting ConfigurableUser specializations
00203     cus = {}
00204     for mod in args:
00205         lst = None
00206         try:
00207             lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
00208         except ImportError:
00209             import traceback
00210             logging.error("Cannot import module %r:\n%s", mod,
00211                           traceback.format_exc().rstrip()) # I remove the trailing '\n'
00212             return 2
00213         if lst:
00214             cus[mod] = lst
00215             # Add the configurables to the database as fake entries to avoid duplicates
00216             for m in lst:
00217                 cfgDb.add(configurable = m,
00218                           package = 'None',
00219                           module  = 'None',
00220                           lib     = 'None')
00221         elif not usingConvention:
00222             logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
00223 
00224     if cus:
00225         logging.info("ConfigurableUser found:\n%s", pformat(cus))
00226         # header
00227         output = """##  -*- python -*-
00228 # db file automatically generated by %s on: %s
00229 ## insulates outside world against anything bad that could happen
00230 ## also prevents global scope pollution
00231 def _fillCfgDb():
00232     from GaudiKernel.Proxy.ConfigurableDb import CfgDb
00233 
00234     # get a handle on the repository of Configurables
00235     cfgDb = CfgDb()
00236 
00237     # populate the repository with informations on Configurables
00238 """ % (parser.prog, time.asctime())
00239 
00240         for mod in cus:
00241             for cu in cus[mod]:
00242                 output += """
00243     cfgDb.add( configurable = '%s',
00244                package = '%s',
00245                module  = '%s',
00246                lib     = 'None' )""" % (cu, package_name, mod)
00247 
00248         # trailer
00249         output += """
00250 
00251     return #_fillCfgDb
00252 
00253 # fill cfgDb at module import...
00254 try:
00255     _fillCfgDb()
00256     #house cleaning...
00257     del _fillCfgDb
00258 except Exception,err:
00259     print "Py:ConfigurableDb   ERROR Problem with [%%s] content!" %% __name__
00260     print "Py:ConfigurableDb   ERROR",err
00261     print "Py:ConfigurableDb   ERROR   ==> culprit is package [%s] !"
00262 """ % package_name
00263     elif usingConvention:
00264         logging.info("No ConfigurableUser found")
00265         output = ("# db file automatically generated by %s on: %s\n"
00266                   "# No ConfigurableUser specialization in %s\n") % (parser.prog, time.asctime(), package_name)
00267     else:
00268         logging.error("No ConfigurableUser specialization found")
00269         return 1
00270 
00271     # create the destination directory if not there
00272     output_dir = os.path.dirname(outputfile)
00273     if not os.path.exists(output_dir):
00274         logging.info("Creating directory %r", output_dir)
00275         os.makedirs(output_dir, 0755)
00276 
00277     # write output to file
00278     logging.verbose("Writing confDb data to %r", outputfile)
00279     open(outputfile, "w").write(output)
00280     return 0
00281 
00282 if __name__ == '__main__':
00283     retcode = main()
00284     sys.exit(retcode)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:33 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004