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: 7676 $"
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
63 """
64 Ensure the given directory exists, creating it if not.
65
66 @raise errors.FatalError: if the directory could not be created.
67 """
68 if not os.path.exists(directory):
69 try:
70 makedirs(directory)
71 except OSError, e:
72 from flumotion.common import errors
73 raise errors.FatalError(
74 "could not create %s directory %s: %s" % (
75 description, directory, str(e)))
76
77
79
80
81 """
82 Create a path string out of the name of a component and its parent.
83
84 @depreciated: Use @componentId instead
85 """
86 return '/%s/%s' % (parentName, componentName)
87
88
90 """
91 Create a C{componentId} based on the C{parentName} and C{componentName}.
92
93 A C{componentId} uniquely identifies a component within a planet.
94
95 @since: 0.3.1
96
97 @rtype: str
98 """
99 return '/%s/%s' % (parentName, componentName)
100
101
103 """
104 Parses a component id ("/flowName/componentName") into its parts.
105
106 @since: 0.3.1
107
108 @rtype: tuple of (str, str)
109 @return: tuple of (flowName, componentName)
110 """
111 assert componentId is not None, "componentId should not be None"
112 l = componentId.split("/")
113 assert len(l) == 3, \
114 "componentId %s should have exactly two parts" % componentId
115 assert l[0] == '', \
116 "componentId %s should start with /" % componentId
117 return (l[1], l[2])
118
119
120 -def feedId(componentName, feedName):
121 """
122 Create a C{feedId} based on the C{componentName} and C{feedName}.
123
124 A C{feedId} uniquely identifies a feed within a flow or atmosphere.
125 It identifies the feed from a feeder to an eater.
126
127 @since: 0.3.1
128
129 @rtype: str
130 """
131 return "%s:%s" % (componentName, feedName)
132
133
135 """
136 @since: 0.3.1
137
138 @rtype: tuple of (str, str)
139 @return: tuple of (componentName, feedName)
140 """
141 assert not feedId.startswith('/'), \
142 "feedId must not start with '/': %s" % feedId
143 parts = feedId.split(":")
144 assert len(parts) == 2, "feedId %s should contain exactly one ':'" % feedId
145 return (parts[0], parts[1])
146
147
148 -def fullFeedId(flowName, componentName, feedName):
149 """
150 Create a C{fullFeedId} based on the C{flowName}, C{componentName} and
151 C{feedName}.
152
153 A C{fullFeedId} uniquely identifies a feed within a planet.
154
155 @since: 0.3.1
156
157 @rtype: str
158 """
159 return feedId(componentId(flowName, componentName), feedName)
160
161
163 """
164 @since: 0.3.1
165
166 @rtype: tuple of (str, str, str)
167 @return: tuple of (flowName, componentName, feedName)
168 """
169 parts = fullFeedId.split(":")
170 assert len(parts) == 2, "%r should have exactly one colon" % fullFeedId
171 flowName, componentName = parseComponentId(parts[0])
172 return (flowName, componentName, parts[1])
173
174
176 """
177 Return a string giving the fully qualified class of the given object.
178 """
179 c = object.__class__
180 return "%s.%s" % (c.__module__, c.__name__)
181
182
184 """
185 Convert the given (relative) path to the python module it would have to
186 be imported as.
187
188 Return None if the path is not a valid python module
189 """
190
191 valid = False
192 suffixes = ['.pyc', '.pyo', '.py', os.path.sep + '__init__']
193 for s in suffixes:
194 if path.endswith(s):
195 path = path[:-len(s)]
196 valid = True
197
198
199 if not '.' in path:
200 valid = True
201
202 if not valid:
203 return None
204
205 return ".".join(path.split(os.path.sep))
206
207
209 """
210 Compares two version strings. Returns -1, 0 or 1 if first is smaller than,
211 equal to or larger than second.
212
213 @type first: str
214 @type second: str
215
216 @rtype: int
217 """
218 if first == second:
219 return 0
220
221 firsts = first.split(".")
222 seconds = second.split(".")
223
224 while firsts or seconds:
225 f = 0
226 s = 0
227 try:
228 f = int(firsts[0])
229 del firsts[0]
230 except IndexError:
231 pass
232 try:
233 s = int(seconds[0])
234 del seconds[0]
235 except IndexError:
236 pass
237
238 if f < s:
239 return -1
240 if f > s:
241 return 1
242
243 return 0
244
245
247 """Checks if two versions are compatible.
248
249 Versions are compatible if they are from the same minor release. In
250 addition, unstable (odd) releases are treated as compatible with
251 their subsequent stable (even) releases.
252
253 @param version: version to check
254 @type version: tuple of int
255 @param against: version against which we are checking. For versions
256 of core Flumotion, this may be obtained by
257 L{flumotion.configure.configure.version}.
258 @type against: tuple of int
259 @returns: True if a configuration from version is compatible with
260 against.
261 """
262 if version == against:
263 return True
264 elif version > against:
265
266
267 return False
268 elif len(version) < 2 or len(against) < 2:
269 return False
270 elif version[0] != against[0]:
271 return False
272 else:
273 round2 = lambda x: ((x + 1) // 2) * 2
274 return round2(version[1]) == round2(against[1])
275
276
278 """
279 Converts a version tuple to a string. If the tuple has a zero nano number,
280 it is dropped from the string.
281
282 @since: 0.4.1
283
284 @type versionTuple: tuple
285
286 @rtype: str
287 """
288 if len(versionTuple) == 4 and versionTuple[3] == 0:
289 versionTuple = versionTuple[:3]
290
291 return ".".join([str(i) for i in versionTuple])
292
293
295 """
296 Converts a 3- or 4-number version string to a 4-tuple.
297
298 @since: 0.5.3
299
300 @type versionString: str
301
302 @rtype: tuple of int
303 """
304 t = tuple(map(int, versionString.split('.')))
305 if len(t) < 4:
306 t = t + (0, )
307
308 return t
309
310
311 -def _uniq(l, key=lambda x: x):
312 """
313 Filters out duplicate entries in a list.
314 """
315 out = []
316 for x in l:
317 if key(x) not in [key(y) for y in out]:
318 out.append(x)
319 return out
320
321
323 mro = type(obj).__mro__
324 if not subclass_first:
325
326
327 mro = list(mro)
328 mro.reverse()
329 procs = []
330 for c in mro:
331 if hasattr(c, method):
332 proc = getattr(c, method)
333 assert callable(proc) and hasattr(proc, 'im_func'),\
334 'attr %s of class %s is not a method' % (method, c)
335 procs.append(proc)
336
337
338
339
340 return _uniq(procs, lambda proc: proc.im_func)
341
342
344 """
345 Invoke all implementations of a method on an object.
346
347 Searches for method implementations in the object's class and all of
348 the class' superclasses. Calls the methods in method resolution
349 order, which goes from subclasses to superclasses.
350 """
351 for proc in get_all_methods(obj, method, True):
352 proc(obj, *args, **kwargs)
353
354
356 """
357 Invoke all implementations of a method on an object.
358
359 Like call_each_method, but calls the methods in reverse method
360 resolution order, from superclasses to subclasses.
361 """
362 for proc in get_all_methods(obj, method, False):
363 proc(obj, *args, **kwargs)
364
365
367 """
368 A mixin class to help with object initialization.
369
370 In some class hierarchies, __init__ is only used for initializing
371 instance variables. In these cases it is advantageous to avoid the
372 need to "chain up" to a parent implementation of a method. Adding
373 this class to your hierarchy will, for each class in the object's
374 class hierarchy, call the class's init() implementation on the
375 object.
376
377 Note that the function is called init() without underscrores, and
378 that there is no need to chain up to superclasses' implementations.
379
380 Uses call_each_method_reversed() internally.
381 """
382
385
386
388 """
389 @type string: str
390
391 @return: True if the string represents a value we interpret as true.
392 """
393 if string in ('True', 'true', '1', 'yes'):
394 return True
395
396 return False
397
398
400 """Assert that twisted has support for SSL connections.
401 """
402 from twisted.internet import posixbase
403 from flumotion.common import errors
404
405 if not posixbase.sslEnabled:
406 raise errors.NoSSLError()
407
408
409
410
411
412
413
414
415