Index: patch.py |
diff --git a/patch.py b/patch.py |
index af18ee43e212583815d27d138d1fc426883eb663..cc86d343e011b1985dfb7c724b15ad06f1af91e2 100644 |
--- a/patch.py |
+++ b/patch.py |
@@ -1,8 +1,10 @@ |
+# coding=utf8 |
# Copyright (c) 2010 The Chromium Authors. All rights reserved. |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
"""Utility functions to handle patches.""" |
+import logging |
import re |
import subprocess2 |
@@ -29,3 +31,68 @@ def apply_patch(location, patch): |
cmd = ['patch', '-p0', '--forward', '--force'] |
subprocess2.check_call(cmd, stdin=patch, cwd=location) |
+ |
+def verify_patch(patch_data): |
+ """Verifies if a patch can be applied. |
+ |
+ Returns a string if the patch can't be applied explaining the issue. |
+ """ |
+ lines = patch_data.splitlines(False) |
+ svn_separator = ( |
+ '___________________________________________________________________') |
+ |
+ index = 0 |
+ |
+ def next_line(i): |
+ if index+i >= len(lines): |
+ return '' |
+ return lines[index+i] |
+ |
+ for index, line in enumerate(lines): |
+ if line == svn_separator: |
+ # Look for the next line. |
+ # TODO: If we ever hit non English patches, we need to |
+ # use something like re.match(ur'^\w+$', u'Modifié', re.UNICODE) |
+ m = re.match(r'^(\w+)\s*\:\s*svn\:([\w\-]+)$', next_line(1)) |
+ if not m: |
+ # The patch confused the script; |
+ continue |
+ prop = m.group(2) |
+ if prop in ('mergeinfo', 'executable', 'ignore'): |
+ # In practice, executable should be treated like eol-style, assuming we |
+ # lookup auto-props. |
+ return 'Can\'t apply svn property svn:%s' % prop |
+ elif prop in ('eol-style', 'mime-type'): |
+ # Silently ignore it, assume that the auto-props are ok. |
+ # TODO: Verify the auto-props would trigger. |
+ continue |
+ else: |
+ # Unknown property |
+ logging.error('Unknown property %s' % prop) |
+ continue |
+ m = re.match(r'^Index\:\s*(.+)$', line) |
+ if m: |
+ # We need to find --- on the next 3 lines otherwise discard the patch. |
+ if next_line(1).startswith('--- '): |
+ continue |
+ if not next_line(1): |
+ return 'Can\'t patch empty file (svn)' |
+ if next_line(2).startswith('--- '): |
+ continue |
+ if not next_line(2): |
+ return 'Can\'t patch empty file (svn)' |
+ if next_line(3).startswith('--- '): |
+ continue |
+ if not next_line(3): |
+ return 'Can\'t patch empty file (svn)' |
+ if next_line(4).startswith('--- '): |
+ # See testSupported3() for a real-world example. |
+ continue |
+ return 'Can\'t patch empty file (svn)' |
+ m = re.match(r'diff \-\-git (.*)$', line) |
+ if m: |
+ if not next_line(1): |
+ return 'Can\'t patch empty file (git)' |
+ if next_line(1).startswith('old mode '): |
+ return 'Unsupported git file mode change' |
+ return None |