~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Martin Pool
  • Date: 2005-07-04 07:34:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050704073408-faed1ea9d8b586d4
- Test case for validate_revision_id

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
 
import os
21
 
from cStringIO import StringIO
 
20
from osutils import pumpfile, appendpath, fingerprint_file
 
21
 
 
22
from bzrlib.trace import mutter, note
 
23
from bzrlib.errors import BzrError
22
24
 
23
25
import bzrlib
24
 
from bzrlib.trace import mutter, note
25
 
from bzrlib.errors import BzrError, BzrCheckError
26
 
from bzrlib.inventory import Inventory
27
 
from bzrlib.osutils import appendpath, fingerprint_file
28
 
 
29
26
 
30
27
exporters = {}
31
28
 
68
65
 
69
66
    def _get_inventory(self):
70
67
        return self._inventory
71
 
    
72
 
    def get_file_by_path(self, path):
73
 
        return self.get_file(self._inventory.path2id(path))
74
68
 
75
69
    inventory = property(_get_inventory,
76
70
                         doc="Inventory of this Tree")
77
71
 
78
72
    def _check_retrieved(self, ie, f):
79
 
        if not __debug__:
80
 
            return  
81
73
        fp = fingerprint_file(f)
82
74
        f.seek(0)
83
75
        
95
87
                     "store is probably damaged/corrupt"])
96
88
 
97
89
 
98
 
    def print_file(self, file_id):
99
 
        """Print file with id `file_id` to stdout."""
 
90
    def print_file(self, fileid):
 
91
        """Print file with id `fileid` to stdout."""
100
92
        import sys
101
 
        sys.stdout.write(self.get_file_text(file_id))
102
 
        
103
 
        
104
 
    def export(self, dest, format='dir', root=None):
 
93
        pumpfile(self.get_file(fileid), sys.stdout)
 
94
        
 
95
        
 
96
    def export(self, dest, format='dir'):
105
97
        """Export this tree."""
106
98
        try:
107
99
            exporter = exporters[format]
108
100
        except KeyError:
109
 
            from bzrlib.errors import BzrCommandError
110
101
            raise BzrCommandError("export format %r not supported" % format)
111
 
        exporter(self, dest, root)
 
102
        exporter(self, dest)
112
103
 
113
104
 
114
105
 
122
113
           or at least passing a description to the constructor.
123
114
    """
124
115
    
125
 
    def __init__(self, weave_store, inv, revision_id):
126
 
        self._weave_store = weave_store
 
116
    def __init__(self, store, inv):
 
117
        self._store = store
127
118
        self._inventory = inv
128
 
        self._revision_id = revision_id
129
 
 
130
 
    def get_weave(self, file_id):
131
 
        # FIXME: RevisionTree should be given a branch
132
 
        # not a store, or the store should know the branch.
133
 
        import bzrlib.transactions as transactions
134
 
        return self._weave_store.get_weave(file_id,
135
 
            transactions.PassThroughTransaction())
136
 
 
137
 
 
138
 
    def get_file_lines(self, file_id):
139
 
        ie = self._inventory[file_id]
140
 
        weave = self.get_weave(file_id)
141
 
        return weave.get(ie.revision)
142
 
        
143
 
 
144
 
    def get_file_text(self, file_id):
145
 
        return ''.join(self.get_file_lines(file_id))
146
 
 
147
119
 
148
120
    def get_file(self, file_id):
149
 
        return StringIO(self.get_file_text(file_id))
 
121
        ie = self._inventory[file_id]
 
122
        f = self._store[ie.text_id]
 
123
        mutter("  get fileid{%s} from %r" % (file_id, self))
 
124
        self._check_retrieved(ie, f)
 
125
        return f
150
126
 
151
127
    def get_file_size(self, file_id):
152
128
        return self._inventory[file_id].text_size
153
129
 
154
130
    def get_file_sha1(self, file_id):
155
131
        ie = self._inventory[file_id]
156
 
        if ie.kind == "file":
157
 
            return ie.text_sha1
158
 
 
159
 
    def is_executable(self, file_id):
160
 
        return self._inventory[file_id].executable
 
132
        return ie.text_sha1
161
133
 
162
134
    def has_filename(self, filename):
163
135
        return bool(self.inventory.path2id(filename))
165
137
    def list_files(self):
166
138
        # The only files returned by this are those from the version
167
139
        for path, entry in self.inventory.iter_entries():
168
 
            yield path, 'V', entry.kind, entry.file_id, entry
169
 
 
170
 
    def get_symlink_target(self, file_id):
171
 
        ie = self._inventory[file_id]
172
 
        return ie.symlink_target;
 
140
            yield path, 'V', entry.kind, entry.file_id
173
141
 
174
142
 
175
143
class EmptyTree(Tree):
176
144
    def __init__(self):
 
145
        from bzrlib.inventory import Inventory
177
146
        self._inventory = Inventory()
178
147
 
179
 
    def get_symlink_target(self, file_id):
180
 
        return None
181
 
 
182
148
    def has_filename(self, filename):
183
149
        return False
184
150
 
185
151
    def list_files(self):
186
 
        return iter([])
 
152
        if False:  # just to make it a generator
 
153
            yield None
187
154
    
188
 
    def __contains__(self, file_id):
189
 
        return file_id in self._inventory
190
 
 
191
 
    def get_file_sha1(self, file_id):
192
 
        assert self._inventory[file_id].kind == "root_directory"
193
 
        return None
194
155
 
195
156
 
196
157
######################################################################
262
223
######################################################################
263
224
# export
264
225
 
265
 
def dir_exporter(tree, dest, root):
 
226
def dir_exporter(tree, dest):
266
227
    """Export this tree to a new directory.
