Package flumotion :: Package worker :: Package checks :: Module check
[hide private]

Source Code for Module flumotion.worker.checks.check

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 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  import os 
 23   
 24  import gst 
 25  from twisted.internet import defer 
 26   
 27  from flumotion.common import documentation, errors, gstreamer, log, messages 
 28  from flumotion.common.i18n import N_, gettexter 
 29   
 30  __version__ = "$Rev$" 
 31  T_ = gettexter() 
 32   
 33   
34 -def handleGStreamerDeviceError(failure, device, mid=None):
35 """ 36 Handle common GStreamer GstErrors or other. 37 Return a message or None. 38 """ 39 if not mid: 40 log.warning('check', 41 'handleGStreamerDeviceError: no message id specified') 42 43 m = None 44 45 if failure.check(errors.GStreamerGstError): 46 source, gerror, debug = failure.value.args 47 log.debug('check', 48 'GStreamer GError: %s (domain %s, code %d, debug %s)' % ( 49 gerror.message, gerror.domain, gerror.code, debug)) 50 51 if gerror.domain == "gst-resource-error-quark": 52 if gerror.code == int(gst.RESOURCE_ERROR_OPEN_READ): 53 m = messages.Error(T_( 54 N_("Could not open device '%s' for reading. " 55 "Check permissions on the device."), device), mid=mid) 56 documentation.messageAddFixBadPermissions(m) 57 if gerror.code == int(gst.RESOURCE_ERROR_OPEN_WRITE): 58 m = messages.Error(T_( 59 N_("Could not open device '%s' for writing. " 60 "Check permissions on the device."), device), mid=mid) 61 documentation.messageAddFixBadPermissions(m) 62 elif gerror.code == int(gst.RESOURCE_ERROR_OPEN_READ_WRITE): 63 m = messages.Error(T_( 64 N_("Could not open device '%s'. " 65 "Check permissions on the device."), device), mid=mid) 66 documentation.messageAddFixBadPermissions(m) 67 elif gerror.code == int(gst.RESOURCE_ERROR_BUSY): 68 m = messages.Error(T_( 69 N_("Device '%s' is already in use."), device), mid=mid) 70 elif gerror.code == int(gst.RESOURCE_ERROR_SETTINGS): 71 m = messages.Error(T_( 72 N_("Device '%s' did not accept the requested settings."), 73 device), 74 debug="%s\n%s" % (gerror.message, debug), mid=mid) 75 76 # fallback GStreamer GstError handling 77 if not m: 78 m = messages.Error(T_(N_("Internal unhandled GStreamer error.")), 79 debug="%s\n%s: %d\n%s" % ( 80 gerror.message, gerror.domain, gerror.code, debug), 81 mid=mid) 82 elif failure.check(errors.GStreamerError): 83 m = messages.Error(T_(N_("Internal GStreamer error.")), 84 debug=debugFailure(failure), mid=mid) 85 log.debug('check', 'handleGStreamerError: returning %r' % m) 86 return m
87 88
89 -def debugFailure(failure):
90 """ 91 Create debug info from a failure. 92 """ 93 return "Failure %r: %s\n%s" % (failure, failure.getErrorMessage(), 94 failure.getTraceback())
95 96
97 -def callbackResult(value, result):
98 """ 99 I am a callback to add to a do_element_check deferred. 100 """ 101 log.debug('check', 'returning succeeded Result, value %r' % (value, )) 102 result.succeed(value) 103 return result
104 105
106 -def errbackResult(failure, result, mid, device):
107 """ 108 I am an errback to add to a do_element_check deferred, after your 109 specific one. 110 111 I handle several generic cases, including some generic GStreamer errors. 112 113 @param mid: the id to set on the message 114 """ 115 m = None 116 if failure.check(errors.GStreamerGstError): 117 m = handleGStreamerDeviceError(failure, device, mid=mid) 118 119 if not m: 120 log.debug('check', 'unhandled failure: %r (%s)\nTraceback:\n%s' % ( 121 failure, failure.getErrorMessage(), failure.getTraceback())) 122 m = messages.Error(T_(N_("Could not probe device '%s'."), device), 123 debug=debugFailure(failure)) 124 125 m.id = mid 126 result.add(m) 127 return result
128 129
130 -def errbackNotFoundResult(failure, result, mid, device):
131 """ 132 I am an errback to add to a do_element_check deferred 133 to check for RESOURCE_ERROR_NOT_FOUND, and add a message to the result. 134 135 @param mid: the id to set on the message 136 """ 137 failure.trap(errors.GStreamerGstError) 138 source, gerror, debug = failure.value.args 139 140 if gerror.domain == "gst-resource-error-quark" and \ 141 gerror.code == int(gst.RESOURCE_ERROR_NOT_FOUND): 142 m = messages.Warning(T_( 143 N_("No device found on %s."), device), mid=mid) 144 result.add(m) 145 return result 146 147 # let failure fall through otherwise 148 return failure
149 150
151 -class CheckProcError(Exception):
152 'Utility error for element checker procedures' 153 data = None 154
155 - def __init__(self, data):
156 self.data = data
157 158
159 -def checkImport(moduleName):
160 log.debug('check', 'checkImport: %s', moduleName) 161 __import__(moduleName) 162 return True
163 164
165 -def checkElements(elementNames):
166 log.debug('check', 'checkElements: element names to check %r', 167 elementNames) 168 ret = [] 169 for name in elementNames: 170 try: 171 gst.element_factory_make(name) 172 ret.append(name) 173 except gst.PluginNotFoundError: 174 log.debug('check', 'no plugin found for element factory %s', name) 175 pass 176 log.debug('check', 'checkElements: returning elements names %r', ret) 177 return ret
178 179
180 -def checkDirectory(pathName):
181 """ 182 Check if a path is a directory and that it is readable and 183 executable 184 @param pathName: path to check 185 @type pathName: string 186 @returns: if the path is a directory and readable 187 @rtype: L{messages.Result} 188 """ 189 190 result = messages.Result() 191 succeeded = False 192 if (os.path.isdir(pathName) and 193 os.access(pathName, os.R_OK|os.X_OK)): 194 succeeded = True 195 196 result.succeed(succeeded) 197 return result
198 199
200 -def checkFile(filePath):
201 """ 202 Checks if a path is a file. 203 204 @param filePath : The path of the file 205 @type filePath : str 206 207 @returns : True if filePath exists and is a file, False otherwise. 208 @rtype : L{messages.Result} 209 """ 210 log.debug('check', 'checkFile: %s', filePath) 211 result = messages.Result() 212 result.succeed(os.path.isfile(filePath)) 213 return result
214 215
216 -def checkMediaFile(filePath, mimetype=None, audio=True, video=True):
217 """ 218 Checks if a path is a valid media file, and returns its properties. 219 220 @param filePath : The path of the file 221 @type filePath : str 222 @param mimetype : File mimetype to check 223 @type mimetype : str 224 @param audio : Audio required 225 @type audio : str 226 @param video : Video required 227 @type video : str 228 229 @returns : Tuple (valid, properties). valid is set to True if it is a valid 230 media file. properties is a dictonary with the video properties (width, 231 height, framerate) 232 @rtype: L{twisted.internet.defer.Deferred} of 233 L{flumotion.common.messages.Result} 234 """ 235 d = defer.Deferred() 236 237 def discovered(dcv, ismedia): 238 result = messages.Result() 239 if not ismedia: 240 result.succeed((False, None)) 241 return d.callback(result) 242 if mimetype and not (mimetype in dcv.mimetype): 243 result.succeed((False, None)) 244 return d.callback(result) 245 if not dcv.is_audio and audio: 246 result.succeed((False, None)) 247 return d.callback(result) 248 properties = dict() 249 if video: 250 if not dcv.is_video or not dcv.videorate: 251 result.succeed((False, None)) 252 return d.callback(result) 253 properties['width'] = dcv.videowidth 254 properties['height'] = dcv.videoheight 255 properties['framerate'] = (float(dcv.videorate.num) / 256 dcv.videorate.denom) 257 result.succeed((True, properties)) 258 return d.callback(result)
259 260 from gst.extend import discoverer 261 dcv = discoverer.Discoverer(filePath) 262 dcv.connect('discovered', discovered) 263 dcv.discover() 264 return d 265 266
267 -def checkPlugin(pluginName, packageName, minimumVersion=None, 268 featureName=None, featureCheck=None):
269 """ 270 Check if the given plug-in is available. 271 Return a result with an error if it is not, or not new enough. 272 273 @param pluginName: name of the plugin to check 274 @param packageName: name of the package to tell the user to install 275 if the check fails 276 @param minimumVersion: minimum version of the plugin, as a tuple. 277 Optional. 278 @param featureName: name of a specific feature to check for in the 279 plugin. Optional. Overrides the minimum version check, if given. 280 @param featureCheck: function to call on the found feature, which 281 should return a boolean representing whether the feature is good or 282 not. Optional, and only makes sense if you specify featureName. 283 @rtype: L{messages.Result} 284 """ 285 result = messages.Result() 286 version = gstreamer.get_plugin_version(pluginName) 287 288 if not version: 289 m = messages.Error(T_( 290 N_("This host is missing the '%s' GStreamer plug-in.\n"), 291 pluginName)) 292 m.add(T_(N_( 293 "Please install '%s'.\n"), packageName)) 294 documentation.messageAddGStreamerInstall(m) 295 result.add(m) 296 elif featureName: 297 r = gst.registry_get_default() 298 features = r.get_feature_list_by_plugin(pluginName) 299 byname = dict([(f.get_name(), f) for f in features]) 300 if (featureName not in byname 301 or (featureCheck and not featureCheck(byname[featureName]))): 302 m = messages.Error(T_( 303 N_("Your '%s' GStreamer plug-in is too old.\n"), pluginName), 304 mid = 'plugin-%s-check' % pluginName) 305 m.add(T_(N_( 306 "Please upgrade '%s' to version %s or higher."), 307 packageName, ".".join([str(x) for x in minimumVersion]))) 308 documentation.messageAddGStreamerInstall(m) 309 result.add(m) 310 elif version < minimumVersion: 311 m = messages.Error(T_( 312 N_("Version %s of the '%s' GStreamer plug-in is too old.\n"), 313 ".".join([str(x) for x in version]), pluginName), 314 mid = 'plugin-%s-check' % pluginName) 315 m.add(T_(N_( 316 "Please upgrade '%s' to version %s."), packageName, 317 ".".join([str(x) for x in minimumVersion]))) 318 documentation.messageAddGStreamerInstall(m) 319 result.add(m) 320 321 result.succeed(None) 322 return defer.succeed(result)
323 324 # FIXME: I would prefer to have this in flumotion/component/base/check.py 325 326
327 -def do_check(obj, callable, *args, **kwargs):
328 """ 329 This method can be used in component do_check vmethods. 330 It will add messages from the result to the UI state. 331 332 @param obj: an object having a addMessage method 333 @param callable: a callable which returns a deferred method 334 returning a Result. 335 336 @rtype: L{twisted.internet.defer.Deferred} 337 """ 338 339 def checkCallback(result): 340 for m in result.messages: 341 obj.addMessage(m)
342 343 d = callable(*args, **kwargs) 344 d.addCallback(checkCallback) 345 return d 346