/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/diff.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:
53
53
 
54
54
DEFAULT_CONTEXT_AMOUNT = 3
55
55
 
 
56
 
56
57
class AtTemplate(string.Template):
57
58
    """Templating class that uses @ instead of $."""
58
59
 
93
94
    if sequence_matcher is None:
94
95
        sequence_matcher = patiencediff.PatienceSequenceMatcher
95
96
    ud = patiencediff.unified_diff_bytes(oldlines, newlines,
96
 
                      fromfile=old_label.encode(path_encoding, 'replace'),
97
 
                      tofile=new_label.encode(path_encoding, 'replace'),
98
 
                      n=context_lines, sequencematcher=sequence_matcher)
 
97
                                         fromfile=old_label.encode(
 
98
                                             path_encoding, 'replace'),
 
99
                                         tofile=new_label.encode(
 
100
                                             path_encoding, 'replace'),
 
101
                                         n=context_lines, sequencematcher=sequence_matcher)
99
102
 
100
103
    ud = list(ud)
101
 
    if len(ud) == 0: # Identical contents, nothing to do
 
104
    if len(ud) == 0:  # Identical contents, nothing to do
102
105
        return
103
106
    # work-around for difflib being too smart for its own good
104
107
    # if /dev/null is "1,0", patch won't recognize it as /dev/null
150
153
 
151
154
    return pipe
152
155
 
 
156
 
153
157
# diff style options as of GNU diff v3.2
154
158
style_option_list = ['-c', '-C', '--context',
155
159
                     '-e', '--ed',
161
165
                     '-y', '--side-by-side',
162
166
                     '-D', '--ifdef']
163
167
 
 
168
 
164
169
def default_style_unified(diff_opts):
165
170
    """Default to unified diff style if alternative not specified in diff_opts.
166
171
 
223
228
                   '--label', new_label,
224
229
                   new_abspath,
225
230
                   '--binary',
226
 
                  ]
 
231
                   ]
227
232
 
228
233
        diff_opts = default_style_unified(diff_opts)
229
234
 
248
253
            out, err = pipe.communicate()
249
254
 
250
255
            # Write out the new i18n diff response
251
 
            to_file.write(out+b'\n')
 
256
            to_file.write(out + b'\n')
252
257
            if pipe.returncode != 2:
253
258
                raise errors.BzrError(
254
 
                               'external diff failed with exit code 2'
255
 
                               ' when run with LANG=C and LC_ALL=C,'
256
 
                               ' but not when run natively: %r' % (diffcmd,))
 
259
                    'external diff failed with exit code 2'
 
260
                    ' when run with LANG=C and LC_ALL=C,'
 
261
                    ' but not when run natively: %r' % (diffcmd,))
257
262
 
258
263
            first_line = lang_c_out.split(b'\n', 1)[0]
259
264
            # Starting with diffutils 2.8.4 the word "binary" was dropped.
278
283
            raise errors.BzrError('external diff failed with %s; command: %r'
279
284
                                  % (msg, diffcmd))
280
285
 
281
 
 
282
286
    finally:
283
287
        oldtmpf.close()                 # and delete
284
288
        newtmpf.close()
298
302
 
299
303
 
300
304
def get_trees_and_branches_to_diff_locked(
301
 
    path_list, revision_specs, old_url, new_url, add_cleanup, apply_view=True):
 
305
        path_list, revision_specs, old_url, new_url, add_cleanup, apply_view=True):
302
306
    """Get the trees and specific files to diff given a list of paths.
303
307
 
304
308
    This method works out the trees to be diff'ed and the files of
389
393
                views.check_path_in_view(working_tree, relpath)
390
394
            specific_files.append(relpath)
391
395
    new_tree = _get_tree_to_diff(new_revision_spec, working_tree, branch,
392
 
        basis_is_default=working_tree is None)
 
396
                                 basis_is_default=working_tree is None)
393
397
    new_branch = branch
394
398
 
395
399
    # Get the specific files (all files is None, no files is [])
400
404
    specific_files.extend(other_paths)
401
405
    if len(specific_files) == 0:
402
406
        specific_files = None
403
 
        if (working_tree is not None and working_tree.supports_views()
404
 
            and apply_view):
 
407
        if (working_tree is not None and working_tree.supports_views() and
 
408
                apply_view):
405
409
            view_files = working_tree.views.lookup_view()
