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: 6964 $" 
 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 def annotated(d, *extraVals): 68 def annotatedReturn(ret): 69 return (ret,) + extraVals
70 d.addCallback(annotatedReturn) 71 return d
72 73 def getZips(sums): 74 # sums is a list of name, sum tuples, highest to lowest 75 # figure out which bundles we're missing 76 toFetch = [] 77 for name, md5 in sums: 78 path = os.path.join(configure.cachedir, name, md5) 79 if os.path.exists(path): 80 self.log('%s is up to date', name) 81 else: 82 self.log('%s needs fetching', name) 83 toFetch.append(name) 84 if toFetch: 85 return annotated(self.callRemote('getBundleZips', toFetch), 86 toFetch, sums) 87 else: 88 return {}, [], sums 89 90 def unpackAndRegister((zips, toFetch, sums)): 91 for name in toFetch: 92 if name not in zips: 93 msg = "Missing bundle %s was not received" 94 self.warning(msg, name) 95 raise errors.NoBundleError(msg % name) 96 97 b = bundle.Bundle(name) 98 b.setZip(zips[name]) 99 path = self._unbundler.unbundle(b) 100 101 # register all package paths; to do so we need to reverse sums 102 sums.reverse() 103 ret = [] 104 for name, md5 in sums: 105 self.log('registerPackagePath for %s' % name) 106 path = os.path.join(configure.cachedir, name, md5) 107 if not os.path.exists(path): 108 self.warning("path %s for bundle %s does not exist", 109 path, name) 110 else: 111 package.getPackager().registerPackagePath(path, name) 112 ret.append((name, path)) 113 114 return ret 115 116 # get sums for all bundles we need 117 d = self.callRemote('getBundleSums', **kwargs) 118 d.addCallback(getZips) 119 d.addCallback(unpackAndRegister) 120 return d 121
122 - def loadModule(self, moduleName):
123 """ 124 Load the module given by name. 125 Sets up all necessary bundles to be able to load the module. 126 127 @rtype: L{twisted.internet.defer.Deferred} 128 @returns: a deferred that will fire when the given module is loaded, 129 giving the loaded module. 130 """ 131 def gotBundles(bundles): 132 self.debug('Got bundles %r', bundles) 133 134 # load up the module and return it 135 __import__(moduleName, globals(), locals(), []) 136 self.log('loaded module %s', moduleName) 137 return sys.modules[moduleName]
138 139 self.debug('Loading module %s', moduleName) 140 141 # get sums for all bundles we need 142 d = self.getBundles(moduleName=moduleName) 143 d.addCallback(gotBundles) 144 return d 145
146 - def getBundleByName(self, bundleName):
147 """ 148 Get the given bundle locally. 149 150 @rtype: L{twisted.internet.defer.Deferred} 151 @returns: a deferred returning the absolute path under which the 152 bundle is extracted. 153 """ 154 def gotBundles(bundles): 155 name, path = bundles[-1] 156 assert name == bundleName 157 self.debug('Got bundle %s in %s', bundleName, path) 158 return path
159 160 161 self.debug('Getting bundle %s', bundleName) 162 d = self.getBundles(bundleName=bundleName) 163 d.addCallback(gotBundles) 164 return d 165
166 - def getFile(self, fileName):
167 """ 168 Do everything needed to get the given bundled file. 169 170 @returns: a deferred returning the absolute path to a local copy 171 of the given file. 172 """ 173 def gotBundles(bundles): 174 name, bundlePath = bundles[-1] 175 path = os.path.join(bundlePath, fileName) 176 if not os.path.exists(path): 177 self.warning("path %s for file %s does not exist", 178 path, fileName) 179 return path
180 181 self.debug('Getting file %s', fileName) 182 d = self.getBundles(fileName=fileName) 183 d.addCallback(gotBundles) 184 return d 185