~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Robert Collins
  • Date: 2005-10-06 00:52:53 UTC
  • Revision ID: robertc@robertcollins.net-20051006005253-415c38ad22094f13
define some expected behaviour for inventory_entry.snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
from cStringIO import StringIO
22
22
 
23
23
import bzrlib
 
24
from bzrlib.trace import mutter, note
24
25
from bzrlib.errors import BzrError, BzrCheckError
25
26
from bzrlib.inventory import Inventory
26
 
from bzrlib.osutils import fingerprint_file
27
 
import bzrlib.revision
28
 
from bzrlib.trace import mutter, note
 
27
from bzrlib.osutils import appendpath, fingerprint_file
 
28
 
 
29
 
 
30
exporters = {}
29
31
 
30
32
class Tree(object):
31
33
    """Abstract file tree.
49
51
    trees or versioned trees.
50
52
    """
51
53
    
52
 
    def conflicts(self):
53
 
        """Get a list of the conflicts in the tree.
54
 
 
55
 
        Each conflict is an instance of bzrlib.conflicts.Conflict.
56
 
        """
57
 
        return []
58
 
 
59
 
    def get_parent_ids(self):
60
 
        """Get the parent ids for this tree. 
61
 
 
62
 
        :return: a list of parent ids. [] is returned to indicate
63
 
        a tree with no parents.
64
 
        :raises: BzrError if the parents are not known.
65
 
        """
66
 
        raise NotImplementedError(self.get_parent_ids)
67
 
    
68
54
    def has_filename(self, filename):
69
55
        """True if the tree has given filename."""
70
56
        raise NotImplementedError()
72
58
    def has_id(self, file_id):
73
59
        return self.inventory.has_id(file_id)
74
60
 
75
 
    def has_or_had_id(self, file_id):
76
 
        if file_id == self.inventory.root.file_id:
77
 
            return True
78
 
        return self.inventory.has_id(file_id)
79
 
 
80
61
    __contains__ = has_id
81
62
 
82
63
    def __iter__(self):
85
66
    def id2path(self, file_id):
86
67
        return self.inventory.id2path(file_id)
87
68
 
88
 
    def kind(self, file_id):
89
 
        raise NotImplementedError("subclasses must implement kind")
90
 
 
91
69
    def _get_inventory(self):
92
70
        return self._inventory
93
71
    
121
99
        """Print file with id `file_id` to stdout."""
122
100
        import sys
123
101
        sys.stdout.write(self.get_file_text(file_id))
124
 
 
125
 
    def lock_read(self):
126
 
        pass
127
 
 
128
 
    def unknowns(self):
129
 
        """What files are present in this tree and unknown.
130
 
        
131
 
        :return: an iterator over the unknown files.
132
 
        """
133
 
        return iter([])
134
 
 
135
 
    def unlock(self):
136
 
        pass
137
 
 
138
 
    def filter_unversioned_files(self, paths):
139
 
        """Filter out paths that are not versioned.
140
 
 
141
 
        :return: set of paths.
142
 
        """
143
 
        # NB: we specifically *don't* call self.has_filename, because for
144
 
        # WorkingTrees that can indicate files that exist on disk but that 
145
 
        # are not versioned.
146
 
        pred = self.inventory.has_filename
147
 
        return set((p for p in paths if not pred(p)))
148
 
        
149
 
        
 
102
        
 
103
        
 
104
    def export(self, dest, format='dir', root=None):
 
105
        """Export this tree."""
 
106
        try:
 
107
            exporter = exporters[format]
 
108
        except KeyError:
 
109
            from bzrlib.errors import BzrCommandError
 
110
            raise BzrCommandError("export format %r not supported" % format)
 
111
        exporter(self, dest, root)
 
112
 
 
113
 
 
114
 
150
115
class RevisionTree(Tree):
151
116
    """Tree viewing a previous revision.
152
117
 
157
122
           or at least passing a description to the constructor.
158
123
    """
159
124
    
160
 
    def __init__(self, branch, inv, revision_id):
161
 
        # for compatability the 'branch' parameter has not been renamed to 
162
 
        # repository at this point. However, we should change RevisionTree's
163
 
        # construction to always be via Repository and not via direct 
164
 
        # construction - this will mean that we can change the constructor
165
 
        # with much less chance of breaking client code.
166
 
        self._repository = branch
167
 
        self._weave_store = branch.weave_store
 
125
    def __init__(self, weave_store, inv, revision_id):
 
126
        self._weave_store = weave_store
168
127
        self._inventory = inv
169
128
        self._revision_id = revision_id
170
129
 
171
 
    def get_parent_ids(self):
172
 
        """See Tree.get_parent_ids.
173
 
 
174
 
        A RevisionTree's parents match the revision graph.
175
 
        """
176
 
        parent_ids = self._repository.get_revision(self._revision_id).parent_ids
177
 
        return parent_ids
178
 
        
179
 
    def get_revision_id(self):
180
 
        """Return the revision id associated with this tree."""
181
 
        return self._revision_id
182
 
 
183
130
    def get_weave(self, file_id):
184
 
        return self._weave_store.get_weave(file_id,
185
 
                self._repository.get_transaction())
 
131
        return self._weave_store.get_weave(file_id)
 
132
 
186
133
 
187
134
    def get_file_lines(self, file_id):
188
135
        ie = self._inventory[file_id]
189
136
        weave = self.get_weave(file_id)
190
 
        return weave.get_lines(ie.revision)
 
137
        return weave.get(ie.revision)
 
138
        
191
139
 
192
140
    def get_file_text(self, file_id):
193
141
        return ''.join(self.get_file_lines(file_id))
194
142
 
 
143
 
195
144
    def get_file(self, file_id):
196
145
        return StringIO(self.get_file_text(file_id))
