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