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