/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tree.py

  • Committer: Jelmer Vernooij
  • Date: 2019-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from __future__ import absolute_import
21
21
 
22
 
import os
 
22
try:
 
23
    from collections.abc import deque
 
24
except ImportError:  # python < 3.7
 
25
    from collections import deque
23
26
 
24
27
from .lazy_import import lazy_import
25
28
lazy_import(globals(), """
26
 
import collections
27
29
 
28
30
from breezy import (
29
31
    conflicts as _mod_conflicts,
68
70
        return (isinstance(other, TreeEntry)
69
71
                and other.__class__ == self.__class__)
70
72
 
 
73
    kind = None
 
74
 
71
75
    def kind_character(self):
72
76
        return "???"
73
77
 
75
79
class TreeDirectory(TreeEntry):
76
80
    """See TreeEntry. This is a directory in a working tree."""
77
81
 
 
82
    kind = 'directory'
 
83
 
78
84
    def kind_character(self):
79
85
        return "/"
80
86
 
82
88
class TreeFile(TreeEntry):
83
89
    """See TreeEntry. This is a regular file in a working tree."""
84
90
 
 
91
    kind = 'file'
 
92
 
85
93
    def kind_character(self):
86
94
        return ''
87
95
 
89
97
class TreeLink(TreeEntry):
90
98
    """See TreeEntry. This is a symlink in a working tree."""
91
99
 
 
100
    kind = 'symlink'
 
101
 
92
102
    def kind_character(self):
93
103
        return ''
94
104
 
96
106
class TreeReference(TreeEntry):
97
107
    """See TreeEntry. This is a reference to a nested tree in a working tree."""
98
108
 
 
109
    kind = 'tree-reference'
 
110
 
99
111
    def kind_character(self):
100
 
        return '/'
 
112
        return '+'
101
113
 
102
114
 
103
115
class Tree(object):
130
142
        return True
131
143
 
132
144
    def changes_from(self, other, want_unchanged=False, specific_files=None,
133
 
        extra_trees=None, require_versioned=False, include_root=False,
134
 
        want_unversioned=False):
 
145
                     extra_trees=None, require_versioned=False, include_root=False,
 
146
                     want_unversioned=False):
135
147
        """Return a TreeDelta of the changes from other to this tree.
136
148
 
137
149
        :param other: A tree to compare with.
142
154
        :param want_unchanged: An optional boolean requesting the inclusion of
143
155
            unchanged entries in the result.
144
156
        :param extra_trees: An optional list of additional trees to use when
145
 
            mapping the contents of specific_files (paths) to file_ids.
 
157
            mapping the contents of specific_files (paths) to their identities.
146
158
        :param require_versioned: An optional boolean (defaults to False). When
147
159
            supplied and True all the 'specific_files' must be versioned, or
148
160
            a PathsNotVersionedError will be thrown.
169
181
        """See InterTree.iter_changes"""
170
182
        intertree = InterTree.get(from_tree, self)
171
183
        return intertree.iter_changes(include_unchanged, specific_files, pb,
172
 
            extra_trees, require_versioned, want_unversioned=want_unversioned)
 
184
                                      extra_trees, require_versioned, want_unversioned=want_unversioned)
173
185
 
174
186
    def conflicts(self):
175
187
        """Get a list of the conflicts in the tree.
245
257
        """
246
258
        raise NotImplementedError(self.iter_entries_by_dir)
247
259
 
248
 
    def iter_child_entries(self, path, file_id=None):
 
260
    def iter_child_entries(self, path):
249
261
        """Iterate over the children of a directory or tree reference.
250
262
 
251
263
        :param path: Path of the directory
252
 
        :param file_id: Optional file id of the directory/tree-reference
253
 
        :raise NoSuchId: When the file_id does not exist
 
264
        :raise NoSuchFile: When the path does not exist
254
265
        :return: Iterator over entries in the directory
255
266
        """
256
267
        raise NotImplementedError(self.iter_child_entries)
261
272
        :param include_root: Whether to include the entry for the tree root
262
273
        :param from_dir: Directory under which to list files
263
274
        :param recursive: Whether to list files recursively
264
 
        :return: iterator over tuples of (path, versioned, kind, file_id,
265
 
            inventory entry)
 
275
        :return: iterator over tuples of
 
276
            (path, versioned, kind, inventory entry)
266
277
        """
267
278
        raise NotImplementedError(self.list_files)
268
279
 
272
283
                if entry.kind == 'tree-reference':
273
284
                    yield path, entry.file_id
274
285
 
275
 
    def kind(self, path, file_id=None):
 
286
    def kind(self, path):
276
287
        raise NotImplementedError("Tree subclass %s must implement kind"
277
 
            % self.__class__.__name__)
 
288
                                  % self.__class__.__name__)
278
289
 
279
 
    def stored_kind(self, path, file_id=None):
280
 
        """File kind stored for this file_id.
 
290
    def stored_kind(self, path):
 
291
        """File kind stored for this path.
281
292
 
282
293
        May not match kind on disk for working trees.  Always available
283
294
        for versioned files, even when the file itself is missing.
284
295
        """
285
 
        return self.kind(path, file_id)
 
296
        return self.kind(path)
286
297
 
287
298
    def path_content_summary(self, path):
288
299
        """Get a summary of the information about path.
293
304
        :param path: A relative path within the tree.
294
305
        :return: A tuple containing kind, size, exec, sha1-or-link.
295
306
            Kind is always present (see tree.kind()).
296
 
            size is present if kind is file and the size of the 
 
307
            size is present if kind is file and the size of the
297
308
                canonical form can be cheaply determined, None otherwise.
298
309
            exec is None unless kind is file and the platform supports the 'x'
299
310
                bit.
302
313
        """
303
314
        raise NotImplementedError(self.path_content_summary)
304
315
 
305
 
    def get_reference_revision(self, path, file_id=None):
 
316
    def get_reference_revision(self, path):
306
317
        raise NotImplementedError("Tree subclass %s must implement "
307
318
                                  "get_reference_revision"
308
 
            % self.__class__.__name__)
 
319
                                  % self.__class__.__name__)
309
320
 
310
321
    def _comparison_data(self, entry, path):
311
322
        """Return a tuple of kind, executable, stat_value for a file.
318
329
        """
319
330
        raise NotImplementedError(self._comparison_data)
320
331
 
321
 
    def get_file(self, path, file_id=None):
322
 
        """Return a file object for the file file_id in the tree.
323
 
 
324
 
        If both file_id and path are defined, it is implementation defined as
325
 
        to which one is used.
 
332
    def get_file(self, path):
 
333
        """Return a file object for the file path in the tree.
326
334
        """
327
335
        raise NotImplementedError(self.get_file)
328
336
 
329
 
    def get_file_with_stat(self, path, file_id=None):
330
 
        """Get a file handle and stat object for file_id.
 
337
    def get_file_with_stat(self, path):
 
338
        """Get a file handle and stat object for path.
331
339
 
332
340
        The default implementation returns (self.get_file, None) for backwards
333
341
        compatibility.
334
342
 
335
343
        :param path: The path of the file.
336
 
        :param file_id: The file id to read, if it is known.
337
344
        :return: A tuple (file_handle, stat_value_or_None). If the tree has
338
345
            no stat facility, or need for a stat cache feedback during commit,
339
346
            it may return None for the second element of the tuple.
340
347
        """
341
 
        return (self.get_file(path, file_id), None)
 
348
        return (self.get_file(path), None)
342
349
 
343
 
    def get_file_text(self, path, file_id=None):
 
350
    def get_file_text(self, path):
344
351
        """Return the byte content of a file.
345
352
 
346
353
        :param path: The path of the file.
347
 
        :param file_id: The file_id of the file.
348
 
 
349
 
        If both file_id and path are supplied, an implementation may use
350
 
        either one.
351
354
 
352
355
        :returns: A single byte string for the whole file.
353
356
        """
