~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

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):
184
195
        """
185
196
        raise NotImplementedError(self.iter_entries_by_dir)
186
197
 
 
198
    def iter_child_entries(self, file_id, path=None):
 
199
        """Iterate over the children of a directory or tree reference.
 
200
 
 
201
        :param file_id: File id of the directory/tree-reference
 
202
        :param path: Optional path of the directory
 
203
        :raise NoSuchId: When the file_id does not exist
 
204
        :return: Iterator over entries in the directory
 
205
        """
 
206
        raise NotImplementedError(self.iter_child_entries)
 
207
 
187
208
    def list_files(self, include_root=False, from_dir=None, recursive=True):
188
209
        """List all files in this tree.
189
210
 
346
367
        """
347
368
        raise NotImplementedError(self.get_file_size)
348
369
 
349
 
    def get_file_by_path(self, path):
350
 
        raise NotImplementedError(self.get_file_by_path)
351
 
 
352
370
    def is_executable(self, file_id, path=None):
353
371
        """Check if a file is executable.
354
372
 
524
542
        return find_ids_across_trees(paths, [self] + list(trees), require_versioned)
525
543
 
526
544
    def iter_children(self, file_id):
527
 
        entry = self.iter_entries_by_dir([file_id]).next()[1]
528
 
        for child in getattr(entry, 'children', {}).itervalues():
529
 
            yield child.file_id
 
545
        """Iterate over the file ids of the children of an entry.
 
546
 
 
547
        :param file_id: File id of the entry
 
548
        :return: Iterator over child file ids.
 
549
        """
 
550
        raise NotImplementedError(self.iter_children)
530
551
 
531
552
    def lock_read(self):
532
553
        """Lock this tree for multiple read only operations.
533
 
        
 
554
 
534
555
        :return: A bzrlib.lock.LogicalLockResult.
535
556
        """
536
557
        pass
623
644
        prefs = self.iter_search_rules([path], filter_pref_names).next()
624
645
        stk = filters._get_filter_stack_for(prefs)
625
646
        if 'filters' in debug.debug_flags:
626
 
            trace.note("*** %s content-filter: %s => %r" % (path,prefs,stk))
 
647
            trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path,prefs,stk))
627
648
        return stk
628
649
 
629
650
    def _content_filter_stack_provider(self):
760
781
            yield cur_path
761
782
        # all done.
762
783
 
 
784
    @deprecated_method(deprecated_in((2, 5, 0)))
763
785
    def _get_inventory(self):
764
786
        return self._inventory
765
787
 
766
788
    inventory = property(_get_inventory,
767
789
                         doc="Inventory of this Tree")
768
790
 
 
791
    def _get_root_inventory(self):
 
792
        return self._inventory
 
793
 
 
794
    root_inventory = property(_get_root_inventory,
 
795
        doc="Root inventory of this tree")
 
796
 
 
797
    def _unpack_file_id(self, file_id):
 
798
        """Find the inventory and inventory file id for a tree file id.
 
799
 
 
800
        :param file_id: The tree file id, as bytestring or tuple
 
801
        :return: Inventory and inventory file id
 
802
        """
 
803
        if isinstance(file_id, tuple):
 
804
            if len(file_id) != 1:
 
805
                raise ValueError("nested trees not yet supported: %r" % file_id)
 
806
            file_id = file_id[0]
 
807
        return self.root_inventory, file_id
 
808
 
769
809
    @needs_read_lock
770
810
    def path2id(self, path):
771
811
        """Return the id for path in this tree."""
772
 
        return self._inventory.path2id(path)
 
812
        return self._path2inv_file_id(path)[1]
 
813
 
 
814
    def _path2inv_file_id(self, path):
 
815
        """Lookup a inventory and inventory file id by path.
 
816
 
 
817
        :param path: Path to look up
 
818
        :return: tuple with inventory and inventory file id
 
819
        """
 
820
        # FIXME: Support nested trees
 
821
        return self.root_inventory, self.root_inventory.path2id(path)
773
822
 
774
823
    def id2path(self, file_id):
775
824
        """Return the path for a file id.
776
825
 
777
826
        :raises NoSuchId:
778
827
        """
779
 
        return self.inventory.id2path(file_id)
 
828
        inventory, file_id = self._unpack_file_id(file_id)
 
829
        return inventory.id2path(file_id)
780
830
 
781
831
    def has_id(self, file_id):
782
 
        return self.inventory.has_id(file_id)
 
832
        inventory, file_id = self._unpack_file_id(file_id)
 
833
        return inventory.has_id(file_id)
783
834
 
784
835
    def has_or_had_id(self, file_id):
785
 
        return self.inventory.has_id(file_id)
 
836
        inventory, file_id = self._unpack_file_id(file_id)
 
837
        return inventory.has_id(file_id)
786
838
 
787
839
    def all_file_ids(self):
788
 
        return set(self.inventory)
 
