Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: scm.py

Issue 14084009: Reland r195308, r195328, and r195363, which use --internal-diff on svn 1.7+. (Closed) Base URL: http://src.chromium.org/svn/trunk/tools/depot_tools/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """SCM-specific utility classes.""" 5 """SCM-specific utility classes."""
6 6
7 import cStringIO 7 import cStringIO
8 import glob 8 import glob
9 import logging 9 import logging
10 import os 10 import os
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after
774 @staticmethod 774 @staticmethod
775 def GenerateDiff(filenames, cwd, full_move, revision): 775 def GenerateDiff(filenames, cwd, full_move, revision):
776 """Returns a string containing the diff for the given file list. 776 """Returns a string containing the diff for the given file list.
777 777
778 The files in the list should either be absolute paths or relative to the 778 The files in the list should either be absolute paths or relative to the
779 given root. If no root directory is provided, the repository root will be 779 given root. If no root directory is provided, the repository root will be
780 used. 780 used.
781 The diff will always use relative paths. 781 The diff will always use relative paths.
782 """ 782 """
783 assert isinstance(filenames, (list, tuple)) 783 assert isinstance(filenames, (list, tuple))
784 # If the user specified a custom diff command in their svn config file,
785 # then it'll be used when we do svn diff, which we don't want to happen
786 # since we want the unified diff.
787 if SVN.AssertVersion("1.7")[0]:
788 # On svn >= 1.7, the "--internal-diff" flag will solve this.
789 return SVN._GenerateDiffInternal(filenames, cwd, full_move, revision,
790 ["diff", "--internal-diff"],
791 ["diff", "--internal-diff"])
792 else:
793 # On svn < 1.7, the "--internal-diff" flag doesn't exist. Using
794 # --diff-cmd=diff doesn't always work, since e.g. Windows cmd users may
795 # not have a "diff" executable in their path at all. So we use an empty
796 # temporary directory as the config directory, which bypasses any user
797 # settings for the diff-cmd. However, we don't pass this for the
798 # remote_safe_diff_command parameter, since when a new config-dir is
799 # specified for an svn diff against a remote URL, it triggers
800 # authentication prompts. In this case there isn't really a good
801 # alternative to svn 1.7's --internal-diff flag.
802 bogus_dir = tempfile.mkdtemp()
803 try:
804 return SVN._GenerateDiffInternal(filenames, cwd, full_move, revision,
805 ["diff", "--config-dir", bogus_dir],
806 ["diff"])
807 finally:
808 gclient_utils.rmtree(bogus_dir)
809
810 @staticmethod
811 def _GenerateDiffInternal(filenames, cwd, full_move, revision, diff_command,
812 remote_safe_diff_command):
784 root = os.path.normcase(os.path.join(cwd, '')) 813 root = os.path.normcase(os.path.join(cwd, ''))
785 def RelativePath(path, root): 814 def RelativePath(path, root):
786 """We must use relative paths.""" 815 """We must use relative paths."""
787 if os.path.normcase(path).startswith(root): 816 if os.path.normcase(path).startswith(root):
788 return path[len(root):] 817 return path[len(root):]
789 return path 818 return path
790 # If the user specified a custom diff command in their svn config file, 819 # Cleanup filenames
791 # then it'll be used when we do svn diff, which we don't want to happen 820 filenames = [RelativePath(f, root) for f in filenames]
792 # since we want the unified diff. Using --diff-cmd=diff doesn't always 821 # Get information about the modified items (files and directories)
793 # work, since they can have another diff executable in their path that 822 data = dict((f, SVN.CaptureLocalInfo([f], root)) for f in filenames)
794 # gives different line endings. So we use a bogus temp directory as the 823 diffs = []
795 # config directory, which gets around these problems. 824 if full_move:
796 bogus_dir = tempfile.mkdtemp() 825 # Eliminate modified files inside moved/copied directory.
797 try: 826 for (filename, info) in data.iteritems():
798 # Cleanup filenames 827 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory":
799 filenames = [RelativePath(f, root) for f in filenames] 828 # Remove files inside the directory.
800 # Get information about the modified items (files and directories) 829 filenames = [f for f in filenames
801 data = dict([(f, SVN.CaptureLocalInfo([f], root)) for f in filenames]) 830 if not f.startswith(filename + os.path.sep)]
802 diffs = [] 831 for filename in data.keys():
803 if full_move: 832 if not filename in filenames:
804 # Eliminate modified files inside moved/copied directory. 833 # Remove filtered out items.
805 for (filename, info) in data.iteritems(): 834 del data[filename]
806 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory": 835 else:
807 # Remove files inside the directory. 836 metaheaders = []
808 filenames = [f for f in filenames 837 for (filename, info) in data.iteritems():
809 if not f.startswith(filename + os.path.sep)] 838 if SVN.IsMovedInfo(info):
810 for filename in data.keys(): 839 # for now, the most common case is a head copy,
811 if not filename in filenames: 840 # so let's just encode that as a straight up cp.
812 # Remove filtered out items. 841 srcurl = info.get('Copied From URL')
813 del data[filename] 842 file_root = info.get('Repository Root')
814 else: 843 rev = int(info.get('Copied From Rev'))
815 metaheaders = [] 844 assert srcurl.startswith(file_root)
816 for (filename, info) in data.iteritems(): 845 src = srcurl[len(file_root)+1:]
817 if SVN.IsMovedInfo(info): 846 try:
818 # for now, the most common case is a head copy, 847 srcinfo = SVN.CaptureRemoteInfo(srcurl)
819 # so let's just encode that as a straight up cp. 848 except subprocess2.CalledProcessError, e:
820 srcurl = info.get('Copied From URL') 849 if not 'Not a valid URL' in e.stderr:
821 file_root = info.get('Repository Root') 850 raise
822 rev = int(info.get('Copied From Rev')) 851 # Assume the file was deleted. No idea how to figure out at which
823 assert srcurl.startswith(file_root) 852 # revision the file was deleted.
824 src = srcurl[len(file_root)+1:] 853 srcinfo = {'Revision': rev}
825 try: 854 if (srcinfo.get('Revision') != rev and
826 srcinfo = SVN.CaptureRemoteInfo(srcurl) 855 SVN.Capture(remote_safe_diff_command + ['-r', '%d:head' % rev,
827 except subprocess2.CalledProcessError, e: 856 srcurl], cwd)):
828 if not 'Not a valid URL' in e.stderr: 857 metaheaders.append("#$ svn cp -r %d %s %s "
829 raise 858 "### WARNING: note non-trunk copy\n" %
830 # Assume the file was deleted. No idea how to figure out at which 859 (rev, src, filename))
831 # revision the file was deleted. 860 else:
832 srcinfo = {'Revision': rev} 861 metaheaders.append("#$ cp %s %s\n" % (src,
833 if (srcinfo.get('Revision') != rev and 862 filename))
834 SVN.Capture(['diff', '-r', '%d:head' % rev, srcurl], cwd)): 863 if metaheaders:
835 metaheaders.append("#$ svn cp -r %d %s %s " 864 diffs.append("### BEGIN SVN COPY METADATA\n")
836 "### WARNING: note non-trunk copy\n" % 865 diffs.extend(metaheaders)
837 (rev, src, filename)) 866 diffs.append("### END SVN COPY METADATA\n")
838 else: 867 # Now ready to do the actual diff.
839 metaheaders.append("#$ cp %s %s\n" % (src, 868 for filename in sorted(data):
840 filename)) 869 diffs.append(SVN._DiffItemInternal(
841 870 filename, cwd, data[filename], diff_command, full_move, revision))
842 if metaheaders: 871 # Use StringIO since it can be messy when diffing a directory move with
843 diffs.append("### BEGIN SVN COPY METADATA\n") 872 # full_move=True.
844 diffs.extend(metaheaders) 873 buf = cStringIO.StringIO()
845 diffs.append("### END SVN COPY METADATA\n") 874 for d in filter(None, diffs):
846 # Now ready to do the actual diff. 875 buf.write(d)
847 for filename in sorted(data.iterkeys()): 876 result = buf.getvalue()
848 diffs.append(SVN._DiffItemInternal( 877 buf.close()
849 filename, cwd, data[filename], bogus_dir, full_move, revision)) 878 return result
850 # Use StringIO since it can be messy when diffing a directory move with
851 # full_move=True.
852 buf = cStringIO.StringIO()
853 for d in filter(None, diffs):
854 buf.write(d)
855 result = buf.getvalue()
856 buf.close()
857 return result
858 finally:
859 gclient_utils.rmtree(bogus_dir)
860 879
861 @staticmethod 880 @staticmethod
862 def _DiffItemInternal(filename, cwd, info, bogus_dir, full_move, revision): 881 def _DiffItemInternal(filename, cwd, info, diff_command, full_move, revision):
863 """Grabs the diff data.""" 882 """Grabs the diff data."""
864 command = ["diff", "--config-dir", bogus_dir, filename] 883 command = diff_command + [filename]
865 if revision: 884 if revision:
866 command.extend(['--revision', revision]) 885 command.extend(['--revision', revision])
867 data = None 886 data = None
868 if SVN.IsMovedInfo(info): 887 if SVN.IsMovedInfo(info):
869 if full_move: 888 if full_move:
870 if info.get("Node Kind") == "directory": 889 if info.get("Node Kind") == "directory":
871 # Things become tricky here. It's a directory copy/move. We need to 890 # Things become tricky here. It's a directory copy/move. We need to
872 # diff all the files inside it. 891 # diff all the files inside it.
873 # This will put a lot of pressure on the heap. This is why StringIO 892 # This will put a lot of pressure on the heap. This is why StringIO
874 # is used and converted back into a string at the end. The reason to 893 # is used and converted back into a string at the end. The reason to
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 # revert, like for properties. 1086 # revert, like for properties.
1068 if not os.path.isdir(cwd): 1087 if not os.path.isdir(cwd):
1069 # '.' was deleted. It's not worth continuing. 1088 # '.' was deleted. It's not worth continuing.
1070 return 1089 return
1071 try: 1090 try:
1072 SVN.Capture(['revert', file_status[1]], cwd=cwd) 1091 SVN.Capture(['revert', file_status[1]], cwd=cwd)
1073 except subprocess2.CalledProcessError: 1092 except subprocess2.CalledProcessError:
1074 if not os.path.exists(file_path): 1093 if not os.path.exists(file_path):
1075 continue 1094 continue
1076 raise 1095 raise
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698