1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """
24 flumotion.launch.parse: A parsing library for flumotion-launch syntax.
25 """
26
27
28 import copy
29 import sys
30
31 from flumotion.common import log, config, common, dag, registry
32
33 __all__ = ['parse_args']
34
35
37 sys.stderr.write(x + '\n')
38 raise SystemExit(1)
39
40
42 __slots__ = ('type', 'name', 'properties', 'plugs', 'source',
43 'clock_priority', 'config_entry', '_reg')
44
63
65 self.config_entry = config.ConfigEntryComponent(
66 self.name,
67 None,
68 self.type,
69 None,
70 self.properties,
71 self.plugs,
72 None,
73 [(None, feedId) for feedId in self.source],
74 None,
75 None,
76 None)
77
80
83 self._names = {}
84 self._last_component = None
85 self.components = {}
86 assert not self
87
89 i = self._names.get(type, 0)
90 self._names[type] = i + 1
91 return '%s%d' % (type, i)
92
93 - def add(self, type):
96
99
102
104 assert self._last_component
105 return self._last_component
106
108 return self.components.keys()
109
126
131
133 return self.components[key]
134
136 self.components[key] = val
137
139 return key in self.components
140
142 return len(self.components)
143
146
148 - def __init__(self, get_last_component):
149
150 self.links = []
151 self._tmp = None
152 self.get_last_component = get_last_component
153
155 return bool(self._tmp)
156
157 - def link(self, feedercompname=None, feeder=None, eatercompname=None,
158 eater=None):
159 if feedercompname:
160 assert not self._tmp
161 self._tmp = [feedercompname, feeder, eatercompname, eater]
162 elif feeder:
163 err('how did i get here?')
164 elif eatercompname:
165 if not self._tmp:
166 err('Invalid grammar: trying to link, but no feeder component')
167 self._tmp[2] = eatercompname
168 if eater:
169 self._tmp[3] = eater
170 elif eater:
171 if not self._tmp:
172 err('Invalid grammar: trying to link, but no feeder component')
173 self._tmp[3] = eater
174 else:
175
176 if not self._tmp:
177 self._tmp = [self.get_last_component(), None, None, None]
178 else:
179 if not self._tmp[0]:
180 self._tmp[0] = self.get_last_component()
181
182 if self._tmp and self._tmp[0] and self._tmp[2]:
183 self.links.append(self._tmp)
184 self._tmp = None
185
187 if self._tmp:
188 err('Invalid grammar: uncompleted link from %s.%s' % self._tmp[:2])
189 else:
190 return self.links
191
193 for link in self.get_links():
194 assert link[0] and link[2]
195 if not link[0] in component_types:
196 err('Invalid grammar: no feeder component %s to link from' % link[0])
197 if not link[2] in component_types:
198 err('Invalid grammar: no eater component %s to link to' % link[2])
199
200 reg = registry.getRegistry()
201 for link in self.get_links():
202 compname = link[0]
203 comptype = component_types[compname]
204 compreg = reg.getComponent(comptype)
205 if link[1]:
206 if not link[1] in compreg.getFeeders():
207 err('Component %s has no feeder named %s' % (compname, link[1]))
208
209 else:
210 if not compreg.getFeeders():
211 err('Component %s has no feeders' % compname)
212 link[1] = compreg.getFeeders()[0]
213
214 for link in self.get_links():
215 compname = link[2]
216 comptype = component_types[compname]
217 compreg = reg.getComponent(comptype)
218 eaters = compreg.getEaters()
219 if link[3]:
220 if not link[3] in [x.getName() for x in eaters]:
221 err('Component %s has no eater named %s' % (compname, link[3]))
222
223 else:
224 if not eaters:
225 err('Component %s has no eaters' % compname)
226 link[3] = eaters[0].getName()
227
228 feeders = dict([(name, []) for name in component_types])
229 for link in self.get_links():
230 feeders[link[2]].append('%s:%s' % (link[0], link[1]))
231 return feeders
232
235
237 for link in self.links:
238 print '%s:%s => %s:%s' % tuple(link)
239
241 plugargs = arg.split(',')
242 plug = plugargs.pop(0)[1:]
243 return plug, [parse_prop(arg) for arg in plugargs]
244
246 prop = arg[:arg.index('=')]
247 val = arg[arg.index('=')+1:]
248 if not prop or not val:
249 err('Invalid property setting: %s' % arg)
250 return prop, val
251
253 def assert_in_component(msg):
254 if linker.pending() or not components:
255 err('Invalid grammar: %s' % msg)
256
257 if arg == '!':
258 if not components:
259 err('Invalid grammar: `!\' without feeder component')
260 linker.link()
261
262 elif arg[0] == '/':
263 assert_in_component('Plug %s does not follow a component' % arg)
264 plug, props = parse_plug(arg)
265 components.add_plug_to_current(plug, props)
266
267 elif arg.find('=') != -1:
268 assert_in_component('Property %s does not follow a component' % arg)
269 prop, val = parse_prop(arg)
270 components.add_prop_to_current(prop, val)
271
272 elif arg.find('.') != -1:
273 t = arg.split('.')
274 if len(t) != 2:
275 err('Invalid grammar: bad eater/feeder specification: %s' % arg)
276 t = [z or None for z in t]
277 if linker.pending():
278 linker.link(eatercompname=t[0], eater=t[1])
279 elif components:
280 linker.link(feedercompname=t[0] or components.last(), feeder=t[1])
281 else:
282 err('Invalid grammar: trying to link from feeder %s but '
283 'no feeder component' % arg)
284
285 else:
286 components.add(arg)
287 if linker.pending():
288 linker.link(eatercompname=components.last())
289
291 """Parse flumotion-launch arguments.
292
293 Parse flumotion-launch arguments, returning a list of component
294 configs.
295
296 A component config is what we will pass to a component when we
297 create it. It is a dict:
298
299 - 'name': component name
300 - 'type': component type
301 - 'properties': dict of property name => property value
302 - 'feed': list of [feeder name,...]
303 - 'source': list of [feeder name,...], (optional)
304 - 'clock-master': clock master or None
305 - 'plugs': dict of socket name => plug config
306 """
307
308 if not args:
309 err('Usage: flumotion-launch COMPONENT [! COMPONENT]...')
310
311 components = ComponentStore()
312
313 linker = Linker(components.last)
314
315 args.reverse()
316 while args:
317 parse_arg(args.pop().strip(), components, linker)
318
319 feeders = linker.resolve_links(dict([(name, components[name].type)
320 for name in components]))
321
322 for compname in feeders:
323 components[compname].source = feeders[compname]
324 components.complete_and_verify_configs()
325
326 return components.sorted_configs(linker.get_sort_order())
327