354
 
        with self.get_file(path, file_id) as my_file:
 
357
        with self.get_file(path) as my_file:
355
358
            return my_file.read()
356
359
 
357
 
    def get_file_lines(self, path, file_id=None):
 
360
    def get_file_lines(self, path):
358
361
        """Return the content of a file, as lines.
359
362
 
360
363
        :param path: The path of the file.
361
 
        :param file_id: The file_id of the file.
362
 
 
363
 
        If both file_id and path are supplied, an implementation may use
364
 
        either one.
365
364
        """
366
 
        return osutils.split_lines(self.get_file_text(path, file_id))
 
365
        return osutils.split_lines(self.get_file_text(path))
367
366
 
368
 
    def get_file_verifier(self, path, file_id=None, stat_value=None):
 
367
    def get_file_verifier(self, path, stat_value=None):
369
368
        """Return a verifier for a file.
370
369
 
371
370
        The default implementation returns a sha1.
372
371
 
373
 
        :param file_id: The handle for this file.
374
372
        :param path: The path that this file can be found at.
375
373
            These must point to the same object.
376
374
        :param stat_value: Optional stat value for the object
377
375
        :return: Tuple with verifier name and verifier data
378
376
        """
379
 
        return ("SHA1", self.get_file_sha1(path, file_id,
380
 
            stat_value=stat_value))
 
377
        return ("SHA1", self.get_file_sha1(path, stat_value=stat_value))
381
378
 
382
 
    def get_file_sha1(self, path, file_id=None, stat_value=None):
 
379
    def get_file_sha1(self, path, stat_value=None):
383
380
        """Return the SHA1 file for a file.
384
381
 
385
382
        :note: callers should use get_file_verifier instead
387
384
            have quicker access to a non-sha1 verifier.
388
385
 
389
386
        :param path: The path that this file can be found at.
390
 
        :param file_id: The handle for this file.
391
 
            These must point to the same object.
392
387
        :param stat_value: Optional stat value for the object
393
388
        """
394
389
        raise NotImplementedError(self.get_file_sha1)
395
390
 
396
 
    def get_file_mtime(self, path, file_id=None):
 
391
    def get_file_mtime(self, path):
397
392
        """Return the modification time for a file.
398
393
 
399
394
        :param path: The path that this file can be found at.
400
 
        :param file_id: The handle for this file.
401
 
            These must point to the same object.
402
395
        """
403
396
        raise NotImplementedError(self.get_file_mtime)
404
397
 
405
 
    def get_file_size(self, path, file_id=None):
 
398
    def get_file_size(self, path):
406
399
        """Return the size of a file in bytes.
407
400
 
408
401
        This applies only to regular files.  If invoked on directories or
409
402
        symlinks, it will return None.
410
 
        :param file_id: The file-id of the file
411
403
        """
412
404
        raise NotImplementedError(self.get_file_size)
413
405
 
414
 
    def is_executable(self, path, file_id=None):
 
406
    def is_executable(self, path):
415
407
        """Check if a file is executable.
416
408
 
417
409
        :param path: The path that this file can be found at.
418
 
        :param file_id: The handle for this file.
419
 
            These must point to the same object.
420
410
        """
421
411
        raise NotImplementedError(self.is_executable)
422
412
 
446
436
            cur_file = (self.get_file_text(path),)
447
437
            yield identifier, cur_file
448
438
 
449
 
    def get_symlink_target(self, path, file_id=None):
450
 
        """Get the target for a given file_id.
 
439
    def get_symlink_target(self, path):
 
440
        """Get the target for a given path.
451
441
 
452
 
        It is assumed that the caller already knows that file_id is referencing
 
442
        It is assumed that the caller already knows that path is referencing
453
443
        a symlink.
454
 
        :param file_id: Handle for the symlink entry.
455
444
        :param path: The path of the file.
456
 
        If both file_id and path are supplied, an implementation may use
457
 
        either one.
458
445
        :return: The path the symlink points to.
