~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Robert Collins
  • Date: 2010-06-28 02:41:22 UTC
  • mto: This revision was merged to the branch mainline in revision 5324.
  • Revision ID: robertc@robertcollins.net-20100628024122-g951fzp74f3u6wst
Sanity check that new_trace_file in pop_log_file is valid, and also fix a test that monkey patched get_terminal_encoding.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd.
 
1
# Copyright (C) 2005-2010 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
28
29
 
29
30
from bzrlib import (
 
31
    branch as _mod_branch,
30
32
    bzrdir,
31
33
    cmdline,
32
34
    cleanup,
418
420
 
419
421
    # Get the specific files (all files is None, no files is [])
420
422
    if make_paths_wt_relative and working_tree is not None:
421
 
        other_paths = working_tree.safe_relpath_files(
422
 
            other_paths,
 
423
        try:
 
424
            from bzrlib.builtins import safe_relpath_files
 
425
            other_paths = safe_relpath_files(working_tree, other_paths,
423
426
            apply_view=apply_view)
 
427
        except errors.FileInWrongBranch:
 
428
            raise errors.BzrCommandError("Files are in different branches")
424
429
    specific_files.extend(other_paths)
425
430
    if len(specific_files) == 0:
426
431
        specific_files = None
463
468
    """Show in text form the changes from one tree to another.
464
469
 
465
470
    :param to_file: The output stream.
466
 
    :param specific_files: Include only changes to these files - None for all
 
471
    :param specific_files:Include only changes to these files - None for all
467
472
        changes.
468
473
    :param external_diff_options: If set, use an external GNU diff and pass 
469
474
        these options.
734
739
                     path_encoding)
735
740
 
736
741
    @classmethod
737
 
    def make_from_diff_tree(klass, command_string, external_diff_options=None):
 
742
    def make_from_diff_tree(klass, command_string):
738
743
        def from_diff_tree(diff_tree):
739
 
            full_command_string = [command_string]
740
 
            if external_diff_options is not None:
741
 
                full_command_string += ' ' + external_diff_options
742
 
            return klass.from_string(full_command_string, diff_tree.old_tree,
 
744
            return klass.from_string(command_string, diff_tree.old_tree,
743
745
                                     diff_tree.new_tree, diff_tree.to_file)
744
746
        return from_diff_tree
745
747
 
746
748
    def _get_command(self, old_path, new_path):
747
749
        my_map = {'old_path': old_path, 'new_path': new_path}
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
        return [AtTemplate(t).substitute(my_map) for t in
 
751
                self.command_template]
760
752
 
761
753
    def _execute(self, old_path, new_path):
762
754
        command = self._get_command(old_path, new_path)
782
774
                raise
783
775
        return True
784
776
 
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
 
 
813
777
    def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
814
778
                    allow_write=False):
815
779
        if not force_temp and isinstance(tree, WorkingTree):
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)
 
780
            return tree.abspath(tree.id2path(file_id))
 
781
        
 
782
        full_path = osutils.pathjoin(self._root, prefix, relpath)
821
783
        if not force_temp and self._try_symlink_root(tree, prefix):
822
784
            return full_path
823
785
        parent_dir = osutils.dirname(full_path)
880
842
        """
881
843
        old_path = self.old_tree.id2path(file_id)
882
844
        new_path = self.new_tree.id2path(file_id)
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)
 
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))
888
850
        subprocess.call(command, cwd=self._root)
889
 
        new_file = open(new_abs_path, 'rb')
 
851
        new_file = open(new_abs_path, 'r')
890
852
        try:
891
853
            return new_file.read()
892
854
        finally:
942
904
        """Factory for producing a DiffTree.
943
905
 
944
906
        Designed to accept options used by show_diff_trees.
945
 
 
946
907
        :param old_tree: The tree to show as old in the comparison
947
908
        :param new_tree: The tree to show as new in the comparison
948
909
        :param to_file: File to write comparisons to
954
915
        :param using: Commandline to use to invoke an external diff tool
955
916
        """
956
917
        if using is not None:
957
 
            extra_factories = [DiffFromTool.make_from_diff_tree(using, external_diff_options)]
 
918
            extra_factories = [DiffFromTool.make_from_diff_tree(using)]
958
919
        else:
959
920
            extra_factories = []
960
921
        if external_diff_options: