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 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
783 assert isinstance(filenames, (list, tuple)) | 783 assert isinstance(filenames, (list, tuple)) |
784 root = os.path.normcase(os.path.join(cwd, '')) | 784 root = os.path.normcase(os.path.join(cwd, '')) |
785 def RelativePath(path, root): | 785 def RelativePath(path, root): |
786 """We must use relative paths.""" | 786 """We must use relative paths.""" |
787 if os.path.normcase(path).startswith(root): | 787 if os.path.normcase(path).startswith(root): |
788 return path[len(root):] | 788 return path[len(root):] |
789 return path | 789 return path |
790 # If the user specified a custom diff command in their svn config file, | 790 # If the user specified a custom diff command in their svn config file, |
791 # then it'll be used when we do svn diff, which we don't want to happen | 791 # then it'll be used when we do svn diff, which we don't want to happen |
792 # since we want the unified diff. Using --diff-cmd=diff doesn't always | 792 # since we want the unified diff. Using --diff-cmd=diff doesn't always |
793 # work, since e.g. Windows cmd users may not have a "diff" executable in | 793 # work, since they can have another diff executable in their path that |
794 # their path at all. So we use an empty temporary directory as the config | 794 # gives different line endings. So we use a bogus temp directory as the |
795 # directory, which gets around these problems. | 795 # config directory, which gets around these problems. |
796 bogus_dir = tempfile.mkdtemp() | 796 bogus_dir = tempfile.mkdtemp() |
797 command = ['diff', '--config-dir', bogus_dir] | |
798 try: | 797 try: |
799 # Cleanup filenames | 798 # Cleanup filenames |
800 filenames = [RelativePath(f, root) for f in filenames] | 799 filenames = [RelativePath(f, root) for f in filenames] |
801 # Get information about the modified items (files and directories) | 800 # Get information about the modified items (files and directories) |
802 data = dict((f, SVN.CaptureLocalInfo([f], root)) for f in filenames) | 801 data = dict([(f, SVN.CaptureLocalInfo([f], root)) for f in filenames]) |
803 diffs = [] | 802 diffs = [] |
804 if full_move: | 803 if full_move: |
805 # Eliminate modified files inside moved/copied directory. | 804 # Eliminate modified files inside moved/copied directory. |
806 for (filename, info) in data.iteritems(): | 805 for (filename, info) in data.iteritems(): |
807 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory": | 806 if SVN.IsMovedInfo(info) and info.get("Node Kind") == "directory": |
808 # Remove files inside the directory. | 807 # Remove files inside the directory. |
809 filenames = [f for f in filenames | 808 filenames = [f for f in filenames |
810 if not f.startswith(filename + os.path.sep)] | 809 if not f.startswith(filename + os.path.sep)] |
811 for filename in data.keys(): | 810 for filename in data.keys(): |
812 if not filename in filenames: | 811 if not filename in filenames: |
(...skipping 12 matching lines...) Expand all Loading... |
825 src = srcurl[len(file_root)+1:] | 824 src = srcurl[len(file_root)+1:] |
826 try: | 825 try: |
827 srcinfo = SVN.CaptureRemoteInfo(srcurl) | 826 srcinfo = SVN.CaptureRemoteInfo(srcurl) |
828 except subprocess2.CalledProcessError, e: | 827 except subprocess2.CalledProcessError, e: |
829 if not 'Not a valid URL' in e.stderr: | 828 if not 'Not a valid URL' in e.stderr: |
830 raise | 829 raise |
831 # Assume the file was deleted. No idea how to figure out at which | 830 # Assume the file was deleted. No idea how to figure out at which |
832 # revision the file was deleted. | 831 # revision the file was deleted. |
833 srcinfo = {'Revision': rev} | 832 srcinfo = {'Revision': rev} |
834 if (srcinfo.get('Revision') != rev and | 833 if (srcinfo.get('Revision') != rev and |
835 SVN.Capture(command + ['-r', '%d:head' % rev, srcurl], cwd)): | 834 SVN.Capture(['diff', '-r', '%d:head' % rev, srcurl], cwd)): |
836 metaheaders.append("#$ svn cp -r %d %s %s " | 835 metaheaders.append("#$ svn cp -r %d %s %s " |
837 "### WARNING: note non-trunk copy\n" % | 836 "### WARNING: note non-trunk copy\n" % |
838 (rev, src, filename)) | 837 (rev, src, filename)) |
839 else: | 838 else: |
840 metaheaders.append("#$ cp %s %s\n" % (src, | 839 metaheaders.append("#$ cp %s %s\n" % (src, |
841 filename)) | 840 filename)) |
842 | 841 |
843 if metaheaders: | 842 if metaheaders: |
844 diffs.append("### BEGIN SVN COPY METADATA\n") | 843 diffs.append("### BEGIN SVN COPY METADATA\n") |
845 diffs.extend(metaheaders) | 844 diffs.extend(metaheaders) |
846 diffs.append("### END SVN COPY METADATA\n") | 845 diffs.append("### END SVN COPY METADATA\n") |
847 # Now ready to do the actual diff. | 846 # Now ready to do the actual diff. |
848 for filename in sorted(data): | 847 for filename in sorted(data.iterkeys()): |
849 diffs.append(SVN._DiffItemInternal( | 848 diffs.append(SVN._DiffItemInternal( |
850 filename, cwd, data[filename], command, full_move, revision)) | 849 filename, cwd, data[filename], bogus_dir, full_move, revision)) |
851 # Use StringIO since it can be messy when diffing a directory move with | 850 # Use StringIO since it can be messy when diffing a directory move with |
852 # full_move=True. | 851 # full_move=True. |
853 buf = cStringIO.StringIO() | 852 buf = cStringIO.StringIO() |
854 for d in filter(None, diffs): | 853 for d in filter(None, diffs): |
855 buf.write(d) | 854 buf.write(d) |
856 result = buf.getvalue() | 855 result = buf.getvalue() |
857 buf.close() | 856 buf.close() |
858 return result | 857 return result |
859 finally: | 858 finally: |
860 gclient_utils.RemoveDirectory(bogus_dir) | 859 gclient_utils.RemoveDirectory(bogus_dir) |
861 | 860 |
862 @staticmethod | 861 @staticmethod |
863 def _DiffItemInternal(filename, cwd, info, diff_command, full_move, revision): | 862 def _DiffItemInternal(filename, cwd, info, bogus_dir, full_move, revision): |
864 """Grabs the diff data.""" | 863 """Grabs the diff data.""" |
865 command = diff_command + [filename] | 864 command = ["diff", "--config-dir", bogus_dir, filename] |
866 if revision: | 865 if revision: |
867 command.extend(['--revision', revision]) | 866 command.extend(['--revision', revision]) |
868 data = None | 867 data = None |
869 if SVN.IsMovedInfo(info): | 868 if SVN.IsMovedInfo(info): |
870 if full_move: | 869 if full_move: |
871 if info.get("Node Kind") == "directory": | 870 if info.get("Node Kind") == "directory": |
872 # Things become tricky here. It's a directory copy/move. We need to | 871 # Things become tricky here. It's a directory copy/move. We need to |
873 # diff all the files inside it. | 872 # diff all the files inside it. |
874 # This will put a lot of pressure on the heap. This is why StringIO | 873 # This will put a lot of pressure on the heap. This is why StringIO |
875 # is used and converted back into a string at the end. The reason to | 874 # 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 Loading... |
1068 # revert, like for properties. | 1067 # revert, like for properties. |
1069 if not os.path.isdir(cwd): | 1068 if not os.path.isdir(cwd): |
1070 # '.' was deleted. It's not worth continuing. | 1069 # '.' was deleted. It's not worth continuing. |
1071 return | 1070 return |
1072 try: | 1071 try: |
1073 SVN.Capture(['revert', file_status[1]], cwd=cwd) | 1072 SVN.Capture(['revert', file_status[1]], cwd=cwd) |
1074 except subprocess2.CalledProcessError: | 1073 except subprocess2.CalledProcessError: |
1075 if not os.path.exists(file_path): | 1074 if not os.path.exists(file_path): |
1076 continue | 1075 continue |
1077 raise | 1076 raise |
OLD | NEW |