/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: Martin
  • Date: 2018-11-16 19:09:31 UTC
  • mfrom: (7175 work)
  • mto: This revision was merged to the branch mainline in revision 7177.
  • Revision ID: gzlist@googlemail.com-20181116190931-rmh7pk2an1zuecby
Merge trunk to resolve conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
128
128
        return True
129
129
 
130
130
    def changes_from(self, other, want_unchanged=False, specific_files=None,
131
 
        extra_trees=None, require_versioned=False, include_root=False,
132
 
        want_unversioned=False):
 
131
                     extra_trees=None, require_versioned=False, include_root=False,
 
132
                     want_unversioned=False):
133
133
        """Return a TreeDelta of the changes from other to this tree.
134
134
 
135
135
        :param other: A tree to compare with.
140
140
        :param want_unchanged: An optional boolean requesting the inclusion of
141
141
            unchanged entries in the result.
142
142
        :param extra_trees: An optional list of additional trees to use when
143
 
            mapping the contents of specific_files (paths) to file_ids.
 
143
            mapping the contents of specific_files (paths) to their identities.
144
144
        :param require_versioned: An optional boolean (defaults to False). When
145
145
            supplied and True all the 'specific_files' must be versioned, or
146
146
            a PathsNotVersionedError will be thrown.
167
167
        """See InterTree.iter_changes"""
168
168
        intertree = InterTree.get(from_tree, self)
169
169
        return intertree.iter_changes(include_unchanged, specific_files, pb,
170
 
            extra_trees, require_versioned, want_unversioned=want_unversioned)
 
170
                                      extra_trees, require_versioned, want_unversioned=want_unversioned)
171
171
 
172
172
    def conflicts(self):
173
173
        """Get a list of the conflicts in the tree.
243
243
        """
244
244
        raise NotImplementedError(self.iter_entries_by_dir)
245
245
 
246
 
    def iter_child_entries(self, path, file_id=None):
 
246
    def iter_child_entries(self, path):
247
247
        """Iterate over the children of a directory or tree reference.
248
248
 
249
249
        :param path: Path of the directory
250
 
        :param file_id: Optional file id of the directory/tree-reference
251
 
        :raise NoSuchId: When the file_id does not exist
 
250
        :raise NoSuchFile: When the path does not exist
252
251
        :return: Iterator over entries in the directory
253
252
        """
254
253
        raise NotImplementedError(self.iter_child_entries)
270
269
                if entry.kind == 'tree-reference':
271
270
                    yield path, entry.file_id
272
271
 
273
 
    def kind(self, path, file_id=None):
 
272
    def kind(self, path):
274
273
        raise NotImplementedError("Tree subclass %s must implement kind"
275
 
            % self.__class__.__name__)
 
274
                                  % self.__class__.__name__)
276
275
 
277
 
    def stored_kind(self, path, file_id=None):
278
 
        """File kind stored for this file_id.
 
276
    def stored_kind(self, path):
 
277
        """File kind stored for this path.
279
278
 
280
279
        May not match kind on disk for working trees.  Always available
281
280
        for versioned files, even when the file itself is missing.
282
281
        """
283
 
        return self.kind(path, file_id)
 
282
        return self.kind(path)
284
283
 
285
284
    def path_content_summary(self, path):
286
285
        """Get a summary of the information about path.
300
299
        """
301
300
        raise NotImplementedError(self.path_content_summary)
302
301
 
303
 
    def get_reference_revision(self, path, file_id=None):
 
302
    def get_reference_revision(self, path):
304
303
        raise NotImplementedError("Tree subclass %s must implement "
305
304
                                  "get_reference_revision"
306
 
            % self.__class__.__name__)
 
305
                                  % self.__class__.__name__)
307
306
 
308
307
    def _comparison_data(self, entry, path):
309
308
        """Return a tuple of kind, executable, stat_value for a file.
316
315
        """
317
316
        raise NotImplementedError(self._comparison_data)
318
317
 
319
 
    def get_file(self, path, file_id=None):
