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,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  """ 
 19  small common functions used by all processes 
 20  """ 
 21   
 22  # 
 23  # FIXME: Everything here should be removed and be placed in 
 24  # modules which have more meaningful names. 
 25  # 
 26  # ********************************************************* 
 27  # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 
 28  # CREATE NEW ONES INSTEAD 
 29  # ********************************************************* 
 30  # 
 31   
 32  import os 
 33   
 34  # Note: This module is loaded very early on, so 
 35  #       don't add any extra flumotion imports unless you 
 36  #       really know what you're doing. 
 37  from flumotion.common.python import makedirs 
 38  from flumotion.configure import configure 
 39   
 40  __version__ = "$Rev$" 
 41   
 42   
43 -def version(binary):
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
60 -def ensureDir(directory, description):
61 """ 62 Ensure the given directory exists, creating it if not. 63 64 @raise errors.FatalError: if the directory could not be created. 65 """ 66 if not os.path.exists(directory): 67 try: 68 makedirs(directory) 69 except OSError, e: 70 from flumotion.common import errors 71 raise errors.FatalError( 72 "could not create %s directory %s: %s" % ( 73 description, directory, str(e)))
74 75
76 -def componentId(parentName, componentName):
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
89 -def parseComponentId(componentId):
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
121 -def parseFeedId(feedId):
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
149 -def parseFullFeedId(fullFeedId):
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
162 -def objRepr(object):
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
170 -def pathToModuleName(path):
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 # __init__ is last because it works on top of the first three 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 # if the path still contains dots, it can't possibly be a valid module 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
195 -def compareVersions(first, second):
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
233 -def checkVersionsCompat(version, against):
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 # e.g. config generated against newer flumotion than what is 253 # running 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
264 -def versionTupleToString(versionTuple):
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
281 -def versionStringToTuple(versionString):
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
310 -def get_all_methods(obj, method, subclass_first):
311 mro = type(obj).__mro__ 312 if not subclass_first: 313 # do a list() so as to copy the mro, we reverse the list in 314 # place so as to start with the base class 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 # In a hierarchy A -> B, if A implements the method, B will inherit 326 # it as well. Compare the functions implementing the methods so as 327 # to avoid calling them twice. 328 return _uniq(procs, lambda proc: proc.im_func)
329 330
331 -def call_each_method(obj, method, *args, **kwargs):
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
343 -def call_each_method_reversed(obj, method, *args, **kwargs):
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
354 -class InitMixin(object):
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
371 - def __init__(self, *args, **kwargs):
372 call_each_method_reversed(self, 'init', *args, **kwargs)
373 374
375 -def strToBool(string):
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
387 -def assertSSLAvailable():
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 # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 400 # CREATE NEW ONES INSTEAD 401 # ********************************************************* 402 # 403