463
463
"""Show in text form the changes from one tree to another.
465
465
:param to_file: The output stream.
466
: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
468
468
:param external_diff_options: If set, use an external GNU diff and pass
746
746
def _get_command(self, old_path, new_path):
747
747
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
753
if isinstance(c, unicode):
754
command_encoded.append(c.encode('mbcs'))
756
command_encoded.append(c)
757
return command_encoded
748
return [AtTemplate(t).substitute(my_map) for t in
749
self.command_template]
761
751
def _execute(self, old_path, new_path):
762
752
command = self._get_command(old_path, new_path)
787
"""Returns safe encoding for passing file path to diff tool"""
788
if sys.platform == 'win32':
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'
795
def _is_safepath(self, path):
796
"""Return true if `path` may be able to pass to subprocess."""
799
return path == path.encode(fenc).decode(fenc)
803
def _safe_filename(self, prefix, relpath):
804
"""Replace unsafe character in `relpath` then join `self._root`,
805
`prefix` and `relpath`."""
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)
813
775
def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
814
776
allow_write=False):
815
777
if not force_temp and isinstance(tree, WorkingTree):
816
full_path = tree.abspath(tree.id2path(file_id))
817
if self._is_safepath(full_path):
820
full_path = self._safe_filename(prefix, relpath)
778
return tree.abspath(tree.id2path(file_id))
780
full_path = osutils.pathjoin(self._root, prefix, relpath)
821
781
if not force_temp and self._try_symlink_root(tree, prefix):
823
783
parent_dir = osutils.dirname(full_path)
881
841
old_path = self.old_tree.id2path(file_id)
882
842
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,
887
command = self._get_command(old_abs_path, new_abs_path)
843
new_abs_path = self._prepare_files(file_id, old_path, new_path,
844
allow_write_new=True,
846
command = self._get_command(osutils.pathjoin('old', old_path),
847
osutils.pathjoin('new', new_path))
888
848
subprocess.call(command, cwd=self._root)
889
new_file = open(new_abs_path, 'rb')
849
new_file = open(new_abs_path, 'r')
891
851
return new_file.read()
942
902
"""Factory for producing a DiffTree.
944
904
Designed to accept options used by show_diff_trees.
946
905
:param old_tree: The tree to show as old in the comparison
947
906
:param new_tree: The tree to show as new in the comparison
948
907
:param to_file: File to write comparisons to