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: 6125 $" 
 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 -class ComponentStore:
82 - def __init__(self):
83 self._names = {} 84 self._last_component = None 85 self.components = {} 86 assert not self # make sure that i am false if empty
87
88 - def _make_name(self, type):
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):
94 self._last_component = name = self._make_name(type) 95 self.components[name] = Component(type, name)
96
97 - def add_plug_to_current(self, type, props):
98 self[self.last()].plugs.append((type, props))
99
100 - def add_prop_to_current(self, key, val):
101 self[self.last()].properties.append((key, val))
102
103 - def last(self):
104 assert self._last_component 105 return self._last_component
106
107 - def names(self):
108 return self.components.keys()
109
111 for name in self.components: 112 self.components[name].complete_and_verify() 113 114 # hackily stolen from config.ConfigXML.parseFlow, definitely 115 # hackariffic 116 117 need_sync = [(x.clock_priority, x) for x in self.components.values() 118 if x.clock_priority] 119 need_sync.sort() 120 need_sync = [x[1] for x in need_sync] 121 122 if need_sync: 123 master = need_sync[-1] 124 for x in need_sync: 125 x.config_entry.config['clock-master'] = master.config_entry.config['avatarId']
126
127 - def sorted_configs(self, partial_orders):
128 sort = dag.topological_sort 129 return [self[name].as_config_dict() 130 for name in sort(self.names(), partial_orders)]
131
132 - def __getitem__(self, key):
133 return self.components[key]
134
135 - def __setitem__(self, key, val):
136 self.components[key] = val
137
138 - def __contains__(self, key):
139 return key in self.components
140
141 - def __len__(self):
142 return len(self.components)
143
144 - def __iter__(self):
145 return self.components.__iter__()
146
147 -class Linker:
148 - def __init__(self, get_last_component):
149 # links: [(feedercomponentname, feeder, eatercomponentname, eater), ...] 150 self.links = [] 151 self._tmp = None 152 self.get_last_component = get_last_component
153
154 - def pending(self):
155 return bool(self._tmp)
156 185 191 232
233 - def get_sort_order(self):
234 return [(link[0], link[2]) for link in self.get_links()]
235
236 - def dump(self):
237 for link in self.links: 238 print '%s:%s => %s:%s' % tuple(link)
239
240 -def parse_plug(arg):
241 plugargs = arg.split(',') 242 plug = plugargs.pop(0)[1:] 243 return plug, [parse_prop(arg) for arg in plugargs]
244
245 -def parse_prop(arg):
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
252 -def parse_arg(arg, components, linker):
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
290 -def parse_args(args):
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() # so we can pop from the tail 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