~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

Exclude more files from dumb-rsync upload

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
20
import os
 
21
from cStringIO import StringIO
22
22
 
 
23
import bzrlib
23
24
from bzrlib.trace import mutter, note
24
 
from bzrlib.errors import BzrError
 
25
from bzrlib.errors import BzrError, BzrCheckError
 
26
from bzrlib.inventory import Inventory
 
27
from bzrlib.osutils import appendpath, fingerprint_file
25
28
 
26
 
import bzrlib
27
29
 
28
30
exporters = {}
29
31
 
56
58
    def has_id(self, file_id):
57
59
        return self.inventory.has_id(file_id)
58
60
 
 
61
    def has_or_had_id(self, file_id):
 
62
        if file_id == self.inventory.root.file_id:
 
63
            return True
 
64
        return self.inventory.has_id(file_id)
 
65
 
59
66
    __contains__ = has_id
60
67
 
61
68
    def __iter__(self):
64
71
    def id2path(self, file_id):
65
72
        return self.inventory.id2path(file_id)
66
73
 
 
74
    def kind(self, file_id):
 
75
        raise NotImplementedError("subclasses must implement kind")
 
76
 
67
77
    def _get_inventory(self):
68
78
        return self._inventory
 
79
    
 
80
    def get_file_by_path(self, path):
 
81
        return self.get_file(self._inventory.path2id(path))
69
82
 
70
83
    inventory = property(_get_inventory,
71
84
                         doc="Inventory of this Tree")
72
85
 
73
86
    def _check_retrieved(self, ie, f):
 
87
        if not __debug__:
 
88
            return  
74
89
        fp = fingerprint_file(f)
75
90
        f.seek(0)
76
91
        
88
103
                     "store is probably damaged/corrupt"])
89
104
 
90
105
 
91
 
    def print_file(self, fileid):
92
 
        """Print file with id `fileid` to stdout."""
 
106
    def print_file(self, file_id):
 
107
        """Print file with id `file_id` to stdout."""
93
108
        import sys
94
 
        pumpfile(self.get_file(fileid), sys.stdout)
 
109
        sys.stdout.write(self.get_file_text(file_id))
95
110
        
96
111
        
97
112
    def export(self, dest, format='dir', root=None):
115
130
           or at least passing a description to the constructor.
116
131
    """
117
132
    
118
 
    def __init__(self, store, inv):
119
 
        self._store = store
 
133
    def __init__(self, weave_store, inv, revision_id):
 
134
        self._weave_store = weave_store
120
135
        self._inventory = inv
 
136
        self._revision_id = revision_id
 
137
 
 
138
    def get_weave(self, file_id):
 
139
        # FIXME: RevisionTree should be given a branch
 
140
        # not a store, or the store should know the branch.
 
141
        import bzrlib.transactions as transactions
 
142
        return self._weave_store.get_weave(file_id,
 
143
            transactions.PassThroughTransaction())
 
144
 
 
145
 
 
146
    def get_file_lines(self, file_id):
 
147
        ie = self._inventory[file_id]
 
148
        weave = self.get_weave(file_id)
 
149
        return weave.get(ie.revision)
 
150
        
 
151
 
 
152
    def get_file_text(self, file_id):
 
153
        return ''.join(self.get_file_lines(file_id))
 
154
 
121
155
 
122
156
    def get_file(self, file_id):
123
 
        ie = self._inventory[file_id]
124
 
        f = self._store[ie.text_id]
125
 
        mutter("  get fileid{%s} from %r" % (file_id, self))
126
 
        self._check_retrieved(ie, f)
127
 
        return f
 
157
        return StringIO(self.get_file_text(file_id))
128
158
 
129
159
    def get_file_size(self, file_id):
130
160
        return self._inventory[file_id].text_size
131
161
 
132
162
    def get_file_sha1(self, file_id):
133
163
        ie = self._inventory[file_id]
134
 
        return ie.text_sha1
 
164
        if ie.kind == "file":
 
165
            return ie.text_sha1
 
166
 
 
167
    def is_executable(self, file_id):
 
168
        ie = self._inventory[file_id]
 
169
        if ie.kind != "file":
 
170
            return None 
 
171
        return self._inventory[file_id].executable
135
172
 
136
173
    def has_filename(self, filename):
137
174
        return bool(self.inventory.path2id(filename))
139
176
    def list_files(self):
140
177
        # The only files returned by this are those from the version
141
178
        for path, entry in self.inventory.iter_entries():
142
 
            yield path, 'V', entry.kind, entry.file_id
 
179
            yield path, 'V', entry.kind, entry.file_id, entry
 
180
 
 
181
    def get_symlink_target(self, file_id):
 
182
        ie = self._inventory[file_id]
 
183
        return ie.symlink_target;
 
184
 
 
185
    def kind(self, file_id):
 
186
        return self._inventory[file_id].kind
143
187
 
144
188
 
145
189
class EmptyTree(Tree):
146
 
    def __init__(self, root_id):
147
 
        from bzrlib.inventory import Inventory
148
 
        self._inventory = Inventory(root_id)
 
190
    def __init__(self):
 
191
        self._inventory = Inventory()
 
192
 
 
193
    def get_symlink_target(self, file_id):
 
194
        return None
149
195
 
150
196
    def has_filename(self, filename):
151
197
        return False
152
198
 
 
199
    def kind(self, file_id):
 
200
        assert self._inventory[file_id].kind == "root_directory"
 
201
        return "root_directory"
 
202
 
153
203
    def list_files(self):
154
 
        if False:  # just to make it a generator
155
 
            yield None
 
204
        return iter([])
156
205
    
 
206
    def __contains__(self, file_id):
 
207
        return file_id in self._inventory
 
208
 
 
209
    def get_file_sha1(self, file_id):
 
210
        assert self._inventory[file_id].kind == "root_directory"
 
211
        return None
157
212
 
158
213
 
159
214
######################################################################
239
294
    """