406
410
            if view_files:
407
411
                specific_files = view_files
476
480
def _patch_header_date(tree, file_id, path):
477
481
    """Returns a timestamp suitable for use in a patch header."""
478
482
    try:
479
 
        mtime = tree.get_file_mtime(path, file_id)
 
483
        mtime = tree.get_file_mtime(path)
480
484
    except FileTimestampUnavailable:
481
485
        mtime = 0
482
486
    return timestamp.format_patch_date(mtime)
483
487
 
484
488
 
485
489
def get_executable_change(old_is_x, new_is_x):
486
 
    descr = { True:b"+x", False:b"-x", None:b"??" }
 
490
    descr = {True: b"+x", False: b"-x", None: b"??"}
487
491
    if old_is_x != new_is_x:
488
492
        return [b"%s to %s" % (descr[old_is_x], descr[new_is_x],)]
489
493
    else:
538
542
    Represents kind change as deletion + creation.  Uses the other differs
539
543
    to do this.
540
544
    """
 
545
 
541
546
    def __init__(self, differs):
542
547
        self.differs = differs
543
548
 
560
565
        if None in (old_kind, new_kind):
561
566
            return DiffPath.CANNOT_DIFF
562
567
        result = DiffPath._diff_many(self.differs, file_id, old_path,
563
 
                                       new_path, old_kind, None)
 
568
                                     new_path, old_kind, None)
564
569
        if result is DiffPath.CANNOT_DIFF:
565
570
            return result
566
571
        return DiffPath._diff_many(self.differs, file_id, old_path, new_path,
567
 
                                     None, new_kind)
 
572
                                   None, new_kind)
568
573
 
569
574
 
570
575
class DiffDirectory(DiffPath):
596
601
        if 'symlink' not in (old_kind, new_kind):
597
602
            return self.CANNOT_DIFF
598
603
        if old_kind == 'symlink':
599
 
            old_target = self.old_tree.get_symlink_target(old_path, file_id)
 
604
            old_target = self.old_tree.get_symlink_target(old_path)
600
605
        elif old_kind is None:
601
606
            old_target = None
602
607
        else:
603
608
            return self.CANNOT_DIFF
604
609
        if new_kind == 'symlink':
605
 
            new_target = self.new_tree.get_symlink_target(new_path, file_id)
 
610
            new_target = self.new_tree.get_symlink_target(new_path)
606
611
        elif new_kind is None:
607
612
            new_target = None
608
613
        else:
612
617
    def diff_symlink(self, old_target, new_target):
613
618
        if old_target is None:
614
619
            self.to_file.write(b'=== target is \'%s\'\n' %
615
 
                new_target.encode(self.path_encoding, 'replace'))
 
620
                               new_target.encode(self.path_encoding, 'replace'))
616
621
        elif new_target is None:
617
622
            self.to_file.write(b'=== target was \'%s\'\n' %
618
 
                old_target.encode(self.path_encoding, 'replace'))
 
623
                               old_target.encode(self.path_encoding, 'replace'))
619
624
        else:
620
625
            self.to_file.write(b'=== target changed \'%s\' => \'%s\'\n' %
621
 
                              (old_target.encode(self.path_encoding, 'replace'),
622
 
                               new_target.encode(self.path_encoding, 'replace')))
 
626
                               (old_target.encode(self.path_encoding, 'replace'),
 
627
                                new_target.encode(self.path_encoding, 'replace')))
623
628
        return self.CHANGED
624
629
 
625
630
 
629
634
    # or removed in a diff.
630
635
    EPOCH_DATE = '1970-01-01 00:00:00 +0000'
631
636
 
632
 
    def __init__(self, old_tree, new_tree, to_file, path_encoding='utf-8', 
633
 
                 old_label='', new_label='', text_differ=internal_diff, 
 
637
    def __init__(self, old_tree, new_tree, to_file, path_encoding='utf-8',
 
638
                 old_label='', new_label='', text_differ=internal_diff,
634
639
                 context_lines=DEFAULT_CONTEXT_AMOUNT):
635
640
        DiffPath.__init__(self, old_tree, new_tree, to_file, path_encoding)
636
641
        self.text_differ = text_differ
666
671
        else:
667
672
            return self.CANNOT_DIFF
668
673
        from_label = '%s%s\t%s' % (self.old_label, old_path,
669
 
                old_date)
 
674
                                   old_date)
670
675
        to_label = '%s%s\t%s' % (self.new_label, new_path,
671
 
                new_date)
 
676
                                 new_date)
672
677
        return self.diff_text(old_path, new_path, from_label, to_label,
673
 
            from_file_id, to_file_id)
 
678
                              from_file_id, to_file_id)
674
679
 
675
680
    def diff_text(self, from_path, to_path, from_label, to_label,
676
 
        from_file_id=None, to_file_id=None):
 
681
                  from_file_id=None, to_file_id=None):
677
682
        """Diff the content of given files in two trees