459
446
        """
460
447
        raise NotImplementedError(self.get_symlink_target)
463
450
        """Return the file_id for the root of this tree."""
464
451
        raise NotImplementedError(self.get_root_id)
465
452
 
466
 
    def annotate_iter(self, path, file_id=None,
 
453
    def annotate_iter(self, path,
467
454
                      default_revision=_mod_revision.CURRENT_REVISION):
468
455
        """Return an iterator of revision_id, line tuples.
469
456
 
470
457
        For working trees (and mutable trees in general), the special
471
458
        revision_id 'current:' will be used for lines that are new in this
472
459
        tree, e.g. uncommitted changes.
473
 
        :param file_id: The file to produce an annotated version from
 
460
        :param path: The file to produce an annotated version from
474
461
        :param default_revision: For lines that don't match a basis, mark them
475
462
            with this revision id. Not all implementations will make use of
476
463
            this value.
498
485
        return self.path2id(path) is not None
499
486
 
500
487
    def find_related_paths_across_trees(self, paths, trees=[],
501
 
            require_versioned=True):
 
488
                                        require_versioned=True):
502
489
        """Find related paths in tree corresponding to specified filenames in any
503
490
        of `lookup_trees`.
504
491
 
610
597
        prefs = next(self.iter_search_rules([path], filter_pref_names))
611
598
        stk = filters._get_filter_stack_for(prefs)
612
599
        if 'filters' in debug.debug_flags:
613
 
            trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path, prefs, stk))
 
600
            trace.note(
 
601
                gettext("*** {0} content-filter: {1} => {2!r}").format(path, prefs, stk))
614
602
        return stk
615
603
 
616
604
    def _content_filter_stack_provider(self):
623
611
        """
624
612
        if self.supports_content_filtering():
625
613
            return lambda path, file_id: \
626
 
                    self._content_filter_stack(path)
 
614
                self._content_filter_stack(path)
627
615
        else:
628
616
            return None
629
617
 
630
618
    def iter_search_rules(self, path_names, pref_names=None,
631
 
        _default_searcher=None):
 
619
                          _default_searcher=None):
632
620
        """Find the preferences for filenames in a tree.
633
621
 
634
622
        :param path_names: an iterable of paths to find attributes for.
667
655
        from .archive import create_archive
668
656
        with self.lock_read():
669
657
            return create_archive(format, self, name, root,
670
 
                    subdir, force_mtime=force_mtime)
 
658
                                  subdir, force_mtime=force_mtime)
671
659
 
672
660
    @classmethod
673
661
    def versionable_kind(cls, kind):
749
737
        elif source_kind == 'file':
750
738
            if not self.file_content_matches(
751
739
                    source_path, target_path,
752
 
                    file_id, file_id, source_stat, target_stat):
 
740
                    source_stat, target_stat):
753
741
                changed_content = True
754
742
        elif source_kind == 'symlink':
755
 
            if (self.source.get_symlink_target(source_path, file_id) !=
756
 
                self.target.get_symlink_target(target_path, file_id)):
 
743
            if (self.source.get_symlink_target(source_path) !=
 
744
                    self.target.get_symlink_target(target_path)):
757
745
                changed_content = True
758
746
        elif source_kind == 'tree-reference':
759
 
            if (self.source.get_reference_revision(source_path, file_id)
760
 
                != self.target.get_reference_revision(target_path, file_id)):
761
 
                    changed_content = True
 
747
            if (self.source.get_reference_revision(source_path)
 
748
                    != self.target.get_reference_revision(target_path)):
 
749
                changed_content = True
762
750
        parent = (source_parent, target_parent)
763
751
        name = (source_name, target_name)
764
752
        executable = (source_executable, target_executable)
765
 
        if (changed_content is not False or versioned[0] != versioned[1]
766
 
            or parent[0] != parent[1] or name[0] != name[1] or
767
 
            executable[0] != executable[1]):
 
753
        if (changed_content is not False or versioned[0] != versioned[1] or
 
754
            parent[0] != parent[1] or name[0] != name[1] or
 
755
                executable[0] != executable[1]):
768
756
            changes = True
769
757
        else:
770
758
            changes = False
772
760
                versioned, parent, name, kind, executable), changes
773
761
 
774
762
    def compare(self, want_unchanged=False, specific_files=None,
775
 
        extra_trees=None, require_versioned=False, include_root=False,
776
 
        want_unversioned=False):
 
763
                extra_trees=None, require_versioned=False, include_root=False,
 
764
                want_unversioned=False):
777
765
        """Return the changes from source to target.
