~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Jelmer Vernooij
  • Date: 2011-05-10 07:46:15 UTC
  • mfrom: (5844 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5845.
  • Revision ID: jelmer@samba.org-20110510074615-eptod049ndjxc4i7
Merge bzr.dev.

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 __future__ import absolute_import
21
 
 
22
20
import os
23
21
 
24
22
from bzrlib.lazy_import import lazy_import
37
35
    rules,
38
36
    trace,
39
37
    )
40
 
from bzrlib.i18n import gettext
41
38
""")
42
39
 
43
40
from bzrlib.decorators import needs_read_lock
61
58
    trees or versioned trees.
62
59
    """
63
60
 
64
 
    def has_versioned_directories(self):
65
 
        """Whether this tree can contain explicitly versioned directories.
66
 
 
67
 
        This defaults to True, but some implementations may want to override
68
 
        it.
69
 
        """
70
 
        return True
71
 
 
72
61
    def changes_from(self, other, want_unchanged=False, specific_files=None,
73
62
        extra_trees=None, require_versioned=False, include_root=False,
74
63
        want_unversioned=False):
138
127
    def has_id(self, file_id):
139
128
        raise NotImplementedError(self.has_id)
140
129
 
141
 
    @deprecated_method(deprecated_in((2, 4, 0)))
142
130
    def __contains__(self, file_id):
143
131
        return self.has_id(file_id)
144
132
 
186
174
             g
187
175
 
188
176
        The yield order (ignoring root) would be::
189
 
 
190
177
          a, f, a/b, a/d, a/b/c, a/d/e, f/g
191
178
 
192
179
        :param yield_parents: If True, yield the parents from the root leading
288
275
 
289
276
        :param file_id: The file_id of the file.
290
277
        :param path: The path of the file.
291
 
 
292
278
        If both file_id and path are supplied, an implementation may use
293
279
        either one.
294
 
 
295
 
        :returns: A single byte string for the whole file.
296
280
        """
297
281
        my_file = self.get_file(file_id, path)
298
282
        try:
305
289
 
306
290
        :param file_id: The file_id of the file.
307
291
        :param path: The path of the file.
308
 
 
309
292
        If both file_id and path are supplied, an implementation may use
310
293
        either one.
311
294
        """
312
295
        return osutils.split_lines(self.get_file_text(file_id, path))
313
296
 
314
 
    def get_file_verifier(self, file_id, path=None, stat_value=None):
315
 
        """Return a verifier for a file.
316
 
 
317
 
        The default implementation returns a sha1.
318
 
 
319
 
        :param file_id: The handle for this file.
320
 
        :param path: The path that this file can be found at.
321
 
            These must point to the same object.
322
 
        :param stat_value: Optional stat value for the object
323
 
        :return: Tuple with verifier name and verifier data
324
 
        """
325
 
        return ("SHA1", self.get_file_sha1(file_id, path=path,
326
 
            stat_value=stat_value))
327
 
 
328
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
297
    def get_file_sha1(self, file_id, path=None):
329
298
        """Return the SHA1 file for a file.
330
299
 
331
 
        :note: callers should use get_file_verifier instead
332
 
            where possible, as the underlying repository implementation may
333
 
            have quicker access to a non-sha1 verifier.
334
 
 
335
300
        :param file_id: The handle for this file.
336
301
        :param path: The path that this file can be found at.
337
302
            These must point to the same object.
338
 
        :param stat_value: Optional stat value for the object
339
303
        """
340
304
        raise NotImplementedError(self.get_file_sha1)
341
305
 
357
321
        """
358
322
        raise NotImplementedError(self.get_file_size)
359
323
 
 
324
    def get_file_by_path(self, path):
 
325
        raise NotImplementedError(self.get_file_by_path)
 
326
 
360
327
    def is_executable(self, file_id, path=None):
361
328
        """Check if a file is executable.
362
329
 
392
359
            cur_file = (self.get_file_text(file_id),)
393
360
            yield identifier, cur_file
394
361
 
395
 
    def get_symlink_target(self, file_id, path=None):
 
362
    def get_symlink_target(self, file_id):
396
363
        """Get the target for a given file_id.
397
364
 
398
365
        It is assumed that the caller already knows that file_id is referencing
399
366
        a symlink.
400
367
        :param file_id: Handle for the symlink entry.
401
 
        :param path: The path of the file.
402
 
        If both file_id and path are supplied, an implementation may use
403
 
        either one.
404
368
        :return: The path the symlink points to.
405
369
        """
406
370
        raise NotImplementedError(self.get_symlink_target)
407
371
 
 
372
 
408
373
    def get_root_id(self):
409
374
        """Return the file_id for the root of this tree."""
410
375
        raise NotImplementedError(self.get_root_id)
631
596
        prefs = self.iter_search_rules([path], filter_pref_names).next()
632
597
        stk = filters._get_filter_stack_for(prefs)
633
598
        if 'filters' in debug.debug_flags:
634
 
            trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path,prefs,stk))
 
599
            trace.note("*** %s content-filter: %s => %r" % (path,prefs,stk))
635
600
        return stk
636
601
 
637
602
    def _content_filter_stack_provider(self):
826
791
        return self.inventory.iter_entries_by_dir(
827
792
            specific_file_ids=specific_file_ids, yield_parents=yield_parents)
828
793
 
829
 
    @deprecated_method(deprecated_in((2, 5, 0)))
