00001
00002 """
00003 Generate _confDb.py files for ConfigurableUser classes.
00004 """
00005
00006 import os, sys, time, logging
00007 from pprint import pformat
00008 from GaudiKernel.ConfigurableDb import loadConfigurableDb, cfgDb
00009
00010 logging.VERBOSE = (logging.INFO + logging.DEBUG) / 2
00011 logging.addLevelName(logging.VERBOSE, "VERBOSE")
00012 logging.verbose = lambda msg, *args, **kwargs: \
00013 apply(logging.log, (logging.VERBOSE, msg) + args, kwargs)
00014
00015 def _inheritsfrom(derived, basename):
00016 """
00017 Check if the class name 'basename' is anywhere in the base classes of the
00018 class 'derived'.
00019 If 'derived' _is_ 'basename', returns False.
00020 """
00021 for b in derived.__bases__:
00022 if b.__name__ == basename:
00023 return True
00024 else:
00025 if _inheritsfrom(b, basename):
00026 return True
00027 return False
00028
00029 def getConfigurableUsers(modulename, root, mayNotExist = False):
00030 """
00031 Find in the module 'modulename' all the classes that derive from ConfigurableUser.
00032 Return the list of the names.
00033 The flag mayNotExist is used to choose the level of the logging message in case
00034 the requested module does not exist.
00035 """
00036
00037 oldpath = list(sys.path)
00038
00039 moduleelements = modulename.split('.')
00040 if len(moduleelements) > 1:
00041 moddir = os.sep.join([root] + moduleelements[:-1])
00042 else:
00043 moddir = root
00044
00045 shortmodname = moduleelements[-1]
00046
00047 if not os.path.exists(os.path.join(moddir, shortmodname) + ".py"):
00048 msg = "Module %s does not exist" % modulename
00049 if mayNotExist:
00050 logging.verbose(msg)
00051 else:
00052 logging.error(msg)
00053
00054 return []
00055
00056 sys.path.insert(0, moddir)
00057 logging.verbose("sys.path prepended with %r", sys.path[0])
00058
00059 logging.info("Looking for ConfigurableUser in %r", modulename)
00060 g, l = {}, {}
00061 try:
00062 logging.verbose("importing %s", shortmodname)
00063 exec "import %s as mod" % shortmodname in g, l
00064 finally:
00065
00066 logging.verbose("restoring old sys.path")
00067 sys.path = oldpath
00068 mod = l["mod"]
00069 if "__all__" in dir(mod) and mod.__all__:
00070 all = mod.__all__
00071 else:
00072 all = [ n for n in dir(mod) if not n.startswith("_")]
00073 result = []
00074 for name in all:
00075 cfg = cfgDb.get(name)
00076 if cfg and cfg["module"] != modulename:
00077
00078 logging.verbose("Object %r already found in module %r", name, cfg["module"])
00079 continue
00080 t = getattr(mod, name)
00081 if isinstance(t, type) and _inheritsfrom(t, "ConfigurableUser"):
00082 result.append(name)
00083 logging.verbose("Found %r", result)
00084 return result
00085
00086 def main():
00087 from optparse import OptionParser
00088 parser = OptionParser(prog = os.path.basename(sys.argv[0]),
00089 usage = "%prog [options] <PackageName> [<Module1> ...]")
00090 parser.add_option("-o", "--output", action="store", type="string",
00091 help="output file for confDb data [default = '../genConf/<PackageName>_user_confDb.py'].")
00092 parser.add_option("-r", "--root", action="store", type="string",
00093 help="root directory of the python modules [default = '../python'].")
00094 parser.add_option("-v", "--verbose", action="store_true",
00095 help="print some debugging information")
00096 parser.add_option("--lockerpath", action="store",
00097 metavar = "DIRNAME",
00098 help="directory where to find the module 'locker'")
00099 parser.set_defaults(root = os.path.join("..","python"))
00100
00101 opts, args = parser.parse_args()
00102
00103 if opts.verbose:
00104 log_level = logging.VERBOSE
00105 else:
00106 log_level = logging.INFO
00107 logging.basicConfig(format = "%(levelname)s: %(message)s",
00108 stream = sys.stdout,
00109 level = log_level)
00110
00111 if len(args) < 1:
00112 parser.error("PackageName is required")
00113
00114 package_name = args.pop(0)
00115
00116 usingConvention = False
00117 if not args:
00118
00119 args = [package_name + ".Configuration"]
00120 usingConvention = True
00121
00122 genConfDir = os.path.join("..", os.environ.get("CMTCONFIG", ""), "genConf")
00123 if not os.path.exists(genConfDir):
00124 genConfDir = os.path.join("..", "genConf")
00125
00126 if not opts.output:
00127 outputfile = os.path.join(genConfDir, package_name + '_user_confDb.py')
00128 else:
00129 outputfile = opts.output
00130
00131
00132
00133
00134 dbLock = None
00135 if "GAUDI_BUILD_LOCK" in os.environ:
00136 if opts.lockerpath:
00137 sys.path.append(opts.lockerpath)
00138
00139
00140 try:
00141 from locker import LockFile
00142 except ImportError:
00143 def LockFile(*args, **kwargs):
00144 return None
00145
00146 dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
00147
00148
00149
00150 try:
00151 import Gaudi.Configurables
00152 Gaudi.Configurables.ignoreMissingConfigurables = True
00153 except:
00154 pass
00155
00156 loadConfigurableDb()
00157
00158 try:
00159
00160
00161 sys.path.insert(0, genConfDir)
00162 sys.path.insert(0, os.path.join("..", "python"))
00163 localConfDb = os.path.join(genConfDir, package_name, package_name + '_confDb.py')
00164 if os.path.exists(localConfDb):
00165 execfile(localConfDb, {}, {})
00166 except:
00167 pass
00168 del dbLock
00169
00170
00171 cus = {}
00172 for mod in args:
00173 lst = None
00174 try:
00175 lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
00176 except ImportError:
00177 import traceback
00178 logging.error("Cannot import module %r:\n%s", mod,
00179 traceback.format_exc().rstrip())
00180 return 2
00181 if lst:
00182 cus[mod] = lst
00183
00184 for m in lst:
00185 cfgDb.add(configurable = m,
00186 package = 'None',
00187 module = 'None',
00188 lib = 'None')
00189 elif not usingConvention:
00190 logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
00191
00192 if cus:
00193 logging.info("ConfigurableUser found:\n%s", pformat(cus))
00194
00195 output = """## -*- python -*-
00196 # db file automatically generated by %s on: %s
00197 ## insulates outside world against anything bad that could happen
00198 ## also prevents global scope pollution
00199 def _fillCfgDb():
00200 from GaudiKernel.Proxy.ConfigurableDb import CfgDb
00201
00202 # get a handle on the repository of Configurables
00203 cfgDb = CfgDb()
00204
00205 # populate the repository with informations on Configurables
00206 """ % (parser.prog, time.asctime())
00207
00208 for mod in cus:
00209 for cu in cus[mod]:
00210 output += """
00211 cfgDb.add( configurable = '%s',
00212 package = '%s',
00213 module = '%s',
00214 lib = 'None' )""" % (cu, package_name, mod)
00215
00216
00217 output += """
00218
00219 return #_fillCfgDb
00220
00221 # fill cfgDb at module import...
00222 try:
00223 _fillCfgDb()
00224 #house cleaning...
00225 del _fillCfgDb
00226 except Exception,err:
00227 print "Py:ConfigurableDb ERROR Problem with [%%s] content!" %% __name__
00228 print "Py:ConfigurableDb ERROR",err
00229 print "Py:ConfigurableDb ERROR ==> culprit is package [%s] !"
00230 """ % package_name
00231 elif usingConvention:
00232 logging.info("No ConfigurableUser found")
00233 output = "# No ConfigurableUser specialization\n"
00234 else:
00235 logging.error("No ConfigurableUser specialization found")
00236 return 1
00237
00238
00239 output_dir = os.path.dirname(outputfile)
00240 if not os.path.exists(output_dir):
00241 logging.info("Creating directory %r", output_dir)
00242 os.makedirs(output_dir, 0755)
00243
00244
00245 logging.verbose("Writing confDb data to %r", outputfile)
00246 open(outputfile, "w").write(output)
00247 return 0
00248
00249 if __name__ == '__main__':
00250 retcode = main()
00251 sys.exit(retcode)