| OLD | NEW |
| 1 # Copyright (C) 2009 Google Inc. All rights reserved. | 1 # Copyright (C) 2009 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | 28 |
| 29 """WebKit's Python module for interacting with patches.""" | 29 """WebKit's Python module for interacting with patches.""" |
| 30 | 30 |
| 31 import logging | 31 import logging |
| 32 import re | 32 import re |
| 33 | 33 |
| 34 _log = logging.getLogger(__name__) | 34 _log = logging.getLogger(__name__) |
| 35 | 35 |
| 36 conversion_patterns = ( | 36 INDEX_PATTERN = re.compile(r'^diff --git \w/(.+) \w/(?P<FilePath>.+)') |
| 37 (re.compile(r"^diff --git \w/(.+) \w/(?P<FilePath>.+)"), lambda matched: "In
dex: " + matched.group('FilePath') + "\n"), | 37 LINES_CHANGED_PATTERN = re.compile(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<New
StartLine>\d+)(,\d+)? @@") |
| 38 (re.compile(r"^new file.*"), lambda matched: "\n"), | |
| 39 (re.compile(r"^index (([0-9a-f]{7}\.\.[0-9a-f]{7})|([0-9a-f]{40}\.\.[0-9a-f]
{40})) [0-9]{6}"), | |
| 40 lambda matched: ("=" * 67) + "\n"), | |
| 41 (re.compile(r"^--- \w/(?P<FilePath>.+)"), lambda matched: "--- " + matched.g
roup('FilePath') + "\n"), | |
| 42 (re.compile(r"^\+\+\+ \w/(?P<FilePath>.+)"), lambda matched: "+++ " + matche
d.group('FilePath') + "\n"), | |
| 43 ) | |
| 44 | 38 |
| 45 index_pattern = re.compile(r"^Index: (?P<FilePath>.+)") | |
| 46 lines_changed_pattern = re.compile(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<New
StartLine>\d+)(,\d+)? @@") | |
| 47 diff_git_pattern = re.compile(r"^diff --git \w/") | |
| 48 | |
| 49 | |
| 50 def git_diff_to_svn_diff(line): | |
| 51 """Converts a git formatted diff line to a svn formatted line. | |
| 52 | |
| 53 Args: | |
| 54 line: A string representing a line of the diff. | |
| 55 """ | |
| 56 for pattern, conversion in conversion_patterns: | |
| 57 matched = pattern.match(line) | |
| 58 if matched: | |
| 59 return conversion(matched) | |
| 60 return line | |
| 61 | |
| 62 | |
| 63 # This function exists so we can unittest get_diff_converter function | |
| 64 def svn_diff_to_svn_diff(line): | |
| 65 return line | |
| 66 | |
| 67 | |
| 68 def get_diff_converter(lines): | |
| 69 """Gets a converter function of diff lines. | |
| 70 | |
| 71 Args: | |
| 72 lines: The lines of a diff file. | |
| 73 If this line is git formatted, we'll return a | |
| 74 converter from git to SVN. | |
| 75 """ | |
| 76 for i, line in enumerate(lines[:-1]): | |
| 77 # Stop when we find the first patch | |
| 78 if line[:3] == "+++" and lines[i + 1] == "---": | |
| 79 break | |
| 80 if diff_git_pattern.match(line): | |
| 81 return git_diff_to_svn_diff | |
| 82 return svn_diff_to_svn_diff | |
| 83 | 39 |
| 84 _INITIAL_STATE = 1 | 40 _INITIAL_STATE = 1 |
| 85 _DECLARED_FILE_PATH = 2 | 41 _DECLARED_FILE_PATH = 2 |
| 86 _PROCESSING_CHUNK = 3 | 42 _PROCESSING_CHUNK = 3 |
| 87 | 43 |
| 88 | 44 |
| 89 class DiffFile(object): | 45 class DiffFile(object): |
| 90 """Contains the information for one file in a patch. | 46 """Contains the information for one file in a patch. |
| 91 | 47 |
| 92 The field "lines" is a list which contains tuples in this format: | 48 The field "lines" is a list which contains tuples in this format: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 """ | 89 """ |
| 134 self.files = self._parse_into_diff_files(diff_input) | 90 self.files = self._parse_into_diff_files(diff_input) |
| 135 | 91 |
| 136 # FIXME: This function is way too long and needs to be broken up. | 92 # FIXME: This function is way too long and needs to be broken up. |
| 137 def _parse_into_diff_files(self, diff_input): | 93 def _parse_into_diff_files(self, diff_input): |
| 138 files = {} | 94 files = {} |
| 139 state = _INITIAL_STATE | 95 state = _INITIAL_STATE |
| 140 current_file = None | 96 current_file = None |
| 141 old_diff_line = None | 97 old_diff_line = None |
| 142 new_diff_line = None | 98 new_diff_line = None |
| 143 transform_line = get_diff_converter(diff_input) | |
| 144 for line in diff_input: | 99 for line in diff_input: |
| 145 line = line.rstrip("\n") | 100 line = line.rstrip('\n') |
| 146 line = transform_line(line) | |
| 147 | 101 |
| 148 file_declaration = index_pattern.match(line) | 102 file_declaration = INDEX_PATTERN.match(line) |
| 149 if file_declaration: | 103 if file_declaration: |
| 150 filename = file_declaration.group('FilePath') | 104 filename = file_declaration.group('FilePath') |
| 151 current_file = DiffFile(filename) | 105 current_file = DiffFile(filename) |
| 152 files[filename] = current_file | 106 files[filename] = current_file |
| 153 state = _DECLARED_FILE_PATH | 107 state = _DECLARED_FILE_PATH |
| 154 continue | 108 continue |
| 155 | 109 |
| 156 lines_changed = lines_changed_pattern.match(line) | 110 lines_changed = LINES_CHANGED_PATTERN.match(line) |
| 157 if lines_changed: | 111 if lines_changed: |
| 158 if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK: | 112 if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK: |
| 159 _log.error('Unexpected line change without file path declara
tion: %r', line) | 113 _log.error('Unexpected line change without file path declara
tion: %r', line) |
| 160 old_diff_line = int(lines_changed.group('OldStartLine')) | 114 old_diff_line = int(lines_changed.group('OldStartLine')) |
| 161 new_diff_line = int(lines_changed.group('NewStartLine')) | 115 new_diff_line = int(lines_changed.group('NewStartLine')) |
| 162 state = _PROCESSING_CHUNK | 116 state = _PROCESSING_CHUNK |
| 163 continue | 117 continue |
| 164 | 118 |
| 165 if state == _PROCESSING_CHUNK: | 119 if state == _PROCESSING_CHUNK: |
| 166 if line.startswith('+'): | 120 if line.startswith('+'): |
| 167 current_file.add_new_line(new_diff_line, line[1:]) | 121 current_file.add_new_line(new_diff_line, line[1:]) |
| 168 new_diff_line += 1 | 122 new_diff_line += 1 |
| 169 elif line.startswith('-'): | 123 elif line.startswith('-'): |
| 170 current_file.add_deleted_line(old_diff_line, line[1:]) | 124 current_file.add_deleted_line(old_diff_line, line[1:]) |
| 171 old_diff_line += 1 | 125 old_diff_line += 1 |
| 172 elif line.startswith(' '): | 126 elif line.startswith(' '): |
| 173 current_file.add_unchanged_line(old_diff_line, new_diff_line
, line[1:]) | 127 current_file.add_unchanged_line(old_diff_line, new_diff_line
, line[1:]) |
| 174 old_diff_line += 1 | 128 old_diff_line += 1 |
| 175 new_diff_line += 1 | 129 new_diff_line += 1 |
| 176 elif line == '\\ No newline at end of file': | 130 elif line == '\\ No newline at end of file': |
| 177 # Nothing to do. We may still have some added lines. | 131 # Nothing to do. We may still have some added lines. |
| 178 pass | 132 pass |
| 179 else: | 133 else: |
| 180 _log.error('Unexpected diff format when parsing a chunk: %r'
, line) | 134 _log.error('Unexpected diff format when parsing a chunk: %r'
, line) |
| 181 return files | 135 return files |
| OLD | NEW |