778
766
 
779
767
        :return: A TreeDelta.
795
783
            trees = trees + tuple(extra_trees)
796
784
        with self.lock_read():
797
785
            return delta._compare_trees(self.source, self.target, want_unchanged,
798
 
                specific_files, include_root, extra_trees=extra_trees,
799
 
                require_versioned=require_versioned,
800
 
                want_unversioned=want_unversioned)
 
786
                                        specific_files, include_root, extra_trees=extra_trees,
 
787
                                        require_versioned=require_versioned,
 
788
                                        want_unversioned=want_unversioned)
801
789
 
802
790
    def iter_changes(self, include_unchanged=False,
803
 
                      specific_files=None, pb=None, extra_trees=[],
804
 
                      require_versioned=True, want_unversioned=False):
 
791
                     specific_files=None, pb=None, extra_trees=[],
 
792
                     require_versioned=True, want_unversioned=False):
805
793
        """Generate an iterator of changes between trees.
806
794
 
807
795
        A tuple is returned:
836
824
            for the versioned pair.
837
825
        """
838
826
        if not extra_trees:
839
 
             extra_trees = []
 
827
            extra_trees = []
840
828
        else:
841
 
             extra_trees = list(extra_trees)
 
829
            extra_trees = list(extra_trees)
842
830
        # The ids of items we need to examine to insure delta consistency.
843
831
        precise_file_ids = set()
844
832
        changed_file_ids = []
847
835
            source_specific_files = []
848
836
        else:
849
837
            target_specific_files = self.target.find_related_paths_across_trees(
850
 
                    specific_files, [self.source] + extra_trees,
851
 
                    require_versioned=require_versioned)
 
838
                specific_files, [self.source] + extra_trees,
 
839
                require_versioned=require_versioned)
852
840
            source_specific_files = self.source.find_related_paths_across_trees(
853
 
                    specific_files, [self.target] + extra_trees,
854
 
                    require_versioned=require_versioned)
 
841
                specific_files, [self.target] + extra_trees,
 
842
                require_versioned=require_versioned)
855
843
        if specific_files is not None:
856
844
            # reparented or added entries must have their parents included
857
845
            # so that valid deltas can be created. The seen_parents set
863
851
            seen_dirs = set()
864
852
        if want_unversioned:
865
853
            all_unversioned = sorted([(p.split('/'), p) for p in
866
 
                                     self.target.extras()
867
 
                if specific_files is None or
868
 
                    osutils.is_inside_any(specific_files, p)])
869
 
            all_unversioned = collections.deque(all_unversioned)
 
854
                                      self.target.extras()
 
855
                                      if specific_files is None or
 
856
                                      osutils.is_inside_any(specific_files, p)])
 
857
            all_unversioned = deque(all_unversioned)
870
858
        else:
871
 
            all_unversioned = collections.deque()
 
859
            all_unversioned = deque()
872
860
        to_paths = {}
873
861
        from_entries_by_dir = list(self.source.iter_entries_by_dir(
874
862
            specific_files=source_specific_files))
883
871
        fake_entry = TreeFile()
884
872
        for target_path, target_entry in to_entries_by_dir:
885
873
            while (all_unversioned and
886
 
                all_unversioned[0][0] < target_path.split('/')):
 
874
                   all_unversioned[0][0] < target_path.split('/')):
887
875
                unversioned_path = all_unversioned.popleft()
888
876
                target_kind, target_executable, target_stat = \
889
 
                    self.target._comparison_data(fake_entry, unversioned_path[1])
 