320
 
        """Return a file object for the file file_id in the tree.
321
 
 
322
 
        If both file_id and path are defined, it is implementation defined as
323
 
        to which one is used.
 
318
    def get_file(self, path):
 
319
        """Return a file object for the file path in the tree.
324
320
        """
325
321
        raise NotImplementedError(self.get_file)
326
322
 
327
 
    def get_file_with_stat(self, path, file_id=None):
328
 
        """Get a file handle and stat object for file_id.
 
323
    def get_file_with_stat(self, path):
 
324
        """Get a file handle and stat object for path.
329
325
 
330
326
        The default implementation returns (self.get_file, None) for backwards
331
327
        compatibility.
332
328
 
333
329
        :param path: The path of the file.
334
 
        :param file_id: The file id to read, if it is known.
335
330
        :return: A tuple (file_handle, stat_value_or_None). If the tree has
336
331
            no stat facility, or need for a stat cache feedback during commit,
337
332
            it may return None for the second element of the tuple.
338
333
        """
339
 
        return (self.get_file(path, file_id), None)
 
334
        return (self.get_file(path), None)
340
335
 
341
 
    def get_file_text(self, path, file_id=None):
 
336
    def get_file_text(self, path):
342
337
        """Return the byte content of a file.
343
338
 
344
339
        :param path: The path of the file.
345
 
        :param file_id: The file_id of the file.
346
 
 
347
 
        If both file_id and path are supplied, an implementation may use
348
 
        either one.
349
340
 
350
341
        :returns: A single byte string for the whole file.
351
342
        """
352
 
        with self.get_file(path, file_id) as my_file:
 
343
        with self.get_file(path) as my_file:
353
344
            return my_file.read()
354
345
 
355
 
    def get_file_lines(self, path, file_id=None):
 
346
    def get_file_lines(self, path):
356
347
        """Return the content of a file, as lines.
357
348
 
358
349
        :param path: The path of the file.
359
 
        :param file_id: The file_id of the file.
360
 
 
361
 
        If both file_id and path are supplied, an implementation may use
362
 
        either one.
363
350
        """
364
 
        return osutils.split_lines(self.get_file_text(path, file_id))
 
351
        return osutils.split_lines(self.get_file_text(path))
365
352
 
366
 
    def get_file_verifier(self, path, file_id=None, stat_value=None):
 
353
    def get_file_verifier(self, path, stat_value=None):
367
354
        """Return a verifier for a file.
368
355
 
369
356
        The default implementation returns a sha1.
370
357
 
371
 
        :param file_id: The handle for this file.
372
358
        :param path: The path that this file can be found at.
373
359
            These must point to the same object.
374
360
        :param stat_value: Optional stat value for the object
375
361
        :return: Tuple with verifier name and verifier data
376
362
        """
377
 
        return ("SHA1", self.get_file_sha1(path, file_id,
378
 
            stat_value=stat_value))
 
363
        return ("SHA1", self.get_file_sha1(path, stat_value=stat_value))
379
364
 
380
 
    def get_file_sha1(self, path, file_id=None, stat_value=None):
 
365
    def get_file_sha1(self, path, stat_value=None):
381
366
        """Return the SHA1 file for a file.
382
367
 
383
368
        :note: callers should use get_file_verifier instead
385
370
            have quicker access to a non-sha1 verifier.
386
371
 
387
372
        :param path: The path that this file can be found at.
388
 
        :param file_id: The handle for this file.
389
 
            These must point to the same object.
390
373
        :param stat_value: Optional stat value for the object
391
374
        """
392
375
        raise NotImplementedError(self.get_file_sha1)
393
376
 
394
 
    def get_file_mtime(self, path, file_id=None):
 
377
    def get_file_mtime(self, path):
395
378
        """Return the modification time for a file.
396
379
 
397
380
        :param path: The path that this file can be found at.
398
 
        :param file_id: The handle for this file.
399
 
            These must point to the same object.
400
381
        """
401
382
        raise NotImplementedError(self.get_file_mtime)
402
383
 
403
 
    def get_file_size(self, path, file_id=None):
 
384
    def get_file_size(self, path):
404
385
        """Return the size of a file in bytes.
405
386
 
406
387
        This applies only to regular files.  If invoked on directories or
407
388
        symlinks, it will return None.
408
 
        :param file_id: The file-id of the file
409
389
        """
410
390
        raise NotImplementedError(self.get_file_size)
411
391
 
412
 
    def is_executable(self, path, file_id=None):
 
392
    def is_executable(self, path):
413
393
        """Check if a file is executable.
414
394
 
415
395
        :param path: The path that this file can be found at.
416
 
        :param file_id: The handle for this file.
417
 
            These must point to the same object.
418
396
        """
419
397
        raise NotImplementedError(self.is_executable)
420
398
 
444
422
            cur_file = (self.get_file_text(path),)
445
423
            yield identifier, cur_file
446
424
 
447
 
    def get_symlink_target(self, path, file_id=None):
448
 
        """Get the target for a given file_id.
 
425
    def get_symlink_target(self, path):
 
426
        """Get the target for a given path.
449
427
 
450
 
        It is assumed that the caller already knows that file_id is referencing
 
428
        It is assumed that the caller already knows that path is referencing
451
429
        a symlink.
452
 
        :param file_id: Handle for the symlink entry.
453
430
        :param path: The path of the file.
454
 
        If both file_id and path are supplied, an implementation may use
455
 
        either one.
456
431
        :return: The path the symlink points to.
457
432
        """
458
433
        raise NotImplementedError(self.get_symlink_target)
461
436
        """Return the file_id for the root of this tree."""
462
437
        raise NotImplementedError(self.get_root_id)
463
438
 
464
 
    def annotate_iter(self, path, file_id=None,
 
439
    def annotate_iter(self, path,
465
440
                      default_revision=_mod_revision.CURRENT_REVISION):
466
441
        """Return an iterator of revision_id, line tuples.
467
442
 
468
443
        For working trees (and mutable trees in general), the special
469
444
        revision_id 'current:' will be used for lines that are new in this
470
445
        tree, e.g. uncommitted changes.
471
 
        :param file_id: The file to produce an annotated version from
 
446
        :param path: The file to produce an annotated version from
472
447
        :param default_revision: For lines that don't match a basis, mark them
473
448
            with this revision id. Not all implementations will make use of
474
449
            this value.
496
471
        return self.path2id(path) is not None
497
472
 
498
473
    def find_related_paths_across_trees(self, paths, trees=[],
499
 
            require_versioned=True):
 
474
                                        require_versioned=True):
500
475
        """Find related paths in tree corresponding to specified filenames in any
501
476
        of `lookup_trees`.
502
477
 
608
583
        prefs = next(self.iter_search_rules([path], filter_pref_names))
609
584
        stk = filters._get_filter_stack_for(prefs)
610
585
        if 'filters' in debug.debug_flags:
611
 
            trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path, prefs, stk))
 
586
            trace.note(
 
587
                gettext("*** {0} content-filter: {1} => {2!r}").format(path, prefs, stk))
612
588
        return stk
613
589
 
614
590
    def _content_filter_stack_provider(self):
621
597
        """
622
598
        if self.supports_content_filtering():
623
599
            return lambda path, file_id: \
624
 
                    self._content_filter_stack(path)
 
600
                self._content_filter_stack(path)
625
601
        else:
626
602
            return None
627
603
 
628
604
    def iter_search_rules(self, path_names, pref_names=None,
629
 
        _default_searcher=None):
 
605
                          _default_searcher=None):
630
606
        """Find the preferences for filenames in a tree.
631
607
 
632
608
        :param path_names: an iterable of paths to find attributes for.
665
641
        from .archive import create_archive
666
642
        with self.lock_read():
667
643
            return create_archive(format, self, name, root,
668
 
                    subdir, force_mtime=force_mtime)
 
644
                                  subdir, force_mtime=force_mtime)
669
645
 
670
646
    @classmethod
671
647
    def versionable_kind(cls, kind):
747
723
        elif source_kind == 'file':
748
724
            if not self.file_content_matches(
749
725
                    source_path, target_path,
750
 
                    file_id, file_id, source_stat, target_stat):
 
726
                    source_stat, target_stat):
751
727
                changed_content = True
752
728
        elif source_kind == 'symlink':
753
 
            if (self.source.get_symlink_target(source_path, file_id) !=
754
 
                self.target.get_symlink_target(target_path, file_id)):
 
729
            if (self.source.get_symlink_target(source_path) !=
 
730
                self.target.get_symlink_target(target_path)):
755
731
                changed_content = True
756
732
        elif source_kind == 'tree-reference':
757
 
            if (self.source.get_reference_revision(source_path, file_id)
758
 
                != self.target.get_reference_revision(target_path, file_id)):
 
733
            if (self.source.get_reference_revision(source_path)
 
734
                != self.target.get_reference_revision(target_path)):
759
735
                    changed_content = True
760
736
        parent = (source_parent, target_parent)
761
737
        name = (source_name, target_name)
762
738
        executable = (source_executable, target_executable)
763
 
        if (changed_content is not False or versioned[0] != versioned[1]
764
 
            or parent[0] != parent[1] or name[0] != name[1] or
765
 
            executable[0] != executable[1]):
 
739
        if (changed_content is not False or versioned[0] != versioned[1] or
 
740
            parent[0] != parent[1] or name[0] != name[1] or
 
741
                executable[0] != executable[1]):
766
742
            changes = True
767
743
        else:
768
744
            changes = False
770
746
                versioned, parent, name, kind, executable), changes
771
747
 
772
748
    def compare(self, want_unchanged=False, specific_files=None,
773
 
        extra_trees=None, require_versioned=False, include_root=False,
774
 
        want_unversioned=False):
 
749
                extra_trees=None, require_versioned=False, include_root=False,
 
750
                want_unversioned=False):
775
751
        """Return the changes from source to target.
776
752
 
777
753
        :return: A TreeDelta.
793
769
            trees = trees + tuple(extra_trees)
794
770
        with self.lock_read():
795
771
            return delta._compare_trees(self.source, self.target, want_unchanged,
796
 
                specific_files, include_root, extra_trees=extra_trees,
797
 
                require_versioned=require_versioned,
798
 
                want_unversioned=want_unversioned)
 
772
                                        specific_files, include_root, extra_trees=extra_trees,
 
773
                                        require_versioned=require_versioned,
 
774
                                        want_unversioned=want_unversioned)
799
775
 
800
776
    def iter_changes(self, include_unchanged=False,
801
 
                      specific_files=None, pb=None, extra_trees=[],
802
 
                      require_versioned=True, want_unversioned=False):
 
777
                     specific_files=None, pb=None, extra_trees=[],
 
778
                     require_versioned=True, want_unversioned=False):
803
779
        """Generate an iterator of changes between trees.
804
780
 
805
781
        A tuple is returned:
834
810
            for the versioned pair.
835
811
        """
836
812
        if not extra_trees:
837
 
             extra_trees = []
 
813
            extra_trees = []
838
814
        else:
839
 
             extra_trees = list(extra_trees)
 
815
            extra_trees = list(extra_trees)
840
816
        # The ids of items we need to examine to insure delta consistency.
841
817
        precise_file_ids = set()
842
818
        changed_file_ids = []
845
821
            source_specific_files = []
846
822
        else:
847
823
            target_specific_files = self.target.find_related_paths_across_trees(
848
 
                    specific_files, [self.source] + extra_trees,
849
 
                    require_versioned=require_versioned)
 
824
                specific_files, [self.source] + extra_trees,
 
825
                require_versioned=require_versioned)
850
826
            source_specific_files = self.source.find_related_paths_across_trees(
851
 
                    specific_files, [self.target] + extra_trees,
852
 
                    require_versioned=require_versioned)
 
827
                specific_files, [self.target] + extra_trees,
 