267
228
 
268
229
    `dest` should not exist, and will be created holding the
279
240
    mutter('export version %r' % tree)
280
241
    inv = tree.inventory
281
242
    for dp, ie in inv.iter_entries():
282
 
        ie.put_on_disk(dest, dp, tree)
283
 
 
 
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))
284
252
exporters['dir'] = dir_exporter
285
253
 
286
254
try:
288
256
except ImportError:
289
257
    pass
290
258
else:
291
 
    def get_root_name(dest):
292
 
        """Get just the root name for a tarball.
293
 
 
294
 
        >>> get_root_name('mytar.tar')
295
 
        'mytar'
296
 
        >>> get_root_name('mytar.tar.bz2')
297
 
        'mytar'
298
 
        >>> get_root_name('tar.tar.tar.tgz')
299
 
        'tar.tar.tar'
300
 
        >>> get_root_name('bzr-0.0.5.tar.gz')
301
 
        'bzr-0.0.5'
302
 
        >>> get_root_name('a/long/path/mytar.tgz')
303
 
        'mytar'
304
 
        >>> get_root_name('../parent/../dir/other.tbz2')
305
 
        'other'
306
 
        """
307
 
        endings = ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']
308
 
        dest = os.path.basename(dest)
309
 
        for end in endings:
310
 
            if dest.endswith(end):
311
 
                return dest[:-len(end)]
312
 
 
313
 
    def tar_exporter(tree, dest, root, compression=None):
 
259
    def tar_exporter(tree, dest, compression=None):
314
260
        """Export this tree to a new tar file.
315
261
 
316
262
        `dest` will be created holding the contents of this tree; if it
319
265
        from time import time
320
266
        now = time()
321
267
        compression = str(compression or '')
322
 
        if root is None:
323
 
            root = get_root_name(dest)
324
268
        try:
325
269
            ball = tarfile.open(dest, 'w:' + compression)
326
270
        except tarfile.CompressionError, e:
329
273
        inv = tree.inventory
330
274
        for dp, ie in inv.iter_entries():
331
275
            mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
332
 
            item, fileobj = ie.get_tar_item(root, dp, now, tree)
 
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
 
333
295
            ball.addfile(item, fileobj)
334
296
        ball.close()
335
 
 
336
297
    exporters['tar'] = tar_exporter
337
298
 
338
 
    def tgz_exporter(tree, dest, root):
339
 
        tar_exporter(tree, dest, root, compression='gz')
 
299
    def tgz_exporter(tree, dest):
 
300
        tar_exporter(tree, dest, compression='gz')
340
301
    exporters['tgz'] = tgz_exporter
341
302
 
342
 
    def tbz_exporter(tree, dest, root):
343
 
        tar_exporter(tree, dest, root, compression='bz2')
 
303
    def tbz_exporter(tree, dest):
 
304
        tar_exporter(tree, dest, compression='bz2')
344
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