~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Martin Pool
  • Date: 2005-06-14 07:52:45 UTC
  • Revision ID: mbp@sourcefrog.net-20050614075245-def811d1b7dc0e14
- export to tarballs
  patch from lalo

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
"""
19
19
 
20
20
from sets import Set
21
 
import os.path, os, fnmatch
 
21
import os.path, os, fnmatch, time
22
22
 
23
23
from osutils import pumpfile, filesize, quotefn, sha_file, \
24
24
     joinpath, splitpath, appendpath, isdir, isfile, file_kind, fingerprint_file
32
32
 
33
33
import bzrlib
34
34
 
 
35
exporters = {}
 
36
 
35
37
class Tree(object):
36
38
    """Abstract file tree.
37
39
 
99
101
        pumpfile(self.get_file(fileid), sys.stdout)
100
102
        
101
103
        
102
 
    def export(self, dest):        
103
 
        """Export this tree to a new directory.
104
 
 
105
 
        `dest` should not exist, and will be created holding the
106
 
        contents of this tree.
107
 
 
108
 
        TODO: To handle subdirectories we need to create the
109
 
               directories first.
110
 
 
111
 
        :note: If the export fails, the destination directory will be
112
 
               left in a half-assed state.
113
 
        """
114
 
        os.mkdir(dest)
115
 
        mutter('export version %r' % self)
116
 
        inv = self.inventory
117
 
        for dp, ie in inv.iter_entries():
118
 
            kind = ie.kind
119
 
            fullpath = appendpath(dest, dp)
120
 
            if kind == 'directory':
121
 
                os.mkdir(fullpath)
122
 
            elif kind == 'file':
123
 
                pumpfile(self.get_file(ie.file_id), file(fullpath, 'wb'))
124
 
            else:
125
 
                bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
126
 
            mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
 
104
    def export(self, dest, format='dir'):
 
105
        """Export this tree."""
 
106
        try:
 
107
            exporter = exporters[format]
 
108
        except KeyError:
 
109
            raise BzrCommandError("export format %r not supported" % format)
 
110
        exporter(self, dest)
127
111
 
128
112
 
129
113
 
241
225
        if old_name != new_name:
242
226
            yield (old_name, new_name)
243
227
            
 
228
 
 
229
 
 
230
######################################################################
 
231
# export
 
232
 
 
233
def dir_exporter(tree, dest):
 
234
    """Export this tree to a new directory.
 
235
 
 
236
    `dest` should not exist, and will be created holding the
 
237
    contents of this tree.
 
238
 
 
239
    TODO: To handle subdirectories we need to create the
 
240
           directories first.
 
241
 
 
242
    :note: If the export fails, the destination directory will be
 
243
           left in a half-assed state.
 
244
    """
 
245
    os.mkdir(dest)
 
246
    mutter('export version %r' % tree)
 
247
    inv = tree.inventory
 
248
    for dp, ie in inv.iter_entries():
 
249
        kind = ie.kind
 
250
        fullpath = appendpath(dest, dp)
 
251
        if kind == 'directory':
 
252
            os.mkdir(fullpath)
 
253
        elif kind == 'file':
 
254
            pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
 
255
        else:
 
256
            bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
 
257
        mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
 
258
exporters['dir'] = dir_exporter
 
259
 
 
260
try:
 
261
    import tarfile
 
262
except ImportError:
 
263
    pass
 
264
else:
 
265
    def tar_exporter(tree, dest, compression=None):
 
266
        """Export this tree to a new tar file.
 
267
 
 
268
        `dest` will be created holding the contents of this tree; if it
 
269
        already exists, it will be clobbered, like with "tar -c".
 
270
        """
 
271
        now = time.time()
 
272
        compression = str(compression or '')
 
273
        try:
 
274
            ball = tarfile.open(dest, 'w:' + compression)
 
275
        except tarfile.CompressionError, e:
 
276
            bailout(str(e))
 
277
        mutter('export version %r' % tree)
 
278
        inv = tree.inventory
 
279
        for dp, ie in inv.iter_entries():
 
280
            mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
 
281
            item = tarfile.TarInfo(dp)
 
282
            # TODO: would be cool to actually set it to the timestamp of the
 
283
            # revision it was last changed
 
284
            item.mtime = now
 
285
            if ie.kind == 'directory':
 
286
                item.type = tarfile.DIRTYPE
 
287
                fileobj = None
 
288
                item.name += '/'
 
289
                item.size = 0
 
290
                item.mode = 0755
 
291
            elif ie.kind == 'file':
 
292
                item.type = tarfile.REGTYPE
 
293
                fileobj = tree.get_file(ie.file_id)
 
294
                item.size = _find_file_size(fileobj)
 
295
                item.mode = 0644
 
296
            else:
 
297
                bailout("don't know how to export {%s} of kind %r" %
 
298
                        (ie.file_id, ie.kind))
 
299
 
 
300
            ball.addfile(item, fileobj)
 
301
        ball.close()
 
302
    exporters['tar'] = tar_exporter
 
303
 
 
304
    def tgz_exporter(tree, dest):
 
305
        tar_exporter(tree, dest, compression='gz')
 
306
    exporters['tgz'] = tgz_exporter
 
307
 
 
308
    def tbz_exporter(tree, dest):
 
309
        tar_exporter(tree, dest, compression='bz2')
 
310
    exporters['tbz2'] = tbz_exporter
 
311
 
 
312
 
 
313
def _find_file_size(fileobj):
 
314
    offset = fileobj.tell()
 
315
    try:
 
316
        fileobj.seek(0, 2)
 
317
        size = fileobj.tell()
 
318
    except TypeError:
 
319
        # gzip doesn't accept second argument to seek()
 
320
        fileobj.seek(0)
 
321
        size = 0
 
322
        while True:
 
323
            nread = len(fileobj.read())
 
324
            if nread == 0:
 
325
                break
 
326
            size += nread
 
327
    fileobj.seek(offset)
 
328
    return size