Gaudi Framework, version v25r2

Home   Generated: Wed Jun 4 2014
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
genconfuser.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 Generate _confDb.py files for ConfigurableUser classes.
4 """
5 
6 import os
7 import sys
8 import time
9 import logging
11 
12 from pprint import pformat
13 from glob import glob
14 from GaudiKernel.ConfigurableDb import cfgDb
15 
16 logging.VERBOSE = (logging.INFO + logging.DEBUG) / 2
17 logging.addLevelName(logging.VERBOSE, "VERBOSE")
18 logging.verbose = lambda msg, *args, **kwargs: \
19  apply(logging.log, (logging.VERBOSE, msg) + args, kwargs)
20 
21 def _inheritsfrom(derived, basename):
22  """
23  Check if the class name 'basename' is anywhere in the base classes of the
24  class 'derived'.
25  If 'derived' _is_ 'basename', returns False.
26  """
27  for b in derived.__bases__:
28  if b.__name__ == basename:
29  return True
30  else:
31  if _inheritsfrom(b, basename):
32  return True
33  return False
34 
36  '''
37  Equivalent to GaudiKernel.ConfigurableDb.loadConfigurableDb(), but does a
38  deep search and executes the '*_confDb.py' files instead of importing them.
39  '''
40  # find the '*_confDb.py' files that are not merged ones
41  for p in sys.path:
42  for f in [f for f in glob(os.path.join(p, '*', '*_confDb.py'))
43  if 'merged' not in f and os.path.isfile(f)]:
44  logging.verbose('Loading %s', f)
45  try:
46  execfile(f, {}, {})
47  except:
48  # It may happen that the file is found but not completely
49  # written, usually during parallel builds, but we do not care.
50  pass
51  # top up with the regular merged confDb (for the used projects)
53 
54 def getConfigurableUsers(modulename, root, mayNotExist = False):
55  """
56  Find in the module 'modulename' all the classes that derive from ConfigurableUser.
57  Return the list of the names.
58  The flag mayNotExist is used to choose the level of the logging message in case
59  the requested module does not exist.
60  """
61  # remember the old system path
62  oldpath = list(sys.path)
63  # we need to hack the sys.path to add the first part of the module name after root
64  moduleelements = modulename.split('.')
65  if len(moduleelements) > 1:
66  moddir = os.sep.join([root] + moduleelements[:-1])
67  else:
68  moddir = root
69  # this is the name of the submodule to import
70  shortmodname = moduleelements[-1]
71  # check if the module file actually exists
72  if not os.path.exists(os.path.join(moddir, shortmodname) + ".py"):
73  msg = "Module %s does not exist" % modulename
74  if mayNotExist:
75  logging.verbose(msg)
76  else:
77  logging.error(msg)
78  # no file -> do not try to import
79  return []
80  # prepend moddir to the path
81  sys.path.insert(0, moddir)
82  logging.verbose("sys.path prepended with %r", sys.path[0])
83 
84  logging.info("Looking for ConfigurableUser in %r", modulename)
85  g, l = {}, {}
86  try:
87  logging.verbose("importing %s", shortmodname)
88  exec "import %s as mod" % shortmodname in g, l
89  finally:
90  # restore old sys.path
91  logging.verbose("restoring old sys.path")
92  sys.path = oldpath
93  mod = l["mod"]
94  if "__all__" in dir(mod) and mod.__all__:
95  all = mod.__all__
96  else:
97  all = [ n for n in dir(mod) if not n.startswith("_")]
98  result = []
99  for name in all:
100  cfg = cfgDb.get(name)
101  if cfg and cfg["module"] != modulename:
102  # This name comes from another module
103  logging.verbose("Object %r already found in module %r", name, cfg["module"])
104  continue
105  t = getattr(mod, name)
106  if isinstance(t, type) and _inheritsfrom(t, "ConfigurableUser"):
107  result.append(name)
108  logging.verbose("Found %r", result)
109  return result
110 
111 def main():
112  from optparse import OptionParser
113  parser = OptionParser(prog = os.path.basename(sys.argv[0]),
114  usage = "%prog [options] <PackageName> [<Module1> ...]")
115  parser.add_option("-o", "--output", action="store", type="string",
116  help="output file for confDb data [default = '../genConf/<PackageName>_user_confDb.py'].")
117  parser.add_option("-r", "--root", action="store", type="string",
118  help="root directory of the python modules [default = '../python'].")
119  parser.add_option("-v", "--verbose", action="store_true",
120  help="print some debugging information")
121  parser.add_option("--debug", action="store_true",
122  help="print more debugging information")
123  parser.add_option("--lockerpath", action="store",
124  metavar = "DIRNAME",
125  help="directory where to find the module 'locker'")
126  parser.set_defaults(root = os.path.join("..","python"))
127 
128  opts, args = parser.parse_args()
129 
130  if opts.debug:
131  log_level = logging.DEBUG
132  elif opts.verbose:
133  log_level = logging.VERBOSE
134  else:
135  log_level = logging.INFO
136  logging.basicConfig(format = "%(levelname)s: %(message)s",
137  stream = sys.stdout,
138  level = log_level)
139 
140  if len(args) < 1:
141  parser.error("PackageName is required")
142 
143  package_name = args.pop(0)
144 
145  usingConvention = False
146  if not args:
147  # use the conventional module name <package>.Configuration
148  args = [package_name + ".Configuration"]
149  usingConvention = True
150 
151  genConfDir = os.path.join("..", os.environ.get("CMTCONFIG", ""), "genConf")
152  if not os.path.exists(genConfDir):
153  genConfDir = os.path.join("..", "genConf")
154 
155  if not opts.output:
156  outputfile = os.path.join(genConfDir, package_name + '_user_confDb.py')
157  else:
158  outputfile = opts.output
159 
160 
161  # The locking ensures that nobody tries to modify the python.zip file while
162  # we read it.
163  dbLock = None
164  if "GAUDI_BUILD_LOCK" in os.environ:
165  if opts.lockerpath:
166  sys.path.append(opts.lockerpath)
167  # Get the LockFile class from the locker module in GaudiPolicy or use a fake
168  # factory.
169  try:
170  from locker import LockFile
171  except ImportError:
172  def LockFile(*args, **kwargs):
173  return None
174  # obtain the lock
175  dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
176 
177  # We can disable the error on missing configurables only if we can import Gaudi.Configurables
178  # It must be done at this point because it may conflict with logging.basicConfig
179  try:
180  import Gaudi.Configurables
181  Gaudi.Configurables.ignoreMissingConfigurables = True
182  except:
183  pass
184  # load configurables database to avoid fake duplicates
186  # ensure that local configurables are in the database
187  try:
188  # Add the local python directories to the python path to be able to import the local
189  # configurables
190  sys.path.insert(0, genConfDir)
191  sys.path.insert(0, os.path.join("..", "python"))
192  localConfDb = os.path.join(genConfDir, package_name, package_name + '_confDb.py')
193  if os.path.exists(localConfDb):
194  execfile(localConfDb, {}, {})
195  # Extend the search path of the package module to find the configurables
196  package_module = __import__(package_name)
197  package_module.__path__.insert(0, os.path.join(genConfDir, package_name))
198  except:
199  pass # ignore failures (not important)
200  del dbLock # Now we can let the others operate on the install area python directory
201 
202  # Collecting ConfigurableUser specializations
203  cus = {}
204  for mod in args:
205  lst = None
206  try:
207  lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
208  except ImportError:
209  import traceback
210  logging.error("Cannot import module %r:\n%s", mod,
211  traceback.format_exc().rstrip()) # I remove the trailing '\n'
212  return 2
213  if lst:
214  cus[mod] = lst
215  # Add the configurables to the database as fake entries to avoid duplicates
216  for m in lst:
217  cfgDb.add(configurable = m,
218  package = 'None',
219  module = 'None',
220  lib = 'None')
221  elif not usingConvention:
222  logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
223 
224  if cus:
225  logging.info("ConfigurableUser found:\n%s", pformat(cus))
226  # header
227  output = """## -*- python -*-
228 # db file automatically generated by %s on: %s
229 ## insulates outside world against anything bad that could happen
230 ## also prevents global scope pollution
231 def _fillCfgDb():
232  from GaudiKernel.Proxy.ConfigurableDb import CfgDb
233 
234  # get a handle on the repository of Configurables
235  cfgDb = CfgDb()
236 
237  # populate the repository with informations on Configurables
238 """ % (parser.prog, time.asctime())
239 
240  for mod in cus:
241  for cu in cus[mod]:
242  output += """
243  cfgDb.add( configurable = '%s',
244  package = '%s',
245  module = '%s',
246  lib = 'None' )""" % (cu, package_name, mod)
247 
248  # trailer
249  output += """
250 
251  return #_fillCfgDb
252 
253 # fill cfgDb at module import...
254 try:
255  _fillCfgDb()
256  #house cleaning...
257  del _fillCfgDb
258 except Exception,err:
259  print "Py:ConfigurableDb ERROR Problem with [%%s] content!" %% __name__
260  print "Py:ConfigurableDb ERROR",err
261  print "Py:ConfigurableDb ERROR ==> culprit is package [%s] !"
262 """ % package_name
263  elif usingConvention:
264  logging.info("No ConfigurableUser found")
265  output = ("# db file automatically generated by %s on: %s\n"
266  "# No ConfigurableUser specialization in %s\n") % (parser.prog, time.asctime(), package_name)
267  else:
268  logging.error("No ConfigurableUser specialization found")
269  return 1
270 
271  # create the destination directory if not there
272  output_dir = os.path.dirname(outputfile)
273  if not os.path.exists(output_dir):
274  logging.info("Creating directory %r", output_dir)
275  os.makedirs(output_dir, 0755)
276 
277  # write output to file
278  logging.verbose("Writing confDb data to %r", outputfile)
279  open(outputfile, "w").write(output)
280  return 0
281 
282 if __name__ == '__main__':
283  retcode = main()
284  sys.exit(retcode)

Generated at Wed Jun 4 2014 14:48:57 for Gaudi Framework, version v25r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004