877
                    self.target._comparison_data(
 
878
                        fake_entry, unversioned_path[1])
890
879
                yield (None, (None, unversioned_path[1]), True, (False, False),
891
 
                    (None, None),
892
 
                    (None, unversioned_path[0][-1]),
893
 
                    (None, target_kind),
894
 
                    (None, target_executable))
 
880
                       (None, None),
 
881
                       (None, unversioned_path[0][-1]),
 
882
                       (None, target_kind),
 
883
                       (None, target_executable))
895
884
            source_path, source_entry = from_data.get(target_entry.file_id,
896
 
                (None, None))
 
885
                                                      (None, None))
897
886
            result, changes = self._changes_from_entries(source_entry,
898
 
                target_entry, source_path=source_path, target_path=target_path)
 
887
                                                         target_entry, source_path=source_path, target_path=target_path)
899
888
            to_paths[result[0]] = result[1][1]
900
889
            entry_count += 1
901
890
            if result[3][0]:
924
913
            to_kind, to_executable, to_stat = \
925
914
                self.target._comparison_data(fake_entry, unversioned_path[1])
926
915
            yield (None, (None, unversioned_path[1]), True, (False, False),
927
 
                (None, None),
928
 
                (None, unversioned_path[0][-1]),
929
 
                (None, to_kind),
930
 
                (None, to_executable))
 
916
                   (None, None),
 
917
                   (None, unversioned_path[0][-1]),
 
918
                   (None, to_kind),
 
919
                   (None, to_executable))
931
920
        # Yield all remaining source paths
932
921
        for path, from_entry in from_entries_by_dir:
933
922
            file_id = from_entry.file_id
953
942
        changed_file_ids = set(changed_file_ids)
954
943
        if specific_files is not None:
955
944
            for result in self._handle_precise_ids(precise_file_ids,
956
 
                changed_file_ids):
 
945
                                                   changed_file_ids):
957
946
                yield result
958
947
 
959
948
    def _get_entry(self, tree, path):
964
953
        desired.
965
954
 
966
955
        :param tree: The tree to lookup the entry in.
967
 
        :param file_id: The file_id to lookup.
 
956
        :param path: The path to look up
968
957
        """
969
958
        # No inventory available.
970
959
        try:
974
963
            return None
975
964
 
976
965
    def _handle_precise_ids(self, precise_file_ids, changed_file_ids,
977
 
        discarded_changes=None):
 
966
                            discarded_changes=None):
978
967
        """Fill out a partial iter_changes to be consistent.
979
968
 
980
969
        :param precise_file_ids: The file ids of parents that were seen during
1029
1018
                        source_path = None
1030
1019
                        source_entry = None
1031
1020
                    else:
1032
 
                        source_entry = self._get_entry(self.source, source_path)
 
1021
                        source_entry = self._get_entry(
 
1022
                            self.source, source_path)
1033
1023
                    try:
1034
1024
                        target_path = self.target.id2path(file_id)
1035
1025
                    except errors.NoSuchId:
1036
1026
                        target_path = None
1037
1027
                        target_entry = None
1038
1028
                    else:
1039
 
                        target_entry = self._get_entry(self.target, target_path)
 
1029
                        target_entry = self._get_entry(
 
1030
                            self.target, target_path)
1040
1031
                    result, changes = self._changes_from_entries(
1041
1032
                        source_entry, target_entry, source_path, target_path)
1042
1033
                else:
1051
1042
                        # to be included.
1052
1043
                        if source_entry is None:
1053
1044
                            # Reusing a discarded change.
1054
 
                            source_entry = self._get_entry(self.source, result[1][0])
 
1045
                            source_entry = self._get_entry(
 
1046
                                self.source, result[1][0])
1055
1047
                        precise_file_ids.update(
1056
 
                                child.file_id
1057
 
                                for child in self.source.iter_child_entries(result[1][0]))
 
1048
                            child.file_id
 
1049
                            for child in self.source.iter_child_entries(result[1][0]))
1058
1050
                    changed_file_ids.add(result[0])
