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: 7096 $" 
 45   
46 -def version(binary):
47 """ 48 Print a version block for the flumotion binaries. 49 50 @arg binary: name of the binary 51 @type binary: string 52 """ 53 54 block = [] 55 block.append("%s %s" % (binary, configure.version)) 56 block.append("part of Flumotion - a streaming media server") 57 block.append("(C) Copyright 2004,2005,2006,2007 Fluendo") 58 return "\n".join(block)
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 # FIXME: fix epydoc to correctly spell deprecated 77 # F0.6
78 -def componentPath(componentName, parentName):
79 """ 80 Create a path string out of the name of a component and its parent. 81 82 @depreciated: Use @componentId instead 83 """ 84 return '/%s/%s' % (parentName, componentName)
85
86 -def componentId(parentName, componentName):
87 """ 88 Create a C{componentId} based on the C{parentName} and C{componentName}. 89 90 A C{componentId} uniquely identifies a component within a planet. 91 92 @since: 0.3.1 93 94 @rtype: str 95 """ 96 return '/%s/%s' % (parentName, componentName)
97
98 -def parseComponentId(componentId):
99 """ 100 Parses a component id ("/flowName/componentName") into its parts. 101 102 @since: 0.3.1 103 104 @rtype: tuple of (str, str) 105 @return: tuple of (flowName, componentName) 106 """ 107 assert componentId is not None, "componentId should not be None" 108 l = componentId.split("/") 109 assert len(l) == 3, \ 110 "componentId %s should have exactly two parts" % componentId 111 assert l[0] == '', \ 112 "componentId %s should start with /" % componentId 113 return (l[1], l[2])
114
115 -def feedId(componentName, feedName):
116 """ 117 Create a C{feedId} based on the C{componentName} and C{feedName}. 118 119 A C{feedId} uniquely identifies a feed within a flow or atmosphere. 120 It identifies the feed from a feeder to an eater. 121 122 @since: 0.3.1 123 124 @rtype: str 125 """ 126 return "%s:%s" % (componentName, feedName)
127
128 -def parseFeedId(feedId):
129 """ 130 @since: 0.3.1 131 132 @rtype: tuple of (str, str) 133 @return: tuple of (componentName, feedName) 134 """ 135 assert not feedId.startswith('/'), \ 136 "feedId must not start with '/': %s" % feedId 137 parts = feedId.split(":") 138 assert len(parts) == 2, "feedId %s should contain exactly one ':'" % feedId 139 return (parts[0], parts[1])
140
141 -def fullFeedId(flowName, componentName, feedName):
142 """ 143 Create a C{fullFeedId} based on the C{flowName}, C{componentName} and 144 C{feedName}. 145 146 A C{fullFeedId} uniquely identifies a feed within a planet. 147 148 @since: 0.3.1 149 150 @rtype: str 151 """ 152 return feedId(componentId(flowName, componentName), feedName)
153
154 -def parseFullFeedId(fullFeedId):
155 """ 156 @since: 0.3.1 157 158 @rtype: tuple of (str, str, str) 159 @return: tuple of (flowName, componentName, feedName) 160 """ 161 parts = fullFeedId.split(":") 162 assert len(parts) == 2 163 flowName, componentName = parseComponentId(parts[0]) 164 return (flowName, componentName, parts[1])
165
166 -def objRepr(object):
167 """ 168 Return a string giving the fully qualified class of the given object. 169 """ 170 c = object.__class__ 171 return "%s.%s" % (c.__module__, c.__name__)
172
173 -def pathToModuleName(path):
174 """ 175 Convert the given (relative) path to the python module it would have to 176 be imported as. 177 178 Return None if the path is not a valid python module 179 """ 180 # __init__ is last because it works on top of the first three 181 valid = False 182 suffixes = ['.pyc', '.pyo', '.py', os.path.sep + '__init__'] 183 for s in suffixes: 184 if path.endswith(s): 185 path = path[:-len(s)] 186 valid = True 187 188 # if the path still contains dots, it can't possibly be a valid module 189 if not '.' in path: 190 valid = True 191 192 if not valid: 193 return None 194 195 return ".".join(path.split(os.path.sep))
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 -def checkVersionsCompat(version, against):
235 """Checks if two versions are compatible. 236 237 Versions are compatible if they are from the same minor release. In 238 addition, unstable (odd) releases are treated as compatible with 239 their subsequent stable (even) releases. 240 241 @param version: version to check 242 @type version: tuple of int 243 @param against: version against which we are checking. For versions 244 of core Flumotion, this may be obtained by 245 L{flumotion.configure.configure.version}. 246 @type against: tuple of int 247 @returns: True if a configuration from version is compatible with 248 against. 249 """ 250 if version == against: 251 return True 252 elif version > against: 253 # e.g. config generated against newer flumotion than what is 254 # running 255 return False 256 elif len(version) < 2 or len(against) < 2: 257 return False 258 elif version[0] != against[0]: 259 return False 260 else: 261 round2 = lambda x: ((x + 1) // 2) * 2 262 return round2(version[1]) == round2(against[1])
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 -def _uniq(l, key=lambda x: x):
281 """ 282 Filters out duplicate entries in a list. 283 """ 284 out = [] 285 for x in l: 286 if key(x) not in [key(y) for y in out]: 287 out.append(x) 288 return out
289
290 -def get_all_methods(obj, method, subclass_first):
291 mro = type(obj).__mro__ 292 if not subclass_first: 293 # do a list() so as to copy the mro, we reverse the list in 294 # place so as to start with the base class 295 mro = list(mro) 296 mro.reverse() 297 procs = [] 298 for c in mro: 299 if hasattr(c, method): 300 proc = getattr(c, method) 301 assert callable(proc) and hasattr(proc, 'im_func'),\ 302 'attr %s of class %s is not a method' % (method, c) 303 procs.append(proc) 304 305 # In a hierarchy A -> B, if A implements the method, B will inherit 306 # it as well. Compare the functions implementing the methods so as 307 # to avoid calling them twice. 308 return _uniq(procs, lambda proc: proc.im_func)
309
310 -def call_each_method(obj, method, *args, **kwargs):
311 """ 312 Invoke all implementations of a method on an object. 313 314 Searches for method implementations in the object's class and all of 315 the class' superclasses. Calls the methods in method resolution 316 order, which goes from subclasses to superclasses. 317 """ 318 for proc in get_all_methods(obj, method, True): 319 proc(obj, *args, **kwargs)
320
321 -def call_each_method_reversed(obj, method, *args, **kwargs):
322 """ 323 Invoke all implementations of a method on an object. 324 325 Like call_each_method, but calls the methods in reverse method 326 resolution order, from superclasses to subclasses. 327 """ 328 for proc in get_all_methods(obj, method, False): 329 proc(obj, *args, **kwargs)
330
331 -class InitMixin(object):
332 """ 333 A mixin class to help with object initialization. 334 335 In some class hierarchies, __init__ is only used for initializing 336 instance variables. In these cases it is advantageous to avoid the 337 need to "chain up" to a parent implementation of a method. Adding 338 this class to your hierarchy will, for each class in the object's 339 class hierarchy, call the class's init() implementation on the 340 object. 341 342 Note that the function is called init() without underscrores, and 343 that there is no need to chain up to superclasses' implementations. 344 345 Uses call_each_method_reversed() internally. 346 """ 347
348 - def __init__(self, *args, **kwargs):
349 call_each_method_reversed(self, 'init', *args, **kwargs)
350
351 -def strToBool(string):
352 """ 353 @type string: str 354 355 @return: True if the string represents a value we interpret as true. 356 """ 357 if string in ('True', 'true', '1', 'yes'): 358 return True 359 360 return False
361
362 -def assertSSLAvailable():
363 """Assert that twisted has support for SSL connections. 364 """ 365 from twisted.internet import posixbase 366 from flumotion.common import errors 367 368 if not posixbase.sslEnabled: 369 raise errors.NoSSLError()
370 371 372 # 373 # ********************************************************* 374 # DO NOT ADD NEW SYMBOLS HERE, ADD THEM TO OTHER MODULES OR 375 # CREATE NEW ONES INSTEAD 376 # ********************************************************* 377 # 378