~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

Refactored the export code to make it easier to add new export formats.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
from bzrlib.inventory import Inventory
27
27
from bzrlib.osutils import appendpath, fingerprint_file
28
28
 
29
 
 
30
 
exporters = {}
31
 
 
32
29
class Tree(object):
33
30
    """Abstract file tree.
34
31
 
109
106
        sys.stdout.write(self.get_file_text(file_id))
110
107
        
111
108
        
112
 
    def export(self, dest, format='dir', root=None):
113
 
        """Export this tree."""
114
 
        try:
115
 
            exporter = exporters[format]
116
 
        except KeyError:
117
 
            from bzrlib.errors import BzrCommandError
118
 
            raise BzrCommandError("export format %r not supported" % format)
119
 
        exporter(self, dest, root)
120
 
 
121
 
 
122
 
 
123
109
class RevisionTree(Tree):
124
110
    """Tree viewing a previous revision.
125
111
 
277
263
            
278
264
 
279
265
 
280
 
######################################################################
281
 
# export
282
 
 
283
 
def dir_exporter(tree, dest, root):
284
 
    """Export this tree to a new directory.
285
 
 
286
 
    `dest` should not exist, and will be created holding the
287
 
    contents of this tree.
288
 
 
289
 
    TODO: To handle subdirectories we need to create the
290
 
           directories first.
291
 
 
292
 
    :note: If the export fails, the destination directory will be
293
 
           left in a half-assed state.
294
 
    """
295
 
    import os
296
 
    os.mkdir(dest)
297
 
    mutter('export version %r', tree)
298
 
    inv = tree.inventory
299
 
    for dp, ie in inv.iter_entries():
300
 
        ie.put_on_disk(dest, dp, tree)
301
 
 
302
 
exporters['dir'] = dir_exporter
303
 
 
304
 
try:
305
 
    import tarfile
306
 
except ImportError:
307
 
    pass
308
 
else:
309
 
    def get_root_name(dest):
310
 
        """Get just the root name for a tarball.
311
 
 
312
 
        >>> get_root_name('mytar.tar')
313
 
        'mytar'
314
 
        >>> get_root_name('mytar.tar.bz2')
315
 
        'mytar'
316
 
        >>> get_root_name('tar.tar.tar.tgz')
317
 
        'tar.tar.tar'
318
 
        >>> get_root_name('bzr-0.0.5.tar.gz')
319
 
        'bzr-0.0.5'
320
 
        >>> get_root_name('a/long/path/mytar.tgz')
321
 
        'mytar'
322
 
        >>> get_root_name('../parent/../dir/other.tbz2')
323
 
        'other'
324
 
        """
325
 
        endings = ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']
326
 
        dest = os.path.basename(dest)
327
 
        for end in endings:
328
 
            if dest.endswith(end):
329
 
                return dest[:-len(end)]
330
 
 
331
 
    def tar_exporter(tree, dest, root, compression=None):
332
 
        """Export this tree to a new tar file.
333
 
 
334
 
        `dest` will be created holding the contents of this tree; if it
335
 
        already exists, it will be clobbered, like with "tar -c".
336
 
        """
337
 
        from time import time
338
 
        now = time()
339
 
        compression = str(compression or '')
340
 
        if root is None:
341
 
            root = get_root_name(dest)
342
 
        try:
343
 
            ball = tarfile.open(dest, 'w:' + compression)
344
 
        except tarfile.CompressionError, e:
345
 
            raise BzrError(str(e))
346
 
        mutter('export version %r', tree)
347
 
        inv = tree.inventory
348
 
        for dp, ie in inv.iter_entries():
349
 
            mutter("  export {%s} kind %s to %s", ie.file_id, ie.kind, dest)
350
 
            item, fileobj = ie.get_tar_item(root, dp, now, tree)
351
 
            ball.addfile(item, fileobj)
352
 
        ball.close()
353
 
 
354
 
    exporters['tar'] = tar_exporter
355
 
 
356
 
    def tgz_exporter(tree, dest, root):
357
 
        tar_exporter(tree, dest, root, compression='gz')
358
 
    exporters['tgz'] = tgz_exporter
359
 
 
360
 
    def tbz_exporter(tree, dest, root):
361
 
        tar_exporter(tree, dest, root, compression='bz2')
362
 
    exporters['tbz2'] = tbz_exporter
363
 
 
364
 
 
365
 
def zip_exporter(tree, dest, root):
366
 
    """ Export this tree to a new zip file.
367
 
 
368
 
    `dest` will be created holding the contents of this tree; if it
369
 
    already exists, it will be overwritten".
370
 
    """
371
 
    import time
372
 
    import zipfile
373
 
 
374
 
    now = time.localtime()[:6]
375
 
    mutter('export version %r', tree)
376
 
 
377
 
    compression = zipfile.ZIP_DEFLATED
378
 
    zipf = zipfile.ZipFile(dest, "w", compression)
379
 
 
380
 
    inv = tree.inventory
381
 
 
382
 
    try:
383
 
        for dp, ie in inv.iter_entries():
384
 
 
385
 
            file_id = ie.file_id
386
 
            mutter("  export {%s} kind %s to %s", file_id, ie.kind, dest)
387
 
 
388
 
            if ie.kind == "file": 
389
 
                zinfo = zipfile.ZipInfo(
390
 
                            filename=str(os.path.join(root, dp)),
391
 
                            date_time=now)
392
 
                zinfo.compress_type = compression
393
 
                zipf.writestr(zinfo, tree.get_file_text(file_id))
394
 
            elif ie.kind == "directory":
395
 
                zinfo = zipfile.ZipInfo(
396
 
                            filename=str(os.path.join(root, dp)+os.sep),
397
 
                            date_time=now)
398
 
                zinfo.compress_type = compression
399
 
                zipf.writestr(zinfo,'')
400
 
            elif ie.kind == "symlink":
401
 
                zinfo = zipfile.ZipInfo(
402
 
                            filename=str(os.path.join(root, dp+".lnk")),
403
 
                            date_time=now)
404
 
                zinfo.compress_type = compression
405
 
                zipf.writestr(zinfo, ie.symlink_target)
406
 
 
407
 
        zipf.close()
408
 
 
409
 
    except UnicodeEncodeError:
410
 
        zipf.close()
411
 
        os.remove(dest)
412
 
        from bzrlib.errors import BzrError
413
 
        raise BzrError("Can't export non-ascii filenames to zip")
414
 
#/def zip_exporter(tree, dest, root):
415
 
 
416
 
exporters["zip"] = zip_exporter