OLD | NEW |
---|---|
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 Loading... | |
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 else: | |
792 # On svn < 1.7, the "--internal-diff" flag doesn't exist. Using | |
793 # --diff-cmd=diff doesn't always work, since e.g. Windows cmd users may | |
794 # not have a "diff" executable in their path at all. So we use an empty | |
795 # temporary directory as the config directory, which bypasses any user | |
796 # settings for the diff-cmd. | |
797 bogus_dir = tempfile.mkdtemp() | |
798 try: | |
799 return SVN._GenerateDiffInternal(filenames, cwd, full_move, revision, | |
800 ["diff", "--config_dir", bogus_dir]) | |
wtc
2013/04/20 01:16:41
This change breaks the gcl command:
$ gcl chang
| |
801 finally: | |
802 gclient_utils.RemoveDirectory(bogus_dir) | |
803 | |
804 @staticmethod | |
805 def _GenerateDiffInternal(filenames, cwd, full_move, revision, diff_command): | |
784 root = os.path.normcase(os.path.join(cwd, '')) | 806 root = os.path.normcase(os.path.join(cwd, '')) |
785 def RelativePath(path, root): | 807 def RelativePath(path, root): |
786 """We must use relative paths.""" | 808 """We must use relative paths.""" |
787 if os.path.normcase(path).startswith(root): | 809 if os.path.normcase(path).startswith(root): |
788 return path[len(root):] | 810 return path[len(root):] |
789 return path | 811 return path |
790 # If the user specified a custom diff command in their svn config file, | 812 # Cleanup filenames |
791 # then it'll be used when we do svn diff, which we don't want to happen | 813 filenames = [RelativePath(f, root) for f in filenames] |
792 # since we want the unified diff. Using --diff-cmd=diff doesn't always | 814 # Get information about the modified items (files and directories) |
793 # work, since e.g. Windows cmd users may not have a "diff" executable in | 815 data = dict((f, SVN.CaptureLocalInfo([f], root)) for f in filenames) |
794 # their path at all. So we use an empty temporary directory as the config | 816 diffs = [] |
795 # directory, which gets around these problems. | 817 if full_move: |
796 bogus_dir = tempfile.mkdtemp() | 818 # Eliminate modified files inside moved/copied directory. |
797 command = ['diff', '--config-dir', bogus_dir] | 819 for (filename, info) in data.iteritems(): |
798 try: | 820 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory": |
799 # Cleanup filenames | 821 # Remove files inside the directory. |
800 filenames = [RelativePath(f, root) for f in filenames] | 822 filenames = [f for f in filenames |
801 # Get information about the modified items (files and directories) | 823 if not f.startswith(filename + os.path.sep)] |
802 data = dict((f, SVN.CaptureLocalInfo([f], root)) for f in filenames) | 824 for filename in data.keys(): |
803 diffs = [] | 825 if not filename in filenames: |
804 if full_move: | 826 # Remove filtered out items. |
805 # Eliminate modified files inside moved/copied directory. | 827 del data[filename] |
806 for (filename, info) in data.iteritems(): | 828 else: |
807 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory": | 829 metaheaders = [] |
808 # Remove files inside the directory. | 830 for (filename, info) in data.iteritems(): |
809 filenames = [f for f in filenames | 831 if SVN.IsMovedInfo(info): |
810 if not f.startswith(filename + os.path.sep)] | 832 # for now, the most common case is a head copy, |
811 for filename in data.keys(): | 833 # so let's just encode that as a straight up cp. |
812 if not filename in filenames: | 834 srcurl = info.get('Copied From URL') |
813 # Remove filtered out items. | 835 file_root = info.get('Repository Root') |
814 del data[filename] | 836 rev = int(info.get('Copied From Rev')) |
815 else: | 837 assert srcurl.startswith(file_root) |
816 metaheaders = [] | 838 src = srcurl[len(file_root)+1:] |
817 for (filename, info) in data.iteritems(): | 839 try: |
818 if SVN.IsMovedInfo(info): | 840 srcinfo = SVN.CaptureRemoteInfo(srcurl) |
819 # for now, the most common case is a head copy, | 841 except subprocess2.CalledProcessError, e: |
820 # so let's just encode that as a straight up cp. | 842 if not 'Not a valid URL' in e.stderr: |
821 srcurl = info.get('Copied From URL') | 843 raise |
822 file_root = info.get('Repository Root') | 844 # Assume the file was deleted. No idea how to figure out at which |
823 rev = int(info.get('Copied From Rev')) | 845 # revision the file was deleted. |
824 assert srcurl.startswith(file_root) | 846 srcinfo = {'Revision': rev} |
825 src = srcurl[len(file_root)+1:] | 847 if (srcinfo.get('Revision') != rev and |
826 try: | 848 SVN.Capture(diff_command + ['-r', '%d:head' % rev, srcurl], cwd)): |
827 srcinfo = SVN.CaptureRemoteInfo(srcurl) | 849 metaheaders.append("#$ svn cp -r %d %s %s " |
828 except subprocess2.CalledProcessError, e: | 850 "### WARNING: note non-trunk copy\n" % |
829 if not 'Not a valid URL' in e.stderr: | 851 (rev, src, filename)) |
830 raise | 852 else: |
831 # Assume the file was deleted. No idea how to figure out at which | 853 metaheaders.append("#$ cp %s %s\n" % (src, |
832 # revision the file was deleted. | 854 filename)) |
833 srcinfo = {'Revision': rev} | 855 if metaheaders: |
834 if (srcinfo.get('Revision') != rev and | 856 diffs.append("### BEGIN SVN COPY METADATA\n") |
835 SVN.Capture(command + ['-r', '%d:head' % rev, srcurl], cwd)): | 857 diffs.extend(metaheaders) |
836 metaheaders.append("#$ svn cp -r %d %s %s " | 858 diffs.append("### END SVN COPY METADATA\n") |
837 "### WARNING: note non-trunk copy\n" % | 859 # Now ready to do the actual diff. |
838 (rev, src, filename)) | 860 for filename in sorted(data): |
839 else: | 861 diffs.append(SVN._DiffItemInternal( |
840 metaheaders.append("#$ cp %s %s\n" % (src, | 862 filename, cwd, data[filename], diff_command, full_move, revision)) |
841 filename)) | 863 # Use StringIO since it can be messy when diffing a directory move with |
842 | 864 # full_move=True. |
843 if metaheaders: | 865 buf = cStringIO.StringIO() |
844 diffs.append("### BEGIN SVN COPY METADATA\n") | 866 for d in filter(None, diffs): |
845 diffs.extend(metaheaders) | 867 buf.write(d) |
846 diffs.append("### END SVN COPY METADATA\n") | 868 result = buf.getvalue() |
847 # Now ready to do the actual diff. | 869 buf.close() |
848 for filename in sorted(data): | 870 return result |
849 diffs.append(SVN._DiffItemInternal( | |
850 filename, cwd, data[filename], command, full_move, revision)) | |
851 # Use StringIO since it can be messy when diffing a directory move with | |
852 # full_move=True. | |
853 buf = cStringIO.StringIO() | |
854 for d in filter(None, diffs): | |
855 buf.write(d) | |
856 result = buf.getvalue() | |
857 buf.close() | |
858 return result | |
859 finally: | |
860 gclient_utils.RemoveDirectory(bogus_dir) | |
861 | 871 |
862 @staticmethod | 872 @staticmethod |
863 def _DiffItemInternal(filename, cwd, info, diff_command, full_move, revision): | 873 def _DiffItemInternal(filename, cwd, info, diff_command, full_move, revision): |
864 """Grabs the diff data.""" | 874 """Grabs the diff data.""" |
865 command = diff_command + [filename] | 875 command = diff_command + [filename] |
866 if revision: | 876 if revision: |
867 command.extend(['--revision', revision]) | 877 command.extend(['--revision', revision]) |
868 data = None | 878 data = None |
869 if SVN.IsMovedInfo(info): | 879 if SVN.IsMovedInfo(info): |
870 if full_move: | 880 if full_move: |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1068 # revert, like for properties. | 1078 # revert, like for properties. |
1069 if not os.path.isdir(cwd): | 1079 if not os.path.isdir(cwd): |
1070 # '.' was deleted. It's not worth continuing. | 1080 # '.' was deleted. It's not worth continuing. |
1071 return | 1081 return |
1072 try: | 1082 try: |
1073 SVN.Capture(['revert', file_status[1]], cwd=cwd) | 1083 SVN.Capture(['revert', file_status[1]], cwd=cwd) |
1074 except subprocess2.CalledProcessError: | 1084 except subprocess2.CalledProcessError: |
1075 if not os.path.exists(file_path): | 1085 if not os.path.exists(file_path): |
1076 continue | 1086 continue |
1077 raise | 1087 raise |
OLD | NEW |