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$" 
 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 componentId(parentName, componentName):
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
91 -def parseComponentId(componentId):
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
123 -def parseFeedId(feedId):
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
151 -def parseFullFeedId(fullFeedId):
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
164 -def objRepr(object):
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
172 -def pathToModuleName(path):
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 # __init__ is last because it works on top of the first three 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 # if the path still contains dots, it can't possibly be a valid module 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
197 -def compareVersions(first, second):
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
235 -def checkVersionsCompat(version, against):
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 # e.g. config generated against newer flumotion than what is 255 # running 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
266 -def versionTupleToString(versionTuple):
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
283 -def versionStringToTuple(versionString):
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
312 -def get_all_methods(obj, method, subclass_first):
313 mro = type(obj).__mro__ 314 if not subclass_first: 315 # do a list() so as to copy the mro, we reverse the list in 316 # place so as to start with the base class 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 # In a hierarchy A -> B, if A implements the method, B will inherit 328 # it as well. Compare the functions implementing the methods so as 329 # to avoid calling them twice. 330 return _uniq(procs, lambda proc: proc.im_func)
331 332
333 -def call_each_method(obj, method, *args, **kwargs):
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
345 -def call_each_method_reversed(obj, method, *args, **kwargs):
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
356 -class InitMixin(object):
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
373 - def __init__(self, *args, **kwargs):
374 call_each_method_reversed(self, 'init', *args, **kwargs)
375 376
377 -def strToBool(string):
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
389 -def assertSSLAvailable():
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 # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 402 # CREATE NEW ONES INSTEAD 403 # ********************************************************* 404 # 405