240
295
    import os
241
296
    os.mkdir(dest)
242
 
    mutter('export version %r' % tree)
 
297
    mutter('export version %r', tree)
243
298
    inv = tree.inventory
244
299
    for dp, ie in inv.iter_entries():
245
 
        kind = ie.kind
246
 
        fullpath = appendpath(dest, dp)
247
 
        if kind == 'directory':
248
 
            os.mkdir(fullpath)
249
 
        elif kind == 'file':
250
 
            pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
251
 
        else:
252
 
            raise BzrError("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
253
 
        mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
 
300
        if dp != ".bzrignore":
 
301
            ie.put_on_disk(dest, dp, tree)
 
302
 
254
303
exporters['dir'] = dir_exporter
255
304
 
256
305
try:
295
344
            ball = tarfile.open(dest, 'w:' + compression)
296
345
        except tarfile.CompressionError, e:
297
346
            raise BzrError(str(e))
298
 
        mutter('export version %r' % tree)
 
347
        mutter('export version %r', tree)
299
348
        inv = tree.inventory
300
349
        for dp, ie in inv.iter_entries():
301
 
            mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
302
 
            item = tarfile.TarInfo(os.path.join(root, dp))
303
 
            # TODO: would be cool to actually set it to the timestamp of the
304
 
            # revision it was last changed
305
 
            item.mtime = now
306
 
            if ie.kind == 'directory':
307
 
                item.type = tarfile.DIRTYPE
308
 
                fileobj = None
309
 
                item.name += '/'
310
 
                item.size = 0
311
 
                item.mode = 0755
312
 
            elif ie.kind == 'file':
313
 
                item.type = tarfile.REGTYPE
314
 
                fileobj = tree.get_file(ie.file_id)
315
 
                item.size = _find_file_size(fileobj)
316
 
                item.mode = 0644
317
 
            else:
318
 
                raise BzrError("don't know how to export {%s} of kind %r" %
319
 
                        (ie.file_id, ie.kind))
320
 
 
321
 
            ball.addfile(item, fileobj)
 
350
            if dp != ".bzrignore":
 
351
                mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
 
352
                item, fileobj = ie.get_tar_item(root, dp, now, tree)
 
353
                ball.addfile(item, fileobj)
322
354
        ball.close()
 
355
 
323
356
    exporters['tar'] = tar_exporter
324
357
 
325
358
    def tgz_exporter(tree, dest, root):
329
362
    def tbz_exporter(tree, dest, root):
330
363
        tar_exporter(tree, dest, root, compression='bz2')
331
364
    exporters['tbz2'] = tbz_exporter
332
 
 
333
 
 
334
 
def _find_file_size(fileobj):
335
 
    offset = fileobj.tell()
336
 
    try:
337
 
        fileobj.seek(0, 2)
338
 
        size = fileobj.tell()
339
 
    except TypeError:
340
 
        # gzip doesn't accept second argument to seek()
341
 
        fileobj.seek(0)
342
 
        size = 0
343
 
        while True:
344
 
            nread = len(fileobj.read())
345
 
            if nread == 0:
346
 
                break
347
 
            size += nread
348
 
    fileobj.seek(offset)
349
 
    return size