Package flumotion :: Package launch :: Module parse
[hide private]

Source Code for Module flumotion.launch.parse

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  """ 
 23  flumotion.launch.parse: A parsing library for flumotion-launch syntax. 
 24  """ 
 25   
 26  import copy 
 27  import sys 
 28   
 29  from flumotion.common import log, common, dag, registry 
 30  from flumotion.manager import config 
 31   
 32  __all__ = ['parse_args'] 
 33  __version__ = "$Rev: 7162 $" 
 34   
 35   
36 -def err(x):
37 sys.stderr.write(x + '\n') 38 raise SystemExit(1)
39 40
41 -class Component(object):
42 __slots__ = ('type', 'name', 'properties', 'plugs', 'source', 43 'clock_priority', 'config_entry', '_reg') 44
45 - def __init__(self, type, name):
46 self.type = type 47 self.name = name 48 self.properties = [] 49 self.plugs = [] 50 self.source = [] 51 52 self.config_entry = None 53 54 r = registry.getRegistry() 55 if not r.hasComponent(self.type): 56 err('Unknown component type: %s' % self.type) 57 58 self._reg = r.getComponent(self.type) 59 if self._reg.getNeedsSynchronization(): 60 self.clock_priority = self._reg.getClockPriority() 61 else: 62 self.clock_priority = None
63
64 - def complete_and_verify(self):
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
78 - def as_config_dict(self):
79 return copy.deepcopy(self.config_entry.config)
80 81
82 -class ComponentStore:
83
84 - def __init__(self):
85 self._names = {} 86 self._last_component = None 87 self.components = {} 88 assert not self # make sure that i am false if empty
89
90 - def _make_name(self, type):
91 i = self._names.get(type, 0) 92 self._names[type] = i + 1 93 return '%s%d' % (type, i)
94
95 - def add(self, type):
96 self._last_component = name = self._make_name(type) 97 self.components[name] = Component(type, name)
98
99 - def add_plug_to_current(self, type, props):
100 self[self.last()].plugs.append((type, props))
101
102 - def add_prop_to_current(self, key, val):
103 self[self.last()].properties.append((key, val))
104
105 - def last(self):
106 assert self._last_component 107 return self._last_component
108
109 - def names(self):
110 return self.components.keys()
111
113 for name in self.components: 114 self.components[name].complete_and_verify() 115 116 # hackily stolen from config.ConfigXML.parseFlow, definitely 117 # hackariffic 118 119 need_sync = [(x.clock_priority, x) for x in self.components.values() 120 if x.clock_priority] 121 need_sync.sort() 122 need_sync = [x[1] for x in need_sync] 123 124 if need_sync: 125 master = need_sync[-1] 126 for x in need_sync: 127 x.config_entry.config['clock-master'] = ( 128 master.config_entry.config['avatarId'])
129
130 - def sorted_configs(self, partial_orders):
131 sort = dag.topological_sort 132 return [self[name].as_config_dict() 133 for name in sort(self.names(), partial_orders)]
134
135 - def __getitem__(self, key):
136 return self.components[key]
137
138 - def __setitem__(self, key, val):
139 self.components[key] = val
140
141 - def __contains__(self, key):
142 return key in self.components
143
144 - def __len__(self):
145 return len(self.components)
146
147 - def __iter__(self):
148 return self.components.__iter__()
149 150
151 -class Linker:
152
153 - def __init__(self, get_last_component):
154 # links: [(feedercomponentname, feeder, 155 # eatercomponentname, eater), ...] 156 self.links = [] 157 self._tmp = None 158 self.get_last_component = get_last_component
159
160 - def pending(self):
161 return bool(self._tmp)
162 191 197 242
243 - def get_sort_order(self):
244 return [(link[0], link[2]) for link in self.get_links()]
245
246 - def dump(self):
247 for link in self.links: 248 print '%s:%s => %s:%s' % tuple(link)
249 250
251 -def parse_plug(arg):
252 plugargs = arg.split(',') 253 plug = plugargs.pop(0)[1:] 254 return plug, [parse_prop(arg) for arg in plugargs]
255 256
257 -def parse_prop(arg):
258 prop = arg[:arg.index('=')] 259 val = arg[arg.index('=')+1:] 260 if not prop or not val: 261 err('Invalid property setting: %s' % arg) 262 return prop, val
263 264
265 -def parse_arg(arg, components, linker):
266 267 def assert_in_component(msg): 268 if linker.pending() or not components: 269 err('Invalid grammar: %s' % msg)
270 271 if arg == '!': 272 if not components: 273 err('Invalid grammar: `!\' without feeder component') 274 linker.link() 275 276 elif arg[0] == '/': 277 assert_in_component('Plug %s does not follow a component' % arg) 278 plug, props = parse_plug(arg) 279 components.add_plug_to_current(plug, props) 280 281 elif arg.find('=') != -1: 282 assert_in_component('Property %s does not follow a component' % arg) 283 prop, val = parse_prop(arg) 284 components.add_prop_to_current(prop, val) 285 286 elif arg.find('.') != -1: 287 t = arg.split('.') 288 if len(t) != 2: 289 err('Invalid grammar: bad eater/feeder specification: %s' % arg) 290 t = [z or None for z in t] 291 if linker.pending(): 292 linker.link(eatercompname=t[0], eater=t[1]) 293 elif components: 294 linker.link(feedercompname=t[0] or components.last(), feeder=t[1]) 295 else: 296 err('Invalid grammar: trying to link from feeder %s but ' 297 'no feeder component' % arg) 298 299 else: 300 components.add(arg) 301 if linker.pending(): 302 linker.link(eatercompname=components.last()) 303 304
305 -def parse_args(args):
306 """Parse flumotion-launch arguments. 307 308 Parse flumotion-launch arguments, returning a list of component 309 configs. 310 311 A component config is what we will pass to a component when we 312 create it. It is a dict: 313 314 - 'name': component name 315 - 'type': component type 316 - 'properties': dict of property name => property value 317 - 'feed': list of [feeder name,...] 318 - 'source': list of [feeder name,...], (optional) 319 - 'clock-master': clock master or None 320 - 'plugs': dict of socket name => plug config 321 """ 322 323 if not args: 324 err('Usage: flumotion-launch COMPONENT [! COMPONENT]...') 325 326 components = ComponentStore() 327 328 linker = Linker(components.last) 329 330 args.reverse() # so we can pop from the tail 331 while args: 332 parse_arg(args.pop().strip(), components, linker) 333 334 feeders = linker.resolve_links(dict([(name, components[name].type) 335 for name in components])) 336 337 for compname in feeders: 338 components[compname].source = feeders[compname] 339 components.complete_and_verify_configs() 340 341 return components.sorted_configs(linker.get_sort_order())
342