00001
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
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
00049
00050 pass
00051
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
00062 oldpath = list(sys.path)
00063
00064 moduleelements = modulename.split('.')
00065 if len(moduleelements) > 1:
00066 moddir = os.sep.join([root] + moduleelements[:-1])
00067 else:
00068 moddir = root
00069
00070 shortmodname = moduleelements[-1]
00071
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
00079 return []
00080
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
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
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
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
00162
00163 dbLock = None
00164 if "GAUDI_BUILD_LOCK" in os.environ:
00165 if opts.lockerpath:
00166 sys.path.append(opts.lockerpath)
00167
00168
00169 try:
00170 from locker import LockFile
00171 except ImportError:
00172 def LockFile(*args, **kwargs):
00173 return None
00174
00175 dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
00176
00177
00178
00179 try:
00180 import Gaudi.Configurables
00181 Gaudi.Configurables.ignoreMissingConfigurables = True
00182 except:
00183 pass
00184
00185 loadConfigurableDb()
00186
00187 try:
00188
00189
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
00196 package_module = __import__(package_name)
00197 package_module.__path__.insert(0, os.path.join(genConfDir, package_name))
00198 except:
00199 pass
00200 del dbLock
00201
00202
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())
00212 return 2
00213 if lst:
00214 cus[mod] = lst
00215
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
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
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
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
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)