~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-05-18 16:11:05 UTC
  • mfrom: (5074.5.9 fix523746)
  • Revision ID: pqm@pqm.ubuntu.com-20110518161105-pbt4yc8mgl0y3qsy
(mbp) better handling of subprocesses with non-ascii encodings and filenames
 (bug 523746) (INADA Naoki)

Show diffs side-by-side

added added

removed removed

Lines of Context:
745
745
 
746
746
    def _get_command(self, old_path, new_path):
747
747
        my_map = {'old_path': old_path, 'new_path': new_path}
748
 
        return [AtTemplate(t).substitute(my_map) for t in
749
 
                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
750
760
 
751
761
    def _execute(self, old_path, new_path):
752
762
        command = self._get_command(old_path, new_path)
772
782
                raise
773
783
        return True
774
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
 
775
813
    def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
776
814
                    allow_write=False):
777
815
        if not force_temp and isinstance(tree, WorkingTree):
778
 
            return tree.abspath(tree.id2path(file_id))
779
 
        
780
 
        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)
781
821
        if not force_temp and self._try_symlink_root(tree, prefix):
782
822
            return full_path
783
823
        parent_dir = osutils.dirname(full_path)
840
880
        """
841
881
        old_path = self.old_tree.id2path(file_id)
842
882
        new_path = self.new_tree.id2path(file_id)
843
 
        new_abs_path = self._prepare_files(file_id, old_path, new_path,
844
 
                                           allow_write_new=True,
845
 
                                           force_temp=True)[1]
846
 
        command = self._get_command(osutils.pathjoin('old', old_path),
847
 
                                    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)
848
888
        subprocess.call(command, cwd=self._root)
849
 
        new_file = open(new_abs_path, 'r')
 
889
        new_file = open(new_abs_path, 'rb')
850
890
        try:
851
891
            return new_file.read()
852
892
        finally: