Package flumotion :: Package common :: Module common
[hide private]

Source Code for Module flumotion.common.common

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_common -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008 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  small common functions used by all processes 
 24  """ 
 25   
 26  # 
 27  # FIXME: Everything here should be removed and be placed in 
 28  # modules which have more meaningful names. 
 29  # 
 30  # ********************************************************* 
 31  # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 
 32  # CREATE NEW ONES INSTEAD 
 33  # ********************************************************* 
 34  # 
 35   
 36  import os 
 37   
 38  # Note: This module is loaded very early on, so 
 39  #       don't add any extra flumotion imports unless you 
 40  #       really know what you're doing. 
 41  from flumotion.common.python import makedirs 
 42  from flumotion.configure import configure 
 43   
 44  __version__ = "$Rev: 7676 $" 
 45   
 46   
47 -def version(binary):
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
62 -def ensureDir(directory, description):
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
78 -def componentPath(componentName, parentName):
79 # FIXME: fix epydoc to correctly spell deprecated 80 # F0.6 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
89 -def componentId(parentName, componentName):
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
102 -def parseComponentId(componentId):
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
134 -def parseFeedId(feedId):
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
162 -def parseFullFeedId(fullFeedId):
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
175 -def objRepr(object):
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
183 -def pathToModuleName(path):
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 # __init__ is last because it works on top of the first three 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 # if the path still contains dots, it can't possibly be a valid module 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
208 -def compareVersions(first, second):
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
246 -def checkVersionsCompat(version, against):
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 # e.g. config generated against newer flumotion than what is 266 # running 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
277 -def versionTupleToString(versionTuple):
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
294 -def versionStringToTuple(versionString):
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
322 -def get_all_methods(obj, method, subclass_first):
323 mro = type(obj).__mro__ 324 if not subclass_first: 325 # do a list() so as to copy the mro, we reverse the list in 326 # place so as to start with the base class 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 # In a hierarchy A -> B, if A implements the method, B will inherit 338 # it as well. Compare the functions implementing the methods so as 339 # to avoid calling them twice. 340 return _uniq(procs, lambda proc: proc.im_func)
341 342
343 -def call_each_method(obj, method, *args, **kwargs):
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
355 -def call_each_method_reversed(obj, method, *args, **kwargs):
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
366 -class InitMixin(object):
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
383 - def __init__(self, *args, **kwargs):
384 call_each_method_reversed(self, 'init', *args, **kwargs)
385 386
387 -def strToBool(string):
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
399 -def assertSSLAvailable():
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 # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 412 # CREATE NEW ONES INSTEAD 413 # ********************************************************* 414 # 415