~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
193
195
        """
194
196
        raise NotImplementedError(self.iter_entries_by_dir)
195
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
 
196
208
    def list_files(self, include_root=False, from_dir=None, recursive=True):
197
209
        """List all files in this tree.
198
210
 
355
367
        """
356
368
        raise NotImplementedError(self.get_file_size)
357
369
 
358
 
    def get_file_by_path(self, path):
359
 
        raise NotImplementedError(self.get_file_by_path)
360
 
 
361
370
    def is_executable(self, file_id, path=None):
362
371
        """Check if a file is executable.
363
372
 
533
542
        return find_ids_across_trees(paths, [self] + list(trees), require_versioned)
534
543
 
535
544
    def iter_children(self, file_id):
536
 
        entry = self.iter_entries_by_dir([file_id]).next()[1]
537
 
        for child in getattr(entry, 'children', {}).itervalues():
538
 
            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)
539
551
 
540
552
    def lock_read(self):
541
553
        """Lock this tree for multiple read only operations.
542
 
        
 
554
 
543
555
        :return: A bzrlib.lock.LogicalLockResult.
544
556
        """
545
557
        pass
769
781
            yield cur_path
770
782
        # all done.
771
783
 
 
784
    @deprecated_method(deprecated_in((2, 5, 0)))
772
785
    def _get_inventory(self):
773
786
        return self._inventory
774
787
 
775
788
    inventory = property(_get_inventory,
776
789
                         doc="Inventory of this Tree")
777
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
 
778
809
    @needs_read_lock
779
810
    def path2id(self, path):
780
811
        """Return the id for path in this tree."""
781
 
        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)
782
822
 
783
823
    def id2path(self, file_id):
784
824
        """Return the path for a file id.
785
825
 
786
826
        :raises NoSuchId:
787
827
        """
788
 
        return self.inventory.id2path(file_id)
 
828
        inventory, file_id = self._unpack_file_id(file_id)
 
829
        return inventory.id2path(file_id)
789
830
 
790
831
    def has_id(self, file_id):
791
 
        return self.inventory.has_id(file_id)
 
832
        inventory, file_id = self._unpack_file_id(file_id)
 
833
        return inventory.has_id(file_id)
792
834
 
793
835
    def has_or_had_id(self, file_id):
794
 
        return self.inventory.has_id(file_id)
 
836
        inventory, file_id = self._unpack_file_id(file_id)
 
837
        return inventory.has_id(file_id)
795
838
 
796
839
    def all_file_ids(self):
797
 
        return set(self.inventory)
 
840
        return set(
 
841
            [entry.file_id for path, entry in self.iter_entries_by_dir()])
798
842
 
799
843
    @deprecated_method(deprecated_in((2, 4, 0)))
800
844
    def __iter__(self):
801
 
        return iter(self.inventory)
 
845
        return iter(self.all_file_ids())
802
846
 
803
847
    def filter_unversioned_files(self, paths):
804
848
        """Filter out paths that are versioned.
808
852
        # NB: we specifically *don't* call self.has_filename, because for
809
853
        # WorkingTrees that can indicate files that exist on disk but that
810
854
        # are not versioned.
811
 
        pred = self.inventory.has_filename
812
 
        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))
813
856
 
814
857
    @needs_read_lock
815
858
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
824
867
            down to specific_file_ids that have been requested. This has no
825
868
            impact if specific_file_ids is None.
826
869
        """
827
 
        return self.inventory.iter_entries_by_dir(
828
 
            specific_file_ids=specific_file_ids, yield_parents=yield_parents)
829
 
 
 
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)))
830
890
    def get_file_by_path(self, path):
831
 
        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
832
898
 
833
899
 
834
900
def find_ids_across_trees(filenames, trees, require_versioned=True):
989
1055
            if (self.source.get_symlink_target(file_id) !=
990
1056
                self.target.get_symlink_target(file_id)):
991
1057
                changed_content = True
992
 
            # XXX: Yes, the indentation below is wrong. But fixing it broke
993
 
            # test_merge.TestMergerEntriesLCAOnDisk.
994
 
            # test_nested_tree_subtree_renamed_and_modified. We'll wait for
995
 
            # the fix from bzr.dev -- vila 2009026
996
 
            elif source_kind == 'tree-reference':
997
 
                if (self.source.get_reference_revision(file_id, source_path)
998
 
                    != 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)):
999
1061
                    changed_content = True
1000
1062
        parent = (source_parent, target_parent)
1001
1063
        name = (source_name, target_name)
1216
1278
        :param file_id: The file_id to lookup.
1217
1279
        """
1218
1280
        try:
1219
 
            inventory = tree.inventory
 
1281
            inventory = tree.root_inventory
1220
1282
        except NotImplementedError:
1221
1283
            # No inventory available.
1222
1284
            try:
1297
1359
                        if old_entry is None:
1298
1360
                            # Reusing a discarded change.
1299
1361
                            old_entry = self._get_entry(self.source, file_id)
1300
 
                        for child in old_entry.children.values():
1301
 
                            precise_file_ids.add(child.file_id)
 
1362
                        precise_file_ids.update(
 
1363
                                self.source.iter_children(file_id))
1302
1364
                    changed_file_ids.add(result[0])
1303
1365
                    yield result
1304
1366
 
1447
1509
            return (None, None)
1448
1510
        else:
1449
1511
            self._out_of_order_processed.add(file_id)
1450
 
            cur_ie = other_tree.inventory[file_id]
 
1512
            cur_ie = other_tree.root_inventory[file_id]
1451
1513
            return (cur_path, cur_ie)
1452
1514
 
1453
1515
    def iter_all(self):