~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-01 19:18:09 UTC
  • mfrom: (6459 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6460.
  • Revision ID: jelmer@samba.org-20120201191809-xn340a5i5v4fqsfu
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
 
20
22
import os
21
23
 
22
24
from bzrlib.lazy_import import lazy_import
35
37
    rules,
36
38
    trace,
37
39
    )
 
40
from bzrlib.i18n import gettext
38
41
""")
39
42
 
40
43
from bzrlib.decorators import needs_read_lock
58
61
    trees or versioned trees.
59
62
    """
60
63
 
 
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
 
61
72
    def changes_from(self, other, want_unchanged=False, specific_files=None,
62
73
        extra_trees=None, require_versioned=False, include_root=False,
63
74
        want_unversioned=False):
277
288
 
278
289
        :param file_id: The file_id of the file.
279
290
        :param path: The path of the file.
 
291
 
280
292
        If both file_id and path are supplied, an implementation may use
281
293
        either one.
 
294
 
 
295
        :returns: A single byte string for the whole file.
282
296
        """
283
297
        my_file = self.get_file(file_id, path)
284
298
        try:
297
311
        """
298
312
        return osutils.split_lines(self.get_file_text(file_id, path))
299
313
 
 
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
 
300
328
    def get_file_sha1(self, file_id, path=None, stat_value=None):
301
329
        """Return the SHA1 file for a file.
302
330
 
 
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
 
303
335
        :param file_id: The handle for this file.
304
336
        :param path: The path that this file can be found at.
305
337
            These must point to the same object.
325
357
        """
326
358
        raise NotImplementedError(self.get_file_size)
327
359
 
328
 
    def get_file_by_path(self, path):
329
 
        raise NotImplementedError(self.get_file_by_path)
330
 
 
331
360
    def is_executable(self, file_id, path=None):
332
361
        """Check if a file is executable.
333
362
 
602
631
        prefs = self.iter_search_rules([path], filter_pref_names).next()
603
632
        stk = filters._get_filter_stack_for(prefs)
604
633
        if 'filters' in debug.debug_flags:
605
 
            trace.note("*** %s content-filter: %s => %r" % (path,prefs,stk))
 
634
            trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path,prefs,stk))
606
635
        return stk
607
636
 
608
637
    def _content_filter_stack_provider(self):
745
774
    inventory = property(_get_inventory,
746
775
                         doc="Inventory of this Tree")
747
776
 
 
777
    def _unpack_file_id(self, file_id):
 
778
        """Find the inventory and inventory file id for a tree file id.
 
779
 
 
780
        :param file_id: The tree file id, as bytestring or tuple
 
781
        :return: Inventory and inventory file id
 
782
        """
 
783
        if isinstance(file_id, tuple):
 
784
            if len(file_id) != 1:
 
785
                raise ValueError("nested trees not yet supported: %r" % file_id)
 
786
            file_id = file_id[0]
 
787
        return self.inventory, file_id
 
788
 
748
789
    @needs_read_lock
749
790
    def path2id(self, path):
750
791
        """Return the id for path in this tree."""
751
 
        return self._inventory.path2id(path)
 
792
        return self._path2inv_file_id(path)[1]
 
793
 
 
794
    def _path2inv_file_id(self, path):
 
795
        """Lookup a inventory and inventory file id by path.
 
796
 
 
797
        :param path: Path to look up
 
798
        :return: tuple with inventory and inventory file id
 
799
        """
 
800
        return self.inventory, self.inventory.path2id(path)
752
801
 
753
802
    def id2path(self, file_id):
754
803
        """Return the path for a file id.
755
804
 
756
805
        :raises NoSuchId:
757
806
        """
758
 
        return self.inventory.id2path(file_id)
 
807
        inventory, file_id = self._unpack_file_id(file_id)
 
808
        return inventory.id2path(file_id)
759
809
 
760
810
    def has_id(self, file_id):
761
 
        return self.inventory.has_id(file_id)
 
811
        inventory, file_id = self._unpack_file_id(file_id)
 
812
        return inventory.has_id(file_id)
762
813
 
763
814
    def has_or_had_id(self, file_id):
764
 
        return self.inventory.has_id(file_id)
 
815
        inventory, file_id = self._unpack_file_id(file_id)
 
816
        return inventory.has_id(file_id)
765
817
 
766
818
    def all_file_ids(self):
767
 
        return set(self.inventory)
 
819
        return set(
 
820
            [entry.file_id for path, entry in self.iter_entries_by_dir()])
768
821
 
769
822
    @deprecated_method(deprecated_in((2, 4, 0)))
770
823
    def __iter__(self):
771
 
        return iter(self.inventory)
 
824
        return iter(self.all_file_ids())
772
825
 
773
826
    def filter_unversioned_files(self, paths):
774
827
        """Filter out paths that are versioned.
778
831
        # NB: we specifically *don't* call self.has_filename, because for
779
832
        # WorkingTrees that can indicate files that exist on disk but that
780
833
        # are not versioned.
781
 
        pred = self.inventory.has_filename
782
 
        return set((p for p in paths if not pred(p)))
 
834
        return set((p for p in paths if self.path2id(p) is None))
783
835
 
784
836
    @needs_read_lock
785
837
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
794
846
            down to specific_file_ids that have been requested. This has no
795
847
            impact if specific_file_ids is None.
796
848
        """
 
849
        if specific_file_ids is None:
 
850
            inventory_file_ids = None
 
851
        else:
 
852
            inventory_file_ids = []
 
853
            for tree_file_id in specific_file_ids:
 
854
                inventory, inv_file_id = self._unpack_file_id(tree_file_id)
 
855
                if not inventory is self.inventory: # for now
 
856
                    raise AssertionError("%r != %r" % (
 
857
                        inventory, self.inventory))
 
858
                inventory_file_ids.append(inv_file_id)
797
859
        return self.inventory.iter_entries_by_dir(
798
 
            specific_file_ids=specific_file_ids, yield_parents=yield_parents)
 
860
            specific_file_ids=inventory_file_ids, yield_parents=yield_parents)
799
861
 
 
862
    @deprecated_method(deprecated_in((2, 5, 0)))
800
863
    def get_file_by_path(self, path):
801
 
        return self.get_file(self._inventory.path2id(path), path)
 
864
        return self.get_file(self.path2id(path), path)
802
865
 
803
866
 
804
867
def find_ids_across_trees(filenames, trees, require_versioned=True):
952
1015
        if source_kind != target_kind:
953
1016
            changed_content = True
954
1017
        elif source_kind == 'file':
955
 
            if (self.source.get_file_sha1(file_id, source_path, source_stat) !=
956
 
                self.target.get_file_sha1(file_id, target_path, target_stat)):
 
1018
            if not self.file_content_matches(file_id, file_id, source_path,
 
1019
                    target_path, source_stat, target_stat):
957
1020
                changed_content = True
958
1021
        elif source_kind == 'symlink':
959
1022
            if (self.source.get_symlink_target(file_id) !=
1272
1335
                    changed_file_ids.add(result[0])
1273
1336
                    yield result
1274
1337
 
 
1338
    @needs_read_lock
 
1339
    def file_content_matches(self, source_file_id, target_file_id,
 
1340
            source_path=None, target_path=None, source_stat=None, target_stat=None):
 
1341
        """Check if two files are the same in the source and target trees.
 
1342
 
 
1343
        This only checks that the contents of the files are the same,
 
1344
        it does not touch anything else.
 
1345
 
 
1346
        :param source_file_id: File id of the file in the source tree
 
1347
        :param target_file_id: File id of the file in the target tree
 
1348
        :param source_path: Path of the file in the source tree
 
1349
        :param target_path: Path of the file in the target tree
 
1350
        :param source_stat: Optional stat value of the file in the source tree
 
1351
        :param target_stat: Optional stat value of the file in the target tree
 
1352
        :return: Boolean indicating whether the files have the same contents
 
1353
        """
 
1354
        source_verifier_kind, source_verifier_data = self.source.get_file_verifier(
 
1355
            source_file_id, source_path, source_stat)
 
1356
        target_verifier_kind, target_verifier_data = self.target.get_file_verifier(
 
1357
            target_file_id, target_path, target_stat)
 
1358
        if source_verifier_kind == target_verifier_kind:
 
1359
            return (source_verifier_data == target_verifier_data)
 
1360
        # Fall back to SHA1 for now
 
1361
        if source_verifier_kind != "SHA1":
 
1362
            source_sha1 = self.source.get_file_sha1(source_file_id,
 
1363
                    source_path, source_stat)
 
1364
        else:
 
1365
            source_sha1 = source_verifier_data
 
1366
        if target_verifier_kind != "SHA1":
 
1367
            target_sha1 = self.target.get_file_sha1(target_file_id,
 
1368
                    target_path, target_stat)
 
1369
        else:
 
1370
            target_sha1 = target_verifier_data
 
1371
        return (source_sha1 == target_sha1)
1275
1372
 
1276
1373
InterTree.register_optimiser(InterTree)
1277
1374