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