~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugin.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
113
113
    dirs.insert(0, os.path.dirname(plugins.__file__))
114
114
 
115
115
    load_from_dirs(dirs)
 
116
    load_from_zips(dirs)
116
117
 
117
118
 
118
119
def load_from_dirs(dirs):
183
184
                ## import pdb; pdb.set_trace()
184
185
                warning('Unable to load plugin %r from %r' % (name, d))
185
186
                log_exception_quietly()
 
187
 
 
188
 
 
189
def load_from_zips(zips):
 
190
    """Load bzr plugins from zip archives with zipimport.
 
191
    It's similar to load_from_dirs but plugins searched inside archives.
 
192
    """
 
193
    import zipfile
 
194
    import zipimport
 
195
 
 
196
    valid_suffixes = ('.py', '.pyc', '.pyo')    # only python modules/packages
 
197
                                                # is allowed
 
198
    for zip_name in zips:
 
199
        if '.zip' not in zip_name:
 
200
            continue
 
201
        try:
 
202
            ziobj = zipimport.zipimporter(zip_name)
 
203
        except zipimport.ZipImportError:
 
204
            # not a valid zip
 
205
            continue
 
206
        mutter('Looking for plugins in %r', zip_name)
 
207
 
 
208
        # use zipfile to get list of files/dirs inside zip
 
209
        z = zipfile.ZipFile(ziobj.archive)
 
210
        namelist = z.namelist()
 
211
        z.close()
 
212
 
 
213
        if ziobj.prefix:
 
214
            prefix = ziobj.prefix.replace('\\','/')
 
215
            ix = len(prefix)
 
216
            namelist = [name[ix:]
 
217
                        for name in namelist
 
218
                        if name.startswith(prefix)]
 
219
 
 
220
        mutter('Names in archive: %r', namelist)
 
221
 
 
222
        for name in namelist:
 
223
            if not name or name.endswith('/'):
 
224
                continue
 
225
 
 
226
            # '/' is used to separate pathname components inside zip archives
 
227
            ix = name.rfind('/')
 
228
            if ix == -1:
 
229
                head, tail = '', name
 
230
            else:
 
231
                head, tail = name.rsplit('/',1)
 
232
            if '/' in head:
 
233
                # we don't need looking in subdirectories
 
234
                continue
 
235
 
 
236
            base, suffix = osutils.splitext(tail)
 
237
            if suffix not in valid_suffixes:
 
238
                continue
 
239
 
 
240
            if base == '__init__':
 
241
                # package
 
242
                plugin_name = head
 
243
            elif head == '':
 
244
                # module
 
245
                plugin_name = base
 
246
            else:
 
247
                continue
 
248
 
 
249
            if not plugin_name:
 
250
                continue
 
251
            if getattr(plugins, plugin_name, None):
 
252
                mutter('Plugin name %s already loaded', plugin_name)
 
253
                continue
 
254
 
 
255
            try:
 
256
                plugin = ziobj.load_module(plugin_name)
 
257
                setattr(plugins, plugin_name, plugin)
 
258
                mutter('Load plugin %s from zip %r', plugin_name, zip_name)
 
259
            except zipimport.ZipImportError, e:
 
260
                mutter('Unable to load plugin %r from %r: %s',
 
261
                       plugin_name, zip_name, str(e))
 
262
                continue
 
263
            except KeyboardInterrupt:
 
264
                raise
 
265
            except Exception, e:
 
266
                ## import pdb; pdb.set_trace()
 
267
                warning('Unable to load plugin %r from %r'
 
268
                        % (name, zip_name))
 
269
                log_exception_quietly()