830
794
    def get_file_by_path(self, path):
831
 
        return self.get_file(self.path2id(path), path)
 
795
        return self.get_file(self._inventory.path2id(path), path)
 
796
 
 
797
 
 
798
######################################################################
 
799
# diff
 
800
 
 
801
# TODO: Merge these two functions into a single one that can operate
 
802
# on either a whole tree or a set of files.
 
803
 
 
804
# TODO: Return the diff in order by filename, not by category or in
 
805
# random order.  Can probably be done by lock-stepping through the
 
806
# filenames from both trees.
 
807
 
 
808
 
 
809
def file_status(filename, old_tree, new_tree):
 
810
    """Return single-letter status, old and new names for a file.
 
811
 
 
812
    The complexity here is in deciding how to represent renames;
 
813
    many complex cases are possible.
 
814
    """
 
815
    old_inv = old_tree.inventory
 
816
    new_inv = new_tree.inventory
 
817
    new_id = new_inv.path2id(filename)
 
818
    old_id = old_inv.path2id(filename)
 
819
 
 
820
    if not new_id and not old_id:
 
821
        # easy: doesn't exist in either; not versioned at all
 
822
        if new_tree.is_ignored(filename):
 
823
            return 'I', None, None
 
824
        else:
 
825
            return '?', None, None
 
826
    elif new_id:
 
827
        # There is now a file of this name, great.
 
828
        pass
 
829
    else:
 
830
        # There is no longer a file of this name, but we can describe
 
831
        # what happened to the file that used to have
 
832
        # this name.  There are two possibilities: either it was
 
833
        # deleted entirely, or renamed.
 
834
        if new_inv.has_id(old_id):
 
835
            return 'X', old_inv.id2path(old_id), new_inv.id2path(old_id)
 
836
        else:
 
837
            return 'D', old_inv.id2path(old_id), None
 
838
 
 
839
    # if the file_id is new in this revision, it is added
 
840
    if new_id and not old_inv.has_id(new_id):
 
841
        return 'A'
 
842
 
 
843
    # if there used to be a file of this name, but that ID has now
 
844
    # disappeared, it is deleted
 
845
    if old_id and not new_inv.has_id(old_id):
 
846
        return 'D'
 
847
 
 
848
    return 'wtf?'
832
849
 
833
850
 
834
851
def find_ids_across_trees(filenames, trees, require_versioned=True):
841
858
        None)
842
859
    :param trees: The trees to find file_ids within
843
860
    :param require_versioned: if true, all specified filenames must occur in
844
 
        at least one tree.
 
861
    at least one tree.
845
862
    :return: a set of file ids for the specified filenames and their children.
846
863
    """
847
864
    if not filenames:
982
999
        if source_kind != target_kind:
983
1000
            changed_content = True
984
1001
        elif source_kind == 'file':
985
 
            if not self.file_content_matches(file_id, file_id, source_path,
986
 
                    target_path, source_stat, target_stat):
 
1002
            if (self.source.get_file_sha1(file_id, source_path, source_stat) !=
 
1003
                self.target.get_file_sha1(file_id, target_path, target_stat)):
987
1004
                changed_content = True
988
1005
        elif source_kind == 'symlink':
989
1006
            if (self.source.get_symlink_target(file_id) !=
1302
1319
                    changed_file_ids.add(result[0])
1303
1320
                    yield result
1304
1321
 
1305
 
    @needs_read_lock
1306
 
    def file_content_matches(self, source_file_id, target_file_id,
1307
 
            source_path=None, target_path=None, source_stat=None, target_stat=None):
1308
 
        """Check if two files are the same in the source and target trees.
1309
 
 
1310
 
        This only checks that the contents of the files are the same,
1311
 
        it does not touch anything else.
1312
 
 
1313
 
        :param source_file_id: File id of the file in the source tree
1314
 
        :param target_file_id: File id of the file in the target tree
1315
 
        :param source_path: Path of the file in the source tree
1316
 
        :param target_path: Path of the file in the target tree
1317
 
        :param source_stat: Optional stat value of the file in the source tree
1318
 
        :param target_stat: Optional stat value of the file in the target tree
1319
 
        :return: Boolean indicating whether the files have the same contents
1320
 
        """
1321
 
        source_verifier_kind, source_verifier_data = self.source.get_file_verifier(
1322
 
            source_file_id, source_path, source_stat)
1323
 
        target_verifier_kind, target_verifier_data = self.target.get_file_verifier(
1324
 
            target_file_id, target_path, target_stat)
1325
 
        if source_verifier_kind == target_verifier_kind:
1326
 
            return (source_verifier_data == target_verifier_data)
1327
 
        # Fall back to SHA1 for now
1328
 
        if source_verifier_kind != "SHA1":
1329
 
            source_sha1 = self.source.get_file_sha1(source_file_id,
1330
 
                    source_path, source_stat)
1331
 
        else:
1332
 
            source_sha1 = source_verifier_data
1333
 
        if target_verifier_kind != "SHA1":
1334
 
            target_sha1 = self.target.get_file_sha1(target_file_id,
1335
 
                    target_path, target_stat)
1336
 
        else:
1337
 
            target_sha1 = target_verifier_data
1338
 
        return (source_sha1 == target_sha1)
1339
1322
 
1340
1323
InterTree.register_optimiser(InterTree)
1341
1324