1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """
19 small common functions used by all processes
20 """
21
22
23
24
25
26
27
28
29
30
31
32 import os
33
34
35
36
37 from flumotion.common.python import makedirs
38 from flumotion.configure import configure
39
40 __version__ = "$Rev$"
41
42
44 """
45 Print a version block for the flumotion binaries.
46
47 @arg binary: name of the binary
48 @type binary: string
49 """
50
51 block = []
52 block.append("%s %s" % (binary, configure.version))
53 block.append("part of Flumotion - a streaming media server")
54 block.append("(C) Copyright 2004,2005,2006,2007,2008,2009 Fluendo, S.L.")
55 block.append("(C) Copyright 2010,2011 Flumotion Services, S.A.")
56
57 return "\n".join(block)
58
59
74
75
77 """
78 Create a C{componentId} based on the C{parentName} and C{componentName}.
79
80 A C{componentId} uniquely identifies a component within a planet.
81
82 @since: 0.3.1
83
84 @rtype: str
85 """
86 return '/%s/%s' % (parentName, componentName)
87
88
90 """
91 Parses a component id ("/flowName/componentName") into its parts.
92
93 @since: 0.3.1
94
95 @rtype: tuple of (str, str)
96 @return: tuple of (flowName, componentName)
97 """
98 assert componentId is not None, "componentId should not be None"
99 l = componentId.split("/")
100 assert len(l) == 3, \
101 "componentId %s should have exactly two parts" % componentId
102 assert l[0] == '', \
103 "componentId %s should start with /" % componentId
104 return (l[1], l[2])
105
106
107 -def feedId(componentName, feedName):
108 """
109 Create a C{feedId} based on the C{componentName} and C{feedName}.
110
111 A C{feedId} uniquely identifies a feed within a flow or atmosphere.
112 It identifies the feed from a feeder to an eater.
113
114 @since: 0.3.1
115
116 @rtype: str
117 """
118 return "%s:%s" % (componentName, feedName)
119
120
122 """
123 @since: 0.3.1
124
125 @rtype: tuple of (str, str)
126 @return: tuple of (componentName, feedName)
127 """
128 assert not feedId.startswith('/'), \
129 "feedId must not start with '/': %s" % feedId
130 parts = feedId.split(":")
131 assert len(parts) == 2, "feedId %s should contain exactly one ':'" % feedId
132 return (parts[0], parts[1])
133
134
135 -def fullFeedId(flowName, componentName, feedName):
136 """
137 Create a C{fullFeedId} based on the C{flowName}, C{componentName} and
138 C{feedName}.
139
140 A C{fullFeedId} uniquely identifies a feed within a planet.
141
142 @since: 0.3.1
143
144 @rtype: str
145 """
146 return feedId(componentId(flowName, componentName), feedName)
147
148
150 """
151 @since: 0.3.1
152
153 @rtype: tuple of (str, str, str)
154 @return: tuple of (flowName, componentName, feedName)
155 """
156 parts = fullFeedId.split(":")
157 assert len(parts) == 2, "%r should have exactly one colon" % fullFeedId
158 flowName, componentName = parseComponentId(parts[0])
159 return (flowName, componentName, parts[1])
160
161
163 """
164 Return a string giving the fully qualified class of the given object.
165 """
166 c = object.__class__
167 return "%s.%s" % (c.__module__, c.__name__)
168
169
171 """
172 Convert the given (relative) path to the python module it would have to
173 be imported as.
174
175 Return None if the path is not a valid python module
176 """
177
178 valid = False
179 suffixes = ['.pyc', '.pyo', '.py', os.path.sep + '__init__']
180 for s in suffixes:
181 if path.endswith(s):
182 path = path[:-len(s)]
183 valid = True
184
185
186 if not '.' in path:
187 valid = True
188
189 if not valid:
190 return None
191
192 return ".".join(path.split(os.path.sep))
193
194
196 """
197 Compares two version strings. Returns -1, 0 or 1 if first is smaller than,
198 equal to or larger than second.
199
200 @type first: str
201 @type second: str
202
203 @rtype: int
204 """
205 if first == second:
206 return 0
207
208 firsts = first.split(".")
209 seconds = second.split(".")
210
211 while firsts or seconds:
212 f = 0
213 s = 0
214 try:
215 f = int(firsts[0])
216 del firsts[0]
217 except IndexError:
218 pass
219 try:
220 s = int(seconds[0])
221 del seconds[0]
222 except IndexError:
223 pass
224
225 if f < s:
226 return -1
227 if f > s:
228 return 1
229
230 return 0
231
232
234 """Checks if two versions are compatible.
235
236 Versions are compatible if they are from the same minor release. In
237 addition, unstable (odd) releases are treated as compatible with
238 their subsequent stable (even) releases.
239
240 @param version: version to check
241 @type version: tuple of int
242 @param against: version against which we are checking. For versions
243 of core Flumotion, this may be obtained by
244 L{flumotion.configure.configure.version}.
245 @type against: tuple of int
246 @returns: True if a configuration from version is compatible with
247 against.
248 """
249 if version == against:
250 return True
251 elif version > against:
252
253
254 return False
255 elif len(version) < 2 or len(against) < 2:
256 return False
257 elif version[0] != against[0]:
258 return False
259 else:
260 round2 = lambda x: ((x + 1) // 2) * 2
261 return round2(version[1]) == round2(against[1])
262
263
265 """
266 Converts a version tuple to a string. If the tuple has a zero nano number,
267 it is dropped from the string.
268
269 @since: 0.4.1
270
271 @type versionTuple: tuple
272
273 @rtype: str
274 """
275 if len(versionTuple) == 4 and versionTuple[3] == 0:
276 versionTuple = versionTuple[:3]
277
278 return ".".join([str(i) for i in versionTuple])
279
280
282 """
283 Converts a 3- or 4-number version string to a 4-tuple.
284
285 @since: 0.5.3
286
287 @type versionString: str
288
289 @rtype: tuple of int
290 """
291 versionString = versionString.split('-')[0]
292 t = tuple(map(int, versionString.split('.')))
293 if len(t) < 4:
294 t = t + (0, )
295
296 return t
297
298
299 -def _uniq(l, key=lambda x: x):
300 """
301 Filters out duplicate entries in a list.
302 """
303 out = []
304 for x in l:
305 if key(x) not in [key(y) for y in out]:
306 out.append(x)
307 return out
308
309
311 mro = type(obj).__mro__
312 if not subclass_first:
313
314
315 mro = list(mro)
316 mro.reverse()
317 procs = []
318 for c in mro:
319 if hasattr(c, method):
320 proc = getattr(c, method)
321 assert callable(proc) and hasattr(proc, 'im_func'),\
322 'attr %s of class %s is not a method' % (method, c)
323 procs.append(proc)
324
325
326
327
328 return _uniq(procs, lambda proc: proc.im_func)
329
330
332 """
333 Invoke all implementations of a method on an object.
334
335 Searches for method implementations in the object's class and all of
336 the class' superclasses. Calls the methods in method resolution
337 order, which goes from subclasses to superclasses.
338 """
339 for proc in get_all_methods(obj, method, True):
340 proc(obj, *args, **kwargs)
341
342
344 """
345 Invoke all implementations of a method on an object.
346
347 Like call_each_method, but calls the methods in reverse method
348 resolution order, from superclasses to subclasses.
349 """
350 for proc in get_all_methods(obj, method, False):
351 proc(obj, *args, **kwargs)
352
353
355 """
356 A mixin class to help with object initialization.
357
358 In some class hierarchies, __init__ is only used for initializing
359 instance variables. In these cases it is advantageous to avoid the
360 need to "chain up" to a parent implementation of a method. Adding
361 this class to your hierarchy will, for each class in the object's
362 class hierarchy, call the class's init() implementation on the
363 object.
364
365 Note that the function is called init() without underscrores, and
366 that there is no need to chain up to superclasses' implementations.
367
368 Uses call_each_method_reversed() internally.
369 """
370
373
374
376 """
377 @type string: str
378
379 @return: True if the string represents a value we interpret as true.
380 """
381 if string in ('True', 'true', '1', 'yes'):
382 return True
383
384 return False
385
386
388 """Assert that twisted has support for SSL connections.
389 """
390 from twisted.internet import posixbase
391 from flumotion.common import errors
392
393 if not posixbase.sslEnabled:
394 raise errors.NoSSLError()
395
396
397
398
399
400
401
402
403