Package flumotion :: Package common :: Module bundleclient
[hide private]

Source Code for Module flumotion.common.bundleclient

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_bundleclient -*- 
  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  """bundle interface for fetching, caching and importing 
 23  """ 
 24   
 25  import os 
 26  import sys 
 27   
 28  from twisted.internet import error, defer 
 29   
 30  from flumotion.common import bundle, common, errors, log, package 
 31  from flumotion.configure import configure 
 32   
 33  __all__ = ['BundleLoader'] 
 34  __version__ = "$Rev$" 
 35   
 36   
37 -class BundleLoader(log.Loggable):
38 """ 39 I am an object that can get and set up bundles from a PB server. 40 41 @cvar remote: a remote reference to an avatar on the PB server. 42 """ 43 remote = None 44 _unbundler = None 45
46 - def __init__(self, callRemote):
47 """ 48 @type callRemote: callable 49 """ 50 self.callRemote = callRemote 51 self._unbundler = bundle.Unbundler(configure.cachedir)
52
53 - def getBundles(self, **kwargs):
54 # FIXME: later on, split out this method into getBundles which does 55 # not call registerPackagePath, and setupBundles which calls getBundles 56 # and register. Then change getBundles calls to setupBundles. 57 """ 58 Get, extract and register all bundles needed. 59 Either one of bundleName, fileName or moduleName should be specified 60 in **kwargs, which should be strings or lists of strings. 61 62 @returns: a deferred firing a a list of (bundleName, bundlePath) 63 tuples, with lowest dependency first. 64 bundlePath is the directory to register 65 for this package. 66 """ 67 68 def annotated(d, *extraVals): 69 70 def annotatedReturn(ret): 71 return (ret, ) + extraVals
72 d.addCallback(annotatedReturn) 73 return d
74 75 def getZips(sums): 76 # sums is a list of name, sum tuples, highest to lowest 77 # figure out which bundles we're missing 78 toFetch = [] 79 for name, md5 in sums: 80 path = os.path.join(configure.cachedir, name, md5) 81 if os.path.exists(path): 82 self.log('%s is up to date', name) 83 else: 84 self.log('%s needs fetching', name) 85 # FIXME: We cannot be completelly sure the bundle has the 86 # correct content only by checking that the directory exists. 87 # The worker/manager could have died during a download leaving 88 # the package incomplete. 89 toFetch.append(name) 90 if toFetch: 91 return annotated(self.callRemote('getBundleZips', toFetch), 92 toFetch, sums) 93 else: 94 return {}, [], sums 95 96 def unpackAndRegister((zips, toFetch, sums)): 97 for name in toFetch: 98 if name not in zips: 99 msg = "Missing bundle %s was not received" 100 self.warning(msg, name) 101 raise errors.NoBundleError(msg % name) 102 103 b = bundle.Bundle(name) 104 b.setZip(zips[name]) 105 path = self._unbundler.unbundle(b) 106 107 # register all package paths; to do so we need to reverse sums 108 sums.reverse() 109 ret = [] 110 for name, md5 in sums: 111 self.log('registerPackagePath for %s' % name) 112 path = os.path.join(configure.cachedir, name, md5) 113 if not os.path.exists(path): 114 self.warning("path %s for bundle %s does not exist", 115 path, name) 116 else: 117 package.getPackager().registerPackagePath(path, name) 118 ret.append((name, path)) 119 120 return ret 121 122 # get sums for all bundles we need 123 d = self.callRemote('getBundleSums', **kwargs) 124 d.addCallback(getZips) 125 d.addCallback(unpackAndRegister) 126 return d 127
128 - def loadModule(self, moduleName):
129 """ 130 Load the module given by name. 131 Sets up all necessary bundles to be able to load the module. 132 133 @rtype: L{twisted.internet.defer.Deferred} 134 @returns: a deferred that will fire when the given module is loaded, 135 giving the loaded module. 136 """ 137 138 def gotBundles(bundles): 139 self.debug('Got bundles %r', bundles) 140 141 # load up the module and return it 142 __import__(moduleName, globals(), locals(), []) 143 self.log('loaded module %s', moduleName) 144 return sys.modules[moduleName]
145 146 self.debug('Loading module %s', moduleName) 147 148 # get sums for all bundles we need 149 d = self.getBundles(moduleName=moduleName) 150 d.addCallback(gotBundles) 151 return d 152
153 - def getBundleByName(self, bundleName):
154 """ 155 Get the given bundle locally. 156 157 @rtype: L{twisted.internet.defer.Deferred} 158 @returns: a deferred returning the absolute path under which the 159 bundle is extracted. 160 """ 161 162 def gotBundles(bundles): 163 name, path = bundles[-1] 164 assert name == bundleName 165 self.debug('Got bundle %s in %s', bundleName, path) 166 return path
167 168 169 self.debug('Getting bundle %s', bundleName) 170 d = self.getBundles(bundleName=bundleName) 171 d.addCallback(gotBundles) 172 return d 173
174 - def getFile(self, fileName):
175 """ 176 Do everything needed to get the given bundled file. 177 178 @returns: a deferred returning the absolute path to a local copy 179 of the given file. 180 """ 181 182 def gotBundles(bundles): 183 name, bundlePath = bundles[-1] 184 path = os.path.join(bundlePath, fileName) 185 if not os.path.exists(path): 186 self.warning("path %s for file %s does not exist", 187 path, fileName) 188 return path
189 190 self.debug('Getting file %s', fileName) 191 d = self.getBundles(fileName=fileName) 192 d.addCallback(gotBundles) 193 return d 194