1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 Bundle fetching, caching, and importing utilities for clients using
24 bundled code and data
25 """
26
27 from twisted.internet import error, defer
28
29 from flumotion.common import bundle, common, errors, log, package
30 from flumotion.configure import configure
31 from flumotion.twisted.defer import defer_generator_method
32
33 __all__ = ['BundleLoader']
34
36 """
37 I am an object that can get and set up bundles from a PB server.
38
39 @cvar remote: a remote reference to an avatar on the PB server.
40 """
41 remote = None
42 _unbundler = None
43
50
58
60
61
62
63 """
64 Get, extract and register all bundles needed.
65 Either one of bundleName, fileName or moduleName should be specified
66 in **kwargs, which should be strings or lists of strings.
67
68 @returns: a deferred firing a a list of (bundleName, bundlePath)
69 tuples, with lowest dependency first.
70 bundlePath is the directory to register
71 for this package.
72 """
73
74 d = self._callRemote('getBundleSums', **kwargs)
75 yield d
76
77
78
79 try:
80 sums = d.value()
81 except Exception, e:
82
83 raise
84 self.debug('Got sums %r' % sums)
85 toFetch = []
86
87 import os
88
89 for name, md5 in sums:
90 path = os.path.join(configure.cachedir, name, md5)
91 if os.path.exists(path):
92 self.log(name + ' is up to date')
93 else:
94 self.log(name + ' needs fetching')
95 toFetch.append(name)
96
97
98 d = self._callRemote('getBundleZips', toFetch)
99 yield d
100
101
102 result = d.value()
103 for name in toFetch:
104 if name not in result.keys():
105 msg = "Missing bundle %s was not received" % name
106 self.warning(msg)
107 raise errors.NoBundleError(msg)
108
109 b = bundle.Bundle(name)
110 b.setZip(result[name])
111 path = self._unbundler.unbundle(b)
112
113
114 sums.reverse()
115 ret = []
116 for name, md5 in sums:
117 self.log('registerPackagePath for %s' % name)
118 path = os.path.join(configure.cachedir, name, md5)
119 if not os.path.exists(path):
120 self.warning("path %s for bundle %s does not exist",
121 path, name)
122 else:
123 package.getPackager().registerPackagePath(path, name)
124 ret.append((name, path))
125
126 yield ret
127 getBundles = defer_generator_method(getBundles)
128
130 """
131 Load the module given by name.
132 Sets up all necessary bundles to be able to load the module.
133
134 @rtype: L{twisted.internet.defer.Deferred}
135 @returns: a deferred that will fire when the given module is loaded,
136 giving the loaded module.
137 """
138
139
140 import os
141 import sys
142
143 self.debug('Loading module %s' % moduleName)
144
145
146 d = self.getBundles(moduleName=moduleName)
147 yield d
148
149 bundles = d.value()
150 self.debug('Got bundles %r' % bundles)
151
152
153 __import__(moduleName, globals(), locals(), [])
154 self.log('loaded module %s' % moduleName)
155 yield sys.modules[moduleName]
156 loadModule = defer_generator_method(loadModule)
157
159 """
160 Get the given bundle locally.
161
162 @rtype: L{twisted.internet.defer.Deferred}
163 @returns: a deferred returning the absolute path under which the
164 bundle is extracted.
165 """
166 self.debug('Getting bundle %s' % bundleName)
167 d = self.getBundles(bundleName=bundleName)
168 yield d
169
170 bundles = d.value()
171 name, path = bundles[-1]
172 assert name == bundleName
173 self.debug('Got bundle %s in %s' % (bundleName, path))
174 yield path
175 getBundleByName = defer_generator_method(getBundleByName)
176
178 """
179 Do everything needed to get the given bundled file.
180
181 Returns: a deferred returning the absolute path to a local copy
182 of the given file.
183 """
184 self.debug('Getting file %s' % fileName)
185 d = self.getBundles(fileName=fileName)
186 yield d
187
188 import os
189
190 bundles = d.value()
191 name, bundlePath = bundles[-1]
192 path = os.path.join(bundlePath, fileName)
193 if not os.path.exists(path):
194 self.warning("path %s for file %s does not exist" % (
195 path, fileName))
196
197 yield path
198 getFile = defer_generator_method(getFile)
199