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