828
                require_versioned=require_versioned)
853
829
        if specific_files is not None:
854
830
            # reparented or added entries must have their parents included
855
831
            # so that valid deltas can be created. The seen_parents set
861
837
            seen_dirs = set()
862
838
        if want_unversioned:
863
839
            all_unversioned = sorted([(p.split('/'), p) for p in
864
 
                                     self.target.extras()
865
 
                if specific_files is None or
866
 
                    osutils.is_inside_any(specific_files, p)])
 
840
                                      self.target.extras()
 
841
                                      if specific_files is None or
 
842
                                      osutils.is_inside_any(specific_files, p)])
867
843
            all_unversioned = collections.deque(all_unversioned)
868
844
        else:
869
845
            all_unversioned = collections.deque()
881
857
        fake_entry = TreeFile()
882
858
        for target_path, target_entry in to_entries_by_dir:
883
859
            while (all_unversioned and
884
 
                all_unversioned[0][0] < target_path.split('/')):
 
860
                   all_unversioned[0][0] < target_path.split('/')):
885
861
                unversioned_path = all_unversioned.popleft()
886
862
                target_kind, target_executable, target_stat = \
887
 
                    self.target._comparison_data(fake_entry, unversioned_path[1])
 
863
                    self.target._comparison_data(
 
864
                        fake_entry, unversioned_path[1])
888
865
                yield (None, (None, unversioned_path[1]), True, (False, False),
889
 
                    (None, None),
890
 
                    (None, unversioned_path[0][-1]),
891
 
                    (None, target_kind),
892
 
                    (None, target_executable))
 
866
                       (None, None),
 
867
                       (None, unversioned_path[0][-1]),
 
868
                       (None, target_kind),
 
869
                       (None, target_executable))
893
870
            source_path, source_entry = from_data.get(target_entry.file_id,
894
 
                (None, None))
 
871
                                                      (None, None))
895
872
            result, changes = self._changes_from_entries(source_entry,
896
 
                target_entry, source_path=source_path, target_path=target_path)
 
873
                                                         target_entry, source_path=source_path, target_path=target_path)
897
874
            to_paths[result[0]] = result[1][1]
898
875
            entry_count += 1
899
876
            if result[3][0]:
922
899
            to_kind, to_executable, to_stat = \
923
900
                self.target._comparison_data(fake_entry, unversioned_path[1])
924
901
            yield (None, (None, unversioned_path[1]), True, (False, False),
925
 
                (None, None),
926
 
                (None, unversioned_path[0][-1]),
927
 
                (None, to_kind),
928
 
                (None, to_executable))
 
902
                   (None, None),
 
903
                   (None, unversioned_path[0][-1]),
 
904
                   (None, to_kind),
 
905
                   (None, to_executable))
929
906
        # Yield all remaining source paths
930
907
        for path, from_entry in from_entries_by_dir:
931
908
            file_id = from_entry.file_id
951
928
        changed_file_ids = set(changed_file_ids)
952
929
        if specific_files is not None:
953
930
            for result in self._handle_precise_ids(precise_file_ids,
954
 
                changed_file_ids):
 
931
                                                   changed_file_ids):
955
932
                yield result
956
933
 
957
934
    def _get_entry(self, tree, path):
962
939
        desired.
963
940
 
964
941
        :param tree: The tree to lookup the entry in.
965
 
        :param file_id: The file_id to lookup.
 
942
        :param path: The path to look up
966
943
        """
967
944
        # No inventory available.
968
945
        try:
972
949
            return None
973
950
 
974
951
    def _handle_precise_ids(self, precise_file_ids, changed_file_ids,
975
 
        discarded_changes=None):
 
952
                            discarded_changes=None):
976
953
        """Fill out a partial iter_changes to be consistent.
977
954
 
978
955
        :param precise_file_ids: The file ids of parents that were seen during
1027
1004
                        source_path = None
1028
1005
                        source_entry = None
1029
1006
                    else:
1030
 
                        source_entry = self._get_entry(self.source, source_path)
 
