~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Martin Pool
  • Date: 2005-05-17 06:56:16 UTC
  • Revision ID: mbp@sourcefrog.net-20050517065616-6f23381d6184a8aa
- add space for un-merged patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Tree classes, representing directory at point in time.
18
18
"""
19
19
 
20
 
from osutils import pumpfile, appendpath, fingerprint_file
21
 
 
22
 
from bzrlib.trace import mutter, note
23
 
from bzrlib.errors import BzrError
 
20
from sets import Set
 
21
import os.path, os, fnmatch
 
22
 
 
23
from osutils import pumpfile, filesize, quotefn, sha_file, \
 
24
     joinpath, splitpath, appendpath, isdir, isfile, file_kind, fingerprint_file
 
25
import errno
 
26
from stat import S_ISREG, S_ISDIR, ST_MODE, ST_SIZE
 
27
 
 
28
from inventory import Inventory
 
29
from trace import mutter, note
 
30
from errors import bailout
 
31
import branch
24
32
 
25
33
import bzrlib
26
34
 
27
 
exporters = {}
28
 
 
29
 
class Tree(object):
 
35
class Tree:
30
36
    """Abstract file tree.
31
37
 
32
38
    There are several subclasses:
57
63
 
58
64
    __contains__ = has_id
59
65
 
 
66
    def id_set(self):
 
67
        """Return set of all ids in this tree."""
 
68
        return self.inventory.id_set()
 
69
 
60
70
    def __iter__(self):
61
71
        return iter(self.inventory)
62
72
 
75
85
        
76
86
        if ie.text_size != None:
77
87
            if ie.text_size != fp['size']:
78
 
                raise BzrError("mismatched size for file %r in %r" % (ie.file_id, self._store),
 
88
                bailout("mismatched size for file %r in %r" % (ie.file_id, self._store),
79
89
                        ["inventory expects %d bytes" % ie.text_size,
80
90
                         "file is actually %d bytes" % fp['size'],
81
91
                         "store is probably damaged/corrupt"])
82
92
 
83
93
        if ie.text_sha1 != fp['sha1']:
84
 
            raise BzrError("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
 
94
            bailout("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
85
95
                    ["inventory expects %s" % ie.text_sha1,
86
96
                     "file is actually %s" % fp['sha1'],
87
97
                     "store is probably damaged/corrupt"])
93
103
        pumpfile(self.get_file(fileid), sys.stdout)
94
104
        
95
105
        
96
 
    def export(self, dest, format='dir'):
97
 
        """Export this tree."""
98
 
        try:
99
 
            exporter = exporters[format]
100
 
        except KeyError:
101
 
            raise BzrCommandError("export format %r not supported" % format)
102
 
        exporter(self, dest)
 
106
    def export(self, dest):        
 
107
        """Export this tree to a new directory.
 
108
 
 
109
        `dest` should not exist, and will be created holding the
 
110
        contents of this tree.
 
111
 
 
112
        TODO: To handle subdirectories we need to create the
 
113
               directories first.
 
114
 
 
115
        :note: If the export fails, the destination directory will be
 
116
               left in a half-assed state.
 
117
        """
 
118
        os.mkdir(dest)
 
119
        mutter('export version %r' % self)
 
120
        inv = self.inventory
 
121
        for dp, ie in inv.iter_entries():
 
122
            kind = ie.kind
 
123
            fullpath = appendpath(dest, dp)
 
124
            if kind == 'directory':
 
125
                os.mkdir(fullpath)
 
126
            elif kind == 'file':
 
127
                pumpfile(self.get_file(ie.file_id), file(fullpath, 'wb'))
 
128
            else:
 
129
                bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
 
130
            mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
103
131
 
104
132
 
105
133
 
142
170
 
143
171
class EmptyTree(Tree):
144
172
    def __init__(self):
145
 
        from bzrlib.inventory import Inventory
146
173
        self._inventory = Inventory()
147
174
 
148
175
    def has_filename(self, filename):
218
245
        if old_name != new_name:
219
246
            yield (old_name, new_name)
220
247
            
221
 
 
222
 
 
223
 
######################################################################
224
 
# export
225
 
 
226
 
def dir_exporter(tree, dest):
227
 
    """Export this tree to a new directory.
228
 
 
229
 
    `dest` should not exist, and will be created holding the
230
 
    contents of this tree.
231
 
 
232
 
    TODO: To handle subdirectories we need to create the
233
 
           directories first.
234
 
 
235
 
    :note: If the export fails, the destination directory will be
236
 
           left in a half-assed state.
237
 
    """
238
 
    import os
239
 
    os.mkdir(dest)
240
 
    mutter('export version %r' % tree)
241
 
    inv = tree.inventory
242
 
    for dp, ie in inv.iter_entries():
243
 
        kind = ie.kind
244
 
        fullpath = appendpath(dest, dp)
245
 
        if kind == 'directory':
246
 
            os.mkdir(fullpath)
247
 
        elif kind == 'file':
248
 
            pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
249
 
        else:
250
 
            raise BzrError("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
251
 
        mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
252
 
exporters['dir'] = dir_exporter
253
 
 
254
 
try:
255
 
    import tarfile
256
 
except ImportError:
257
 
    pass
258
 
else:
259
 
    def tar_exporter(tree, dest, compression=None):
260
 
        """Export this tree to a new tar file.
261
 
 
262
 
        `dest` will be created holding the contents of this tree; if it
263
 
        already exists, it will be clobbered, like with "tar -c".
264
 
        """
265
 
        from time import time
266
 
        now = time()
267
 
        compression = str(compression or '')
268
 
        try:
269
 
            ball = tarfile.open(dest, 'w:' + compression)
270
 
        except tarfile.CompressionError, e:
271
 
            raise BzrError(str(e))
272
 
        mutter('export version %r' % tree)
273
 
        inv = tree.inventory
274
 
        for dp, ie in inv.iter_entries():
275
 
            mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
276
 
            item = tarfile.TarInfo(dp)
277
 
            # TODO: would be cool to actually set it to the timestamp of the
278
 
            # revision it was last changed
279
 
            item.mtime = now
280
 
            if ie.kind == 'directory':
281
 
                item.type = tarfile.DIRTYPE
282
 
                fileobj = None
283
 
                item.name += '/'
284
 
                item.size = 0
285
 
                item.mode = 0755
286
 
            elif ie.kind == 'file':
287
 
                item.type = tarfile.REGTYPE
288
 
                fileobj = tree.get_file(ie.file_id)
289
 
                item.size = _find_file_size(fileobj)
290
 
                item.mode = 0644
291
 
            else:
292
 
                raise BzrError("don't know how to export {%s} of kind %r" %
293
 
                        (ie.file_id, ie.kind))
294
 
 
295
 
            ball.addfile(item, fileobj)
296
 
        ball.close()
297
 
    exporters['tar'] = tar_exporter
298
 
 
299
 
    def tgz_exporter(tree, dest):
300
 
        tar_exporter(tree, dest, compression='gz')
301
 
    exporters['tgz'] = tgz_exporter
302
 
 
303
 
    def tbz_exporter(tree, dest):
304
 
        tar_exporter(tree, dest, compression='bz2')
305
 
    exporters['tbz2'] = tbz_exporter
306
 
 
307
 
 
308
 
def _find_file_size(fileobj):
309
 
    offset = fileobj.tell()
310
 
    try:
311
 
        fileobj.seek(0, 2)
312
 
        size = fileobj.tell()
313
 
    except TypeError:
314
 
        # gzip doesn't accept second argument to seek()
315
 
        fileobj.seek(0)
316
 
        size = 0
317
 
        while True:
318
 
            nread = len(fileobj.read())
319
 
            if nread == 0:
320
 
                break
321
 
            size += nread
322
 
    fileobj.seek(offset)
323
 
    return size