678
683
 
679
684
        :param from_path: The path in the from tree. If None,
689
694
        def _get_text(tree, file_id, path):
690
695
            if file_id is None:
691
696
                return []
692
 
            return tree.get_file_lines(path, file_id)
 
697
            return tree.get_file_lines(path)
693
698
        try:
694
699
            from_text = _get_text(self.old_tree, from_file_id, from_path)
695
700
            to_text = _get_text(self.new_tree, to_file_id, to_path)
698
703
                             context_lines=self.context_lines)
699
704
        except errors.BinaryFile:
700
705
            self.to_file.write(
701
 
                  ("Binary files %s and %s differ\n" %
702
 
                  (from_label, to_label)).encode(self.path_encoding, 'replace'))
 
706
                ("Binary files %s and %s differ\n" %
 
707
                 (from_label, to_label)).encode(self.path_encoding, 'replace'))
703
708
        return self.CHANGED
704
709
 
705
710
 
734
739
        my_map = {'old_path': old_path, 'new_path': new_path}
735
740
        command = [AtTemplate(t).substitute(my_map) for t in
736
741
                   self.command_template]
737
 
        if sys.platform == 'win32': # Popen doesn't accept unicode on win32
 
742
        if sys.platform == 'win32':  # Popen doesn't accept unicode on win32
738
743
            command_encoded = []
739
744
            for c in command:
740
745
                if isinstance(c, text_type):
760
765
        return proc.wait()
761
766
 
762
767
    def _try_symlink_root(self, tree, prefix):
763
 
        if (getattr(tree, 'abspath', None) is None
764
 
            or not osutils.host_os_dereferences_symlinks()):
 
768
        if (getattr(tree, 'abspath', None) is None or
 
769
                not osutils.host_os_dereferences_symlinks()):
765
770
            return False
766
771
        try:
767
772
            os.symlink(tree.abspath(''), osutils.pathjoin(self._root, prefix))
814
819
        except OSError as e:
815
820
            if e.errno != errno.EEXIST:
816
821
                raise
817
 
        source = tree.get_file(relpath, file_id)
 
822
        source = tree.get_file(relpath)
818
823
        try:
819
824
            with open(full_path, 'wb') as target:
820
825
                osutils.pumpfile(source, target)
821
826
        finally:
822
827
            source.close()
823
828
        try:
824
 
            mtime = tree.get_file_mtime(relpath, file_id)
 
829
            mtime = tree.get_file_mtime(relpath)
825
830
        except FileTimestampUnavailable:
826
831
            pass
827
832
        else:
845
850
        except OSError as e:
846
851
            if e.errno != errno.ENOENT:
847
852
                mutter("The temporary directory \"%s\" was not "
848
 
                        "cleanly removed: %s." % (self._root, e))
 
853
                       "cleanly removed: %s." % (self._root, e))
849
854
 
850
855
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
851
856
        if (old_kind, new_kind) != ('file', 'file'):
852
857
            return DiffPath.CANNOT_DIFF
853
858
        (old_disk_path, new_disk_path) = self._prepare_files(
854
 
                old_path, new_path, file_id=file_id)
 
859
            old_path, new_path, file_id=file_id)
855
860
        self._execute(old_disk_path, new_disk_path)
856
861
 
857
862
    def edit_file(self, old_path, new_path, file_id=None):
864
869
        :return: The new contents of the file.
865
870
        """
866
871
        old_abs_path, new_abs_path = self._prepare_files(
867
 
                old_path, new_path, allow_write_new=True, force_temp=True,
868
 
                file_id=file_id)
 
872
            old_path, new_path, allow_write_new=True, force_temp=True,
 
873
            file_id=file_id)
869
874
        command = self._get_command(old_abs_path, new_abs_path)
870
875
        subprocess.call(command, cwd=self._root)
871
876
        with open(new_abs_path, 'rb') as new_file:
903
908
            DiffPaths"""
