~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd.
 
1
# Copyright (C) 2005-2011 Canonical Ltd.
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
import errno
26
26
import subprocess
27
27
import tempfile
28
 
import time
29
28
 
30
29
from bzrlib import (
31
 
    branch as _mod_branch,
32
30
    bzrdir,
33
31
    cmdline,
34
32
    cleanup,
465
463
    """Show in text form the changes from one tree to another.
466
464
 
467
465
    :param to_file: The output stream.
468
 
    :param specific_files:Include only changes to these files - None for all
 
466
    :param specific_files: Include only changes to these files - None for all
469
467
        changes.
470
468
    :param external_diff_options: If set, use an external GNU diff and pass 
471
469
        these options.
747
745
 
748
746
    def _get_command(self, old_path, new_path):
749
747
        my_map = {'old_path': old_path, 'new_path': new_path}
750
 
        return [AtTemplate(t).substitute(my_map) for t in
751
 
                self.command_template]
 
748
        command = [AtTemplate(t).substitute(my_map) for t in
 
749
                   self.command_template]
 
750
        if sys.platform == 'win32': # Popen doesn't accept unicode on win32
 
751
            command_encoded = []
 
752
            for c in command:
 
753
                if isinstance(c, unicode):
 
754
                    command_encoded.append(c.encode('mbcs'))
 
755
                else:
 
756
                    command_encoded.append(c)
 
757
            return command_encoded
 
758
        else:
 
759
            return command
752
760
 
753
761
    def _execute(self, old_path, new_path):
754
762
        command = self._get_command(old_path, new_path)
774
782
                raise
775
783
        return True
776
784
 
 
785
    @staticmethod
 
786
    def _fenc():
 
787
        """Returns safe encoding for passing file path to diff tool"""
 
788
        if sys.platform == 'win32':
 
789
            return 'mbcs'
 
790
        else:
 
791
            # Don't fallback to 'utf-8' because subprocess may not be able to
 
792
            # handle utf-8 correctly when locale is not utf-8.
 
793
            return sys.getfilesystemencoding() or 'ascii'
 
794
 
 
795
    def _is_safepath(self, path):
 
796
        """Return true if `path` may be able to pass to subprocess."""
 
797
        fenc = self._fenc()
 
798
        try:
 
799
            return path == path.encode(fenc).decode(fenc)
 
800
        except UnicodeError:
 
801
            return False
 
802
 
 
803
    def _safe_filename(self, prefix, relpath):
 
804
        """Replace unsafe character in `relpath` then join `self._root`,
 
805
        `prefix` and `relpath`."""
 
806
        fenc = self._fenc()
 
807
        # encoded_str.replace('?', '_') may break multibyte char.
 
808
        # So we should encode, decode, then replace(u'?', u'_')
 
809
        relpath_tmp = relpath.encode(fenc, 'replace').decode(fenc, 'replace')
 
810
        relpath_tmp = relpath_tmp.replace(u'?', u'_')
 
811
        return osutils.pathjoin(self._root, prefix, relpath_tmp)
 
812
 
777
813
    def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
778
814
                    allow_write=False):
779
815
        if not force_temp and isinstance(tree, WorkingTree):
780
 
            return tree.abspath(tree.id2path(file_id))
781
 
        
782
 
        full_path = osutils.pathjoin(self._root, prefix, relpath)
 
816
            full_path = tree.abspath(tree.id2path(file_id))
 
817
            if self._is_safepath(full_path):
 
818
                return full_path
 
819
 
 
820
        full_path = self._safe_filename(prefix, relpath)
783
821
        if not force_temp and self._try_symlink_root(tree, prefix):
784
822
            return full_path
785
823
        parent_dir = osutils.dirname(full_path)
842
880
        """
843
881
        old_path = self.old_tree.id2path(file_id)
844
882
        new_path = self.new_tree.id2path(file_id)
845
 
        new_abs_path = self._prepare_files(file_id, old_path, new_path,
846
 
                                           allow_write_new=True,
847
 
                                           force_temp=True)[1]
848
 
        command = self._get_command(osutils.pathjoin('old', old_path),
849
 
                                    osutils.pathjoin('new', new_path))
 
883
        old_abs_path, new_abs_path = self._prepare_files(
 
884
                                            file_id, old_path, new_path,
 
885
                                            allow_write_new=True,
 
886
                                            force_temp=True)
 
887
        command = self._get_command(old_abs_path, new_abs_path)
850
888
        subprocess.call(command, cwd=self._root)
851
 
        new_file = open(new_abs_path, 'r')
 
889
        new_file = open(new_abs_path, 'rb')
852
890
        try:
853
891
            return new_file.read()
854
892
        finally:
904
942
        """Factory for producing a DiffTree.
905
943
 
906
944
        Designed to accept options used by show_diff_trees.
 
945
 
907
946
        :param old_tree: The tree to show as old in the comparison
908
947
        :param new_tree: The tree to show as new in the comparison
909
948
        :param to_file: File to write comparisons to