1059
1051
                    yield result
1060
1052
 
1061
1053
    def file_content_matches(
1062
1054
            self, source_path, target_path,
1063
 
            source_file_id=None, target_file_id=None,
1064
1055
            source_stat=None, target_stat=None):
1065
1056
        """Check if two files are the same in the source and target trees.
1066
1057
 
1077
1068
        """
1078
1069
        with self.lock_read():
1079
1070
            source_verifier_kind, source_verifier_data = (
1080
 
                    self.source.get_file_verifier(
1081
 
                        source_path, source_file_id, source_stat))
 
1071
                self.source.get_file_verifier(source_path, source_stat))
1082
1072
            target_verifier_kind, target_verifier_data = (
1083
1073
                self.target.get_file_verifier(
1084
 
                    target_path, target_file_id, target_stat))
 
1074
                    target_path, target_stat))
1085
1075
            if source_verifier_kind == target_verifier_kind:
1086
1076
                return (source_verifier_data == target_verifier_data)
1087
1077
            # Fall back to SHA1 for now
1088
1078
            if source_verifier_kind != "SHA1":
1089
1079
                source_sha1 = self.source.get_file_sha1(
1090
 
                        source_path, source_file_id, source_stat)
 
1080
                    source_path, source_file_id, source_stat)
1091
1081
            else:
1092
1082
                source_sha1 = source_verifier_data
1093
1083
            if target_verifier_kind != "SHA1":
1094
1084
                target_sha1 = self.target.get_file_sha1(
1095
 
                        target_path, target_file_id, target_stat)
 
1085
                    target_path, target_file_id, target_stat)
1096
1086
            else:
1097
1087
                target_sha1 = target_verifier_data
1098
1088
            return (source_sha1 == target_sha1)
1099
1089
 
 
1090
 
1100
1091
InterTree.register_optimiser(InterTree)
1101
1092
 
1102
1093
 
1324
1315
                other_extra.pop(file_id)
1325
1316
                other_values = [(None, None)] * idx
1326
1317
                other_values.append((other_path, other_ie))
1327
 
                for alt_idx, alt_extra in enumerate(self._others_extra[idx+1:]):
 
1318
                for alt_idx, alt_extra in enumerate(self._others_extra[idx + 1:]):
1328
1319
                    alt_idx = alt_idx + idx + 1
1329
1320
                    alt_extra = self._others_extra[alt_idx]
1330
1321
                    alt_tree = self._other_trees[alt_idx]
1331
1322
                    other_values.append(self._lookup_by_file_id(
1332
 
                                            alt_extra, alt_tree, file_id))
 
1323
                        alt_extra, alt_tree, file_id))
1333
1324
                yield other_path, file_id, None, other_values
1334
1325
 
1335
1326
 
1375
1366
    :return: The canonical path
1376
1367
    """
1377
1368
    # go walkin...
1378
 
    cur_id = tree.get_root_id()
1379
1369
    cur_path = ''
1380
1370
    bit_iter = iter(path.split("/"))
1381
1371
    for elt in bit_iter:
1382
1372
        lelt = normalize(elt)
1383
1373
        new_path = None
1384
1374
        try:
1385
 
            for child in tree.iter_child_entries(cur_path, cur_id):
 
1375
            for child in tree.iter_child_entries(cur_path):
1386
1376
                try:
1387
1377
                    if child.name == elt:
1388
1378
                        # if we found an exact match, we can stop now; if
1389
1379
                        # we found an approximate match we need to keep
1390
1380
                        # searching because there might be an exact match
1391
1381
                        # later.
1392
 
                        cur_id = child.file_id
1393
1382
                        new_path = osutils.pathjoin(cur_path, child.name)
1394
1383
                        break
1395
1384
                    elif normalize(child.name) == lelt:
1396
 
                        cur_id = child.file_id
1397
1385
                        new_path = osutils.pathjoin(cur_path, child.name)
1398
1386
                except errors.NoSuchId:
1399
1387
                    # before a change is committed we can see this error...