904
909
        if diff_text is None:
905
910
            diff_text = DiffText(old_tree, new_tree, to_file, path_encoding,
906
 
                                 '', '',  internal_diff)
 
911
                                 '', '', internal_diff)
907
912
        self.old_tree = old_tree
908
913
        self.new_tree = new_tree
909
914
        self.to_file = to_file
933
938
        :param using: Commandline to use to invoke an external diff tool
934
939
        """
935
940
        if using is not None:
936
 
            extra_factories = [DiffFromTool.make_from_diff_tree(using, external_diff_options)]
 
941
            extra_factories = [DiffFromTool.make_from_diff_tree(
 
942
                using, external_diff_options)]
937
943
        else:
938
944
            extra_factories = []
939
945
        if external_diff_options:
940
946
            opts = external_diff_options.split()
 
947
 
941
948
            def diff_file(olab, olines, nlab, nlines, to_file, path_encoding=None, context_lines=None):
942
949
                """:param path_encoding: not used but required
943
950
                        to match the signature of internal_diff.
966
973
        # TODO: Generation of pseudo-diffs for added/deleted files could
967
974
        # be usefully made into a much faster special case.
968
975
        iterator = self.new_tree.iter_changes(self.old_tree,
969
 
                                               specific_files=specific_files,
970
 
                                               extra_trees=extra_trees,
971
 
                                               require_versioned=True)
 
976
                                              specific_files=specific_files,
 
977
                                              extra_trees=extra_trees,
 
978
                                              require_versioned=True)
972
979
        has_changes = 0
 
980
 
973
981
        def changes_key(change):
974
982
            old_path, new_path = change[1]
975
983
            path = new_path
976
984
            if path is None:
977
985
                path = old_path
978
986
            return path
 
987
 
979
988
        def get_encoded_path(path):
980
989
            if path is not None:
981
990
                return path.encode(self.path_encoding, "replace")
993
1002
            renamed = (parent[0], name[0]) != (parent[1], name[1])
994
1003
 
995
1004
            properties_changed = []
996
 
            properties_changed.extend(get_executable_change(executable[0], executable[1]))
 
1005
            properties_changed.extend(
 
1006
                get_executable_change(executable[0], executable[1]))
997
1007
 
998
1008
            if properties_changed:
999
1009
                prop_str = b" (properties changed: %s)" % (
1000
 
                        b", ".join(properties_changed),)
 
1010
                    b", ".join(properties_changed),)
1001
1011
            else:
1002
1012
                prop_str = b""
1003
1013
 
1011
1021
                oldpath = newpath
1012
1022
            elif renamed:
1013
1023
                self.to_file.write(b"=== renamed %s '%s' => '%s'%s\n" %
1014
 
                    (kind[0].encode('ascii'), oldpath_encoded, newpath_encoded, prop_str))
 
1024
                                   (kind[0].encode('ascii'), oldpath_encoded, newpath_encoded, prop_str))
1015
1025
            else:
1016
1026
                # if it was produced by iter_changes, it must be
1017
1027
                # modified *somehow*, either content or execute bit.
1018
1028
                self.to_file.write(b"=== modified %s '%s'%s\n" % (kind[0].encode('ascii'),
1019
 
                                   newpath_encoded, prop_str))
 
1029
                                                                  newpath_encoded, prop_str))
1020
1030
            if changed_content:
1021
1031
                self._diff(oldpath, newpath, kind[0], kind[1], file_id=file_id)
1022
1032
                has_changes = 1
1034
1044
        if old_path is None:
1035
1045
            old_kind = None
1036
1046
        else:
1037
 
            old_kind = self.old_tree.kind(old_path, file_id)
 
1047
            old_kind = self.old_tree.kind(old_path)
1038
1048
        if new_path is None:
1039
1049
            new_kind = None
1040
1050
        else:
1041
 
            new_kind = self.new_tree.kind(new_path, file_id)
 
1051
            new_kind = self.new_tree.kind(new_path)
1042
1052
        self._diff(old_path, new_path, old_kind, new_kind, file_id=file_id)
1043
1053
 
1044
1054
    def _diff(self, old_path, new_path, old_kind, new_kind, file_id):