197
146
 
198
147
    def get_file_size(self, file_id):
199
148
        return self._inventory[file_id].text_size
200
149
 
201
 
    def get_file_sha1(self, file_id, path=None):
 
150
    def get_file_sha1(self, file_id):
202
151
        ie = self._inventory[file_id]
203
152
        if ie.kind == "file":
204
153
            return ie.text_sha1
205
 
        return None
206
 
 
207
 
    def get_file_mtime(self, file_id, path=None):
208
 
        ie = self._inventory[file_id]
209
 
        revision = self._repository.get_revision(ie.revision)
210
 
        return revision.timestamp
211
 
 
212
 
    def is_executable(self, file_id, path=None):
213
 
        ie = self._inventory[file_id]
214
 
        if ie.kind != "file":
215
 
            return None 
 
154
 
 
155
    def is_executable(self, file_id):
216
156
        return self._inventory[file_id].executable
217
157
 
218
158
    def has_filename(self, filename):
227
167
        ie = self._inventory[file_id]
228
168
        return ie.symlink_target;
229
169
 
230
 
    def kind(self, file_id):
231
 
        return self._inventory[file_id].kind
232
 
 
233
 
    def lock_read(self):
234
 
        self._repository.lock_read()
235
 
 
236
 
    def unlock(self):
237
 
        self._repository.unlock()
238
 
 
239
170
 
240
171
class EmptyTree(Tree):
241
 
 
242
172
    def __init__(self):
243
173
        self._inventory = Inventory()
244
174
 
245
 
    def get_parent_ids(self):
246
 
        """See Tree.get_parent_ids.
247
 
 
248
 
        An EmptyTree always has NULL_REVISION as the only parent.
249
 
        """
250
 
        return []
251
 
 
252
175
    def get_symlink_target(self, file_id):
253
176
        return None
254
177
 
255
178
    def has_filename(self, filename):
256
179
        return False
257
180
 
258
 
    def kind(self, file_id):
259
 
        assert self._inventory[file_id].kind == "root_directory"
260
 
        return "root_directory"
261
 
 
262
181
    def list_files(self):
263
182
        return iter([])
264
183
    
265
184
    def __contains__(self, file_id):
266
185
        return file_id in self._inventory
267
186
 
268
 
    def get_file_sha1(self, file_id, path=None):
 
187
    def get_file_sha1(self, file_id):
269
188
        assert self._inventory[file_id].kind == "root_directory"
270
189
        return None
271
190
 
336
255
            
337
256
 
338
257
 
 
258
######################################################################
 
259
# export
 
260
 
 
261
def dir_exporter(tree, dest, root):
 
262
    """Export this tree to a new directory.
 
263
 
 
264
    `dest` should not exist, and will be created holding the
 
265
    contents of this tree.
 
266
 
 
267
    TODO: To handle subdirectories we need to create the
 
268
           directories first.
 
269
 
 
270
    :note: If the export fails, the destination directory will be
 
271
           left in a half-assed state.
 
272
    """
 
273
    import os
 
274
    os.mkdir(dest)
 
275
    mutter('export version %r' % tree)
 
276
    inv = tree.inventory
 
277
    for dp, ie in inv.iter_entries():
 
278
        ie.put_on_disk(dest, dp, tree)
 
279
 
 
280
exporters['dir'] = dir_exporter
 
281
 
 
282
try:
 
283
    import tarfile
 
284
except ImportError:
 
285
    pass
 
286
else:
 
287
    def get_root_name(dest):
 
288
        """Get just the root name for a tarball.
 
289
 
 
290
        >>> get_root_name('mytar.tar')
 
291
        'mytar'
 
292
        >>> get_root_name('mytar.tar.bz2')
 
293
        'mytar'
 
294
        >>> get_root_name('tar.tar.tar.tgz')
 
295
        'tar.tar.tar'
 
296
        >>> get_root_name('bzr-0.0.5.tar.gz')
 
297
        'bzr-0.0.5'
 
298
        >>> get_root_name('a/long/path/mytar.tgz')
 
299
        'mytar'
 
300
        >>> get_root_name('../parent/../dir/other.tbz2')
 
301
        'other'
 
302
        """
 
303
        endings = ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']
 
304
        dest = os.path.basename(dest)
 
305
        for end in endings:
 
306
            if dest.endswith(end):
 
307
                return dest[:-len(end)]
 
308
 
 
309
    def tar_exporter(tree, dest, root, compression=None):
 
310
        """Export this tree to a new tar file.
 
311
 
 
312
        `dest` will be created holding the contents of this tree; if it
 
313
        already exists, it will be clobbered, like with "tar -c".
 
314
        """
 
315
        from time import time
 
316
        now = time()
 
317
        compression = str(compression or '')
 
318
        if root is None:
 
319
            root = get_root_name(dest)
 
320
        try:
 
321
            ball = tarfile.open(dest, 'w:' + compression)
 
322
        except tarfile.CompressionError, e:
 
323
            raise BzrError(str(e))
 
324
        mutter('export version %r' % tree)
 
325
        inv = tree.inventory
 
326
        for dp, ie in inv.iter_entries():
 
327
            mutter("  export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
 
328
            item, fileobj = ie.get_tar_item(root, dp, now, tree)
 
329
            ball.addfile(item, fileobj)
 
330
        ball.close()
 
331
 
 
332
    exporters['tar'] = tar_exporter
 
333
 
 
334
    def tgz_exporter(tree, dest, root):
 
335
        tar_exporter(tree, dest, root, compression='gz')
 
336
    exporters['tgz'] = tgz_exporter
 
337
 
 
338
    def tbz_exporter(tree, dest, root):
 
339
        tar_exporter(tree, dest, root, compression='bz2')
 
340
    exporters['tbz2'] = tbz_exporter