840
        return set(
 
841
            [entry.file_id for path, entry in self.iter_entries_by_dir()])
789
842
 
790
843
    @deprecated_method(deprecated_in((2, 4, 0)))
791
844
    def __iter__(self):
792
 
        return iter(self.inventory)
 
845
        return iter(self.all_file_ids())
793
846
 
794
847
    def filter_unversioned_files(self, paths):
795
848
        """Filter out paths that are versioned.
799
852
        # NB: we specifically *don't* call self.has_filename, because for
800
853
        # WorkingTrees that can indicate files that exist on disk but that
801
854
        # are not versioned.
802
 
        pred = self.inventory.has_filename
803
 
        return set((p for p in paths if not pred(p)))
 
855
        return set((p for p in paths if self.path2id(p) is None))
804
856
 
805
857
    @needs_read_lock
806
858
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
815
867
            down to specific_file_ids that have been requested. This has no
816
868
            impact if specific_file_ids is None.
817
869
        """
818
 
        return self.inventory.iter_entries_by_dir(
819
 
            specific_file_ids=specific_file_ids, yield_parents=yield_parents)
820
 
 
 
870
        if specific_file_ids is None:
 
871
            inventory_file_ids = None
 
872
        else:
 
873
            inventory_file_ids = []
 
874
            for tree_file_id in specific_file_ids:
 
875
                inventory, inv_file_id = self._unpack_file_id(tree_file_id)
 
876
                if not inventory is self.root_inventory: # for now
 
877
                    raise AssertionError("%r != %r" % (
 
878
                        inventory, self.root_inventory))
 
879
                inventory_file_ids.append(inv_file_id)
 
880
        # FIXME: Handle nested trees
 
881
        return self.root_inventory.iter_entries_by_dir(
 
882
            specific_file_ids=inventory_file_ids, yield_parents=yield_parents)
 
883
 
 
884
    @needs_read_lock
 
885
    def iter_child_entries(self, file_id, path=None):
 
886
        inv, inv_file_id = self._unpack_file_id(file_id)
 
887
        return inv[inv_file_id].children.itervalues()
 
888
 
 
889
    @deprecated_method(deprecated_in((2, 5, 0)))
821
890
    def get_file_by_path(self, path):
822
 
        return self.get_file(self._inventory.path2id(path), path)
 
891
        return self.get_file(self.path2id(path), path)
 
892
 
 
893
    def iter_children(self, file_id, path=None):
 
894
        """See Tree.iter_children."""
 
895
        entry = self.iter_entries_by_dir([file_id]).next()[1]
 
896
        for child in getattr(entry, 'children', {}).itervalues():
 
897
            yield child.file_id
823
898
 
824
899
 
825
900
def find_ids_across_trees(filenames, trees, require_versioned=True):
980
1055
            if (self.source.get_symlink_target(file_id) !=
981
1056
                self.target.get_symlink_target(file_id)):
982
1057
                changed_content = True
983
 
            # XXX: Yes, the indentation below is wrong. But fixing it broke
984
 
            # test_merge.TestMergerEntriesLCAOnDisk.
985
 
            # test_nested_tree_subtree_renamed_and_modified. We'll wait for
986
 
            # the fix from bzr.dev -- vila 2009026
987
 
            elif source_kind == 'tree-reference':
988
 
                if (self.source.get_reference_revision(file_id, source_path)
989
 
                    != self.target.get_reference_revision(file_id, target_path)):
 
1058
        elif source_kind == 'tree-reference':
 
1059
            if (self.source.get_reference_revision(file_id, source_path)
 
1060
                != self.target.get_reference_revision(file_id, target_path)):
990
1061
                    changed_content = True
991
1062
        parent = (source_parent, target_parent)
992
1063
        name = (source_name, target_name)
1207
1278
        :param file_id: The file_id to lookup.
1208
1279
        """
1209
1280
        try:
1210
 
            inventory = tree.inventory
 
1281
            inventory = tree.root_inventory
1211
1282
        except NotImplementedError:
1212
1283
            # No inventory available.
1213
1284
            try:
1288
1359
                        if old_entry is None:
1289
1360
                            # Reusing a discarded change.
1290
1361
                            old_entry = self._get_entry(self.source, file_id)
1291
 
                        for child in old_entry.children.values():
1292
 
                            precise_file_ids.add(child.file_id)
 
1362
                        precise_file_ids.update(
 
1363
                                self.source.iter_children(file_id))
1293
1364
                    changed_file_ids.add(result[0])
1294
1365
                    yield result
1295
1366
 
1438
1509
            return (None, None)
1439
1510
        else:
1440
1511
            self._out_of_order_processed.add(file_id)
1441
 
            cur_ie = other_tree.inventory[file_id]
 
1512
            cur_ie = other_tree.root_inventory[file_id]
1442
1513
            return (cur_path, cur_ie)
1443
1514
 
1444
1515
    def iter_all(self):