1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """configuration parsing utilities.
23 Base classes for parsing of flumotion configuration files
24 """
25
26 import os
27 import locale
28 import sys
29
30 from flumotion.common import log, common, registry, fxml
31 from flumotion.common.errors import ConfigError
32 from flumotion.common.fraction import fractionFromValue
33
34 __version__ = "$Rev: 6982 $"
35
37
38
39
40 if sys.version_info < (2, 4):
41 locale.setlocale(locale.LC_NUMERIC, "C")
42 def tryStr(s):
43 try:
44 return str(s)
45 except UnicodeEncodeError:
46 return s
47 def strWithoutNewlines(s):
48 return tryStr(' '.join([x.strip() for x in s.split('\n')]))
49 def boolean(v):
50 if isinstance(v, bool):
51 return v
52 return common.strToBool(v)
53
54 try:
55
56 return {'string': strWithoutNewlines,
57 'rawstring': tryStr,
58 'int': int,
59 'long': long,
60 'bool': boolean,
61 'float': float,
62 'fraction': fractionFromValue}[type](value)
63 except KeyError:
64 raise ConfigError("unknown type '%s' for property %s"
65 % (type, propName))
66 except Exception, e:
67 raise ConfigError("Error parsing property '%s': '%s' does not "
68 "appear to be a valid %s.\nDebug: %s"
69 % (propName, value, type,
70 log.getExceptionMessage(e)))
71
87
89 """Build a property dict suitable for forming part of a component
90 config.
91
92 @param propertyList: List of property name-value pairs. For example,
93 [('foo', 'bar'), ('baz', 3)] defines two
94 property-value pairs. The values will be parsed
95 into the appropriate types, this it is allowed
96 to pass the string '3' for an int value.
97 @type propertyList: List of (name, value)
98 @param propertySpecList: The set of allowed and required properties
99 @type propertySpecList: List of
100 L{flumotion.common.registry.RegistryEntryProperty}
101 """
102 ret = {}
103 prop_specs = dict([(x.name, x) for x in propertySpecList])
104 for name, value in propertyList:
105 if not name in prop_specs:
106 raise ConfigError('unknown property %s' % (name,))
107 definition = prop_specs[name]
108
109 if isinstance(definition, registry.RegistryEntryCompoundProperty):
110 parsed = parseCompoundPropertyValue(name, definition, value)
111 else:
112 if isinstance(value, (list, tuple)):
113 raise ConfigError('compound value specified where simple'
114 ' property (name=%r) expected' % (name,))
115 parsed = parsePropertyValue(name, definition.type, value)
116 if definition.multiple:
117 vals = ret.get(name, [])
118 vals.append(parsed)
119 ret[name] = vals
120 else:
121 if name in ret:
122 raise ConfigError("multiple value specified but not "
123 "allowed for property %s" % (name,))
124 ret[name] = parsed
125
126 for name, definition in prop_specs.items():
127 if definition.isRequired() and not name in ret:
128 raise ConfigError("required but unspecified property %s"
129 % (name,))
130 return ret
131
133 """Build a plugs dict suitable for forming part of a component
134 config.
135
136 @param plugsList: List of plugs, as type-propertyList pairs. For
137 example, [('frag', [('foo', 'bar')])] defines a plug
138 of type 'frag', and the propertyList representing
139 that plug's properties. The properties will be
140 validated against the plug's properties as defined
141 in the registry.
142 @type plugsList: List of (type, propertyList)
143 @param sockets: The set of allowed sockets
144 @type sockets: List of str
145 """
146 ret = {}
147 for socket in sockets:
148 ret[socket] = []
149 for plugType, propertyList in plugsList:
150 plug = ConfigEntryPlug(plugType, propertyList)
151 if plug.socket not in ret:
152 raise ConfigError("Unsupported socket type: %s"
153 % (plug.socket,))
154 ret[plug.socket].append(plug.config)
155 return ret
156
157 -class ConfigEntryPlug(log.Loggable):
158 "I represent a <plug> entry in a planet config file"
159 - def __init__(self, plugType, propertyList):
160 try:
161 defs = registry.getRegistry().getPlug(plugType)
162 except KeyError:
163 raise ConfigError("unknown plug type: %s" % plugType)
164
165 self.type = plugType
166 self.socket = defs.getSocket()
167 self.properties = buildPropertyDict(propertyList,
168 defs.getProperties())
169 self.config = {'type': self.type,
170 'socket': self.socket,
171 'entries' : self._parseEntries(defs),
172 'properties': self.properties}
173
174 - def _parseEntries(self, entries):
175 d = {}
176 for entry in entries.getEntries():
177 d[entry.getType()] = {
178 'module-name': entry.getModuleName(),
179 'function-name': entry.getFunction(),
180 }
181 return d
182
183
185 parserError = ConfigError
186
188 """
189 @param file: The file to parse, either as an open file object,
190 or as the name of a file to open.
191 @type file: str or file.
192 """
193 self.add(file)
194
195 - def add(self, file):
196 """
197 @param file: The file to parse, either as an open file object,
198 or as the name of a file to open.
199 @type file: str or file.
200 """
201 try:
202 self.path = os.path.split(file.name)[0]
203 except AttributeError:
204
205 self.path = None
206
207 try:
208 self.doc = self.getRoot(file)
209 except fxml.ParserError, e:
210 raise ConfigError(e.args[0])
211
214
216
217
218
219 self.checkAttributes(node)
220
221 plugs = []
222 def parsePlug(node):
223
224
225
226 plugType, socket = self.parseAttributes(
227 node, ('type',), ('socket',))
228 properties = []
229 parsers = {'property': (self._parseProperty, properties.append),
230 'compound-property': (self._parseCompoundProperty,
231 properties.append)}
232 self.parseFromTable(node, parsers)
233 return plugType, properties
234
235 parsers = {'plug': (parsePlug, plugs.append)}
236 self.parseFromTable(node, parsers)
237 return plugs
238
242
255