| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
10 import GaudiKernel.ConfigurableDb
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
35 def loadConfigurableDb():
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)
52 GaudiKernel.ConfigurableDb.loadConfigurableDb()
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
185 loadConfigurableDb()
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)