1007
                        source_entry = self._get_entry(
 
1008
                            self.source, source_path)
1031
1009
                    try:
1032
1010
                        target_path = self.target.id2path(file_id)
1033
1011
                    except errors.NoSuchId:
1034
1012
                        target_path = None
1035
1013
                        target_entry = None
1036
1014
                    else:
1037
 
                        target_entry = self._get_entry(self.target, target_path)
 
1015
                        target_entry = self._get_entry(
 
1016
                            self.target, target_path)
1038
1017
                    result, changes = self._changes_from_entries(
1039
1018
                        source_entry, target_entry, source_path, target_path)
1040
1019
                else:
1049
1028
                        # to be included.
1050
1029
                        if source_entry is None:
1051
1030
                            # Reusing a discarded change.
1052
 
                            source_entry = self._get_entry(self.source, result[1][0])
 
1031
                            source_entry = self._get_entry(
 
1032
                                self.source, result[1][0])
1053
1033
                        precise_file_ids.update(
1054
 
                                child.file_id
1055
 
                                for child in self.source.iter_child_entries(result[1][0]))
 
1034
                            child.file_id
 
1035
                            for child in self.source.iter_child_entries(result[1][0]))
1056
1036
                    changed_file_ids.add(result[0])
1057
1037
                    yield result
1058
1038
 
1059
1039
    def file_content_matches(
1060
1040
            self, source_path, target_path,
1061
 
            source_file_id=None, target_file_id=None,
1062
1041
            source_stat=None, target_stat=None):
1063
1042
        """Check if two files are the same in the source and target trees.
1064
1043
 
1075
1054
        """
1076
1055
        with self.lock_read():
1077
1056
            source_verifier_kind, source_verifier_data = (
1078
 
                    self.source.get_file_verifier(
1079
 
                        source_path, source_file_id, source_stat))
 
1057
                self.source.get_file_verifier(source_path, source_stat))
1080
1058
            target_verifier_kind, target_verifier_data = (
1081
1059
                self.target.get_file_verifier(
1082
 
                    target_path, target_file_id, target_stat))
 
1060
                    target_path, target_stat))
1083
1061
            if source_verifier_kind == target_verifier_kind:
1084
1062
                return (source_verifier_data == target_verifier_data)
1085
1063
            # Fall back to SHA1 for now
1086
1064
            if source_verifier_kind != "SHA1":
1087
1065
                source_sha1 = self.source.get_file_sha1(
1088
 
                        source_path, source_file_id, source_stat)
 
1066
                    source_path, source_file_id, source_stat)
1089
1067
            else:
1090
1068
                source_sha1 = source_verifier_data
1091
1069
            if target_verifier_kind != "SHA1":
1092
1070
                target_sha1 = self.target.get_file_sha1(
1093
 
                        target_path, target_file_id, target_stat)
 
1071
                    target_path, target_file_id, target_stat)
1094
1072
            else:
1095
1073
                target_sha1 = target_verifier_data
1096
1074
            return (source_sha1 == target_sha1)
1097
1075
 
 
1076
 
1098
1077
InterTree.register_optimiser(InterTree)
1099
1078
 
1100
1079
 
1322
1301
                other_extra.pop(file_id)
1323
1302
                other_values = [(None, None)] * idx
1324
1303
                other_values.append((other_path, other_ie))
1325
 
                for alt_idx, alt_extra in enumerate(self._others_extra[idx+1:]):
 
1304
                for alt_idx, alt_extra in enumerate(self._others_extra[idx + 1:]):
1326
1305
                    alt_idx = alt_idx + idx + 1
1327
1306
                    alt_extra = self._others_extra[alt_idx]
1328
1307
                    alt_tree = self._other_trees[alt_idx]
1329
1308
                    other_values.append(self._lookup_by_file_id(
1330
 
                                            alt_extra, alt_tree, file_id))
 
1309
                        alt_extra, alt_tree, file_id))
1331
1310
                yield other_path, file_id, None, other_values
1332
1311
 
1333
1312