ConfigurableDb.py 6.05 KB
Newer Older
marcocle's avatar
marcocle committed
1
2
3
4
5
6
7
8
# File: AthenaCommon/python/ConfigurableDb.py
# Author: Sebastien Binet (binet@cern.ch)
"""A singleton holding informations on the whereabouts of all the automatically
generated Configurables.
This repository of (informations on) Configurables is used by the PropertyProxy
class to locate Configurables and feed the JobOptionsSvc. It could also be used
to feed the AthenaEmacs module..."""

Marco Clemencic's avatar
Marco Clemencic committed
9
__all__ = ['CfgDb', 'cfgDb', 'loadConfigurableDb', 'getConfigurable']
marcocle's avatar
marcocle committed
10
11
12
13
14

import string
_transtable = string.maketrans('<>&*,: ().', '__rp__s___')

import logging
Marco Clemencic's avatar
Marco Clemencic committed
15
log = logging.getLogger('ConfigurableDb')
marcocle's avatar
marcocle committed
16

Marco Clemencic's avatar
Marco Clemencic committed
17
18

class _CfgDb(dict):
marcocle's avatar
marcocle committed
19
20
21
22
23
24
25
26
27
28
    """
    A singleton class holding informations about automatically generated
    Configurables.
     --> package holding that Configurable
     --> library holding the components related to that Configurable
     --> python module holding the Configurable
     --> a dictionary of duplicates
    """

    __slots__ = {
Marco Clemencic's avatar
Marco Clemencic committed
29
30
        '_duplicates': {},
    }
marcocle's avatar
marcocle committed
31
32
33
34
35

    def __init__(self):
        object.__init__(self)
        self._duplicates = {}

Marco Clemencic's avatar
Marco Clemencic committed
36
    def add(self, configurable, package, module, lib):
marcocle's avatar
marcocle committed
37
38
39
40
41
42
43
44
        """Method to populate the Db.
        It is called from the auto-generated Xyz_confDb.py files (genconf.cpp)
        @param configurable: the name of the configurable being added
        @param package: the name of the package which holds this Configurable
        @param module: the name of the python module holding the Configurable
        @param lib: the name of the library holding the component(s) (ie: the
                    C++ Gaudi component which is mapped by the Configurable)
        """
Gitlab CI's avatar
Gitlab CI committed
45
        cfg = {'package': package, 'module': module, 'lib': lib}
Marco Clemencic's avatar
Marco Clemencic committed
46
47
        if self.has_key(configurable):
            # check if it comes from the same library...
marcocle's avatar
marcocle committed
48
            if cfg['lib'] != self[configurable]['lib']:
Gitlab CI's avatar
Gitlab CI committed
49
50
                log.debug("dup!! [%s] p=%s m=%s lib=%s", configurable, package,
                          module, lib)
marcocle's avatar
marcocle committed
51
                if self._duplicates.has_key(configurable):
Marco Clemencic's avatar
Marco Clemencic committed
52
                    self._duplicates[configurable] += [cfg]
marcocle's avatar
marcocle committed
53
                else:
Marco Clemencic's avatar
Marco Clemencic committed
54
                    self._duplicates[configurable] = [cfg]
marcocle's avatar
marcocle committed
55
        else:
Gitlab CI's avatar
Gitlab CI committed
56
57
            log.debug("added [%s] p=%s m=%s lib=%s", configurable, package,
                      module, lib)
marcocle's avatar
marcocle committed
58
59
60
61
62
            self[configurable] = cfg

    def duplicates(self):
        return self._duplicates

63
64
    def _loadModule(self, fname):
        f = open(fname)
Marco Clemencic's avatar
Marco Clemencic committed
65
        for i, ll in enumerate(f):
66
67
68
69
70
71
72
73
74
75
76
77
78
            l = ll.strip()
            if l.startswith('#') or len(l) <= 0:
                continue
            try:
                line = l.split()
                cname = line[2]
                pkg = line[0].split('.')[0]
                module = line[0]
                lib = line[1]
                self.add(cname, pkg, module, lib)
            except Exception:
                f.close()
                raise Exception(
Gitlab CI's avatar
Gitlab CI committed
79
                    "invalid line format: %s:%d: %r" % (fname, i + 1, ll))
80
81
        f.close()

marcocle's avatar
marcocle committed
82

Marco Clemencic's avatar
Marco Clemencic committed
83
class _Singleton(object):
marcocle's avatar
marcocle committed
84

Marco Clemencic's avatar
Marco Clemencic committed
85
86
    # the object this singleton is holding
    # No other object will be created...
marcocle's avatar
marcocle committed
87
88
    __obj = _CfgDb()

Marco Clemencic's avatar
Marco Clemencic committed
89
    def __call__(self):
marcocle's avatar
marcocle committed
90
91
        return self.__obj

Marco Clemencic's avatar
Marco Clemencic committed
92

marcocle's avatar
marcocle committed
93
94
95
96
97
98
CfgDb = _Singleton()

# clean-up
del _Singleton
del _CfgDb

Marco Clemencic's avatar
Marco Clemencic committed
99
# default name for CfgDb instance
marcocle's avatar
marcocle committed
100
101
cfgDb = CfgDb()

Marco Clemencic's avatar
Marco Clemencic committed
102
103
104
# Helper function to load all ConfigurableDb files holding informations


marcocle's avatar
marcocle committed
105
106
107
108
109
110
111
112
def loadConfigurableDb():
    """Helper function to load all ConfigurableDb files (modules) holding
    informations about Configurables
    """
    import os
    import sys
    from glob import glob
    from os.path import join as path_join
Marco Clemencic's avatar
Marco Clemencic committed
113
114
    log.debug("loading confDb files...")
    nFiles = 0  # counter of imported files
115
116
117
118
    if sys.platform == 'darwin':
        pathlist = os.getenv("DYLD_LIBRARY_PATH", "").split(os.pathsep)
    else:
        pathlist = os.getenv("LD_LIBRARY_PATH", "").split(os.pathsep)
119
    for path in pathlist:
120
        if not os.path.isdir(path):
marcocle's avatar
marcocle committed
121
            continue
Marco Clemencic's avatar
Marco Clemencic committed
122
        log.debug("walking in [%s]...", path)
Gitlab CI's avatar
Gitlab CI committed
123
124
125
126
127
128
        confDbFiles = [
            f for f in [
                path_join(path, f) for f in os.listdir(path)
                if f.endswith('.confdb')
            ] if os.path.isfile(f)
        ]
129
        # check if we use "*_merged.confdb"
Gitlab CI's avatar
Gitlab CI committed
130
131
132
        mergedConfDbFiles = [
            f for f in confDbFiles if f.endswith('_merged.confdb')
        ]
133
134
135
136
        if mergedConfDbFiles:
            # use only the merged ones
            confDbFiles = mergedConfDbFiles

137
        for confDb in confDbFiles:
Marco Clemencic's avatar
Marco Clemencic committed
138
            log.debug("\t-loading [%s]...", confDb)
marcocle's avatar
marcocle committed
139
            try:
Marco Clemencic's avatar
Marco Clemencic committed
140
                cfgDb._loadModule(confDb)
141
            except Exception as err:
Marco Clemencic's avatar
Marco Clemencic committed
142
143
                log.warning("Could not load file [%s] !", confDb)
                log.warning("Reason: %s", err)
144
            nFiles += 1
Marco Clemencic's avatar
Marco Clemencic committed
145
146
147
    log.debug("loading confDb files... [DONE]")
    nPkgs = len(set([k['package'] for k in cfgDb.values()]))
    log.debug("loaded %i confDb packages", nPkgs)
marcocle's avatar
marcocle committed
148
149
150
    return nFiles


Marco Clemencic's avatar
Marco Clemencic committed
151
152
def getConfigurable(className, requester='', assumeCxxClass=True):
    confClass = className
marcocle's avatar
marcocle committed
153
154
    if assumeCxxClass:
        # assume className is C++: --> translate to python
Marco Clemencic's avatar
Marco Clemencic committed
155
        confClass = string.translate(confClass, _transtable)
marcocle's avatar
marcocle committed
156
157
158
159
160
161
162
    # see if I have it in my dictionary
    confClassInfo = cfgDb.get(confClass)
    if not confClassInfo:
        confClassInfo = cfgDb.get(confClass)
    # get the python module
    confMod = confClassInfo and confClassInfo.get('module')
    if not confMod:
Marco Clemencic's avatar
Marco Clemencic committed
163
        log.warning("%s: Class %s not in database", requester, className)
marcocle's avatar
marcocle committed
164
165
166
        return None
    # load the module
    try:
Marco Clemencic's avatar
Marco Clemencic committed
167
        mod = __import__(confMod, globals(), locals(), confClass)
marcocle's avatar
marcocle committed
168
    except ImportError:
Marco Clemencic's avatar
Marco Clemencic committed
169
170
        log.warning("%s: Module %s not found (needed for configurable %s)",
                    requester, confMod, className)
marcocle's avatar
marcocle committed
171
172
173
        return None
    # get the class
    try:
Marco Clemencic's avatar
Marco Clemencic committed
174
        confClass = getattr(mod, confClass)
marcocle's avatar
marcocle committed
175
    except AttributeError:
Gitlab CI's avatar
Gitlab CI committed
176
177
        log.warning("%s: Configurable %s not found in module %s", requester,
                    confClass, confMod)
marcocle's avatar
marcocle committed
178
179
        return None
    # Got it!
Gitlab CI's avatar
Gitlab CI committed
180
181
    log.debug("%s: Found configurable %s in module %s", requester, confClass,
              confMod)
marcocle's avatar
marcocle committed
182
183

    return confClass