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 if not opts.output:
00123 outputfile = os.path.join("..", "genConf", package_name + '_user_confDb.py')
00124 else:
00125 outputfile = opts.output
00126
00127
00128
00129 dbLock = None
00130 if "GAUDI_BUILD_LOCK" in os.environ:
00131 if opts.lockerpath:
00132 sys.path.append(opts.lockerpath)
00133
00134
00135 try:
00136 from locker import LockFile
00137 except ImportError:
00138 def LockFile(*args, **kwargs):
00139 return None
00140
00141 dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
00142
00143
00144
00145 try:
00146 import Gaudi.Configurables
00147 Gaudi.Configurables.ignoreMissingConfigurables = True
00148 except:
00149 pass
00150
00151 loadConfigurableDb()
00152
00153 try:
00154
00155
00156 sys.path.insert(0, os.path.join("..", "genConf"))
00157 sys.path.insert(0, os.path.join("..", "python"))
00158 localConfDb = os.path.join("..", "genConf", package_name, package_name + '_confDb.py')
00159 if os.path.exists(localConfDb):
00160 execfile(localConfDb, {}, {})
00161 except:
00162 pass
00163 del dbLock
00164
00165
00166 cus = {}
00167 for mod in args:
00168 lst = None
00169 try:
00170 lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
00171 except ImportError:
00172 import traceback
00173 logging.error("Cannot import module %r:\n%s", mod,
00174 traceback.format_exc().rstrip())
00175 return 2
00176 if lst:
00177 cus[mod] = lst
00178
00179 for m in lst:
00180 cfgDb.add(configurable = m,
00181 package = 'None',
00182 module = 'None',
00183 lib = 'None')
00184 elif not usingConvention:
00185 logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
00186
00187 if cus:
00188 logging.info("ConfigurableUser found:\n%s", pformat(cus))
00189
00190 output = """## -*- python -*-
00191 # db file automatically generated by %s on: %s
00192 ## insulates outside world against anything bad that could happen
00193 ## also prevents global scope pollution
00194 def _fillCfgDb():
00195 from GaudiKernel.Proxy.ConfigurableDb import CfgDb
00196
00197 # get a handle on the repository of Configurables
00198 cfgDb = CfgDb()
00199
00200 # populate the repository with informations on Configurables
00201 """ % (parser.prog, time.asctime())
00202
00203 for mod in cus:
00204 for cu in cus[mod]:
00205 output += """
00206 cfgDb.add( configurable = '%s',
00207 package = '%s',
00208 module = '%s',
00209 lib = 'None' )""" % (cu, package_name, mod)
00210
00211
00212 output += """
00213
00214 return #_fillCfgDb
00215
00216 # fill cfgDb at module import...
00217 try:
00218 _fillCfgDb()
00219 #house cleaning...
00220 del _fillCfgDb
00221 except Exception,err:
00222 print "Py:ConfigurableDb ERROR Problem with [%%s] content!" %% __name__
00223 print "Py:ConfigurableDb ERROR",err
00224 print "Py:ConfigurableDb ERROR ==> culprit is package [%s] !"
00225 """ % package_name
00226 elif usingConvention:
00227 logging.info("No ConfigurableUser found")
00228 output = "# No ConfigurableUser specialization\n"
00229 else:
00230 logging.error("No ConfigurableUser specialization found")
00231 return 1
00232
00233
00234 output_dir = os.path.dirname(outputfile)
00235 if not os.path.exists(output_dir):
00236 logging.info("Creating directory %r", output_dir)
00237 os.makedirs(output_dir, 0755)
00238
00239
00240 logging.verbose("Writing confDb data to %r", outputfile)
00241 open(outputfile, "w").write(output)
00242 return 0
00243
00244 if __name__ == '__main__':
00245 retcode = main()
00246 sys.exit(retcode)