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 = ( |
| 37 (re.compile("^diff --git \w/(.+) \w/(?P<FilePath>.+)"), lambda matched: "Ind
ex: " + matched.group('FilePath') + "\n"), |
| 38 (re.compile("^new file.*"), lambda matched: "\n"), |
| 39 (re.compile("^index (([0-9a-f]{7}\.\.[0-9a-f]{7})|([0-9a-f]{40}\.\.[0-9a-f]{
40})) [0-9]{6}"), lambda matched: ("=" * 67) + "\n"), |
| 40 (re.compile("^--- \w/(?P<FilePath>.+)"), lambda matched: "--- " + matched.gr
oup('FilePath') + "\n"), |
| 41 (re.compile("^\+\+\+ \w/(?P<FilePath>.+)"), lambda matched: "+++ " + matched
.group('FilePath') + "\n"), |
| 42 ) |
36 | 43 |
37 # FIXME: This is broken. We should compile our regexps up-front | 44 index_pattern = re.compile(r"^Index: (?P<FilePath>.+)") |
38 # instead of using a custom cache. | 45 lines_changed_pattern = re.compile(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<New
StartLine>\d+)(,\d+)? @@") |
39 _regexp_compile_cache = {} | 46 diff_git_pattern = re.compile(r"^diff --git \w/") |
40 | 47 |
41 | 48 |
42 # FIXME: This function should be removed. | |
43 def match(pattern, string): | |
44 """Matches the string with the pattern, caching the compiled regexp.""" | |
45 if not pattern in _regexp_compile_cache: | |
46 _regexp_compile_cache[pattern] = re.compile(pattern) | |
47 return _regexp_compile_cache[pattern].match(string) | |
48 | |
49 | |
50 # FIXME: This belongs on DiffParser (e.g. as to_svn_diff()). | |
51 def git_diff_to_svn_diff(line): | 49 def git_diff_to_svn_diff(line): |
52 """Converts a git formatted diff line to a svn formatted line. | 50 """Converts a git formatted diff line to a svn formatted line. |
53 | 51 |
54 Args: | 52 Args: |
55 line: A string representing a line of the diff. | 53 line: A string representing a line of the diff. |
56 """ | 54 """ |
57 # FIXME: This list should be a class member on DiffParser. | |
58 # These regexp patterns should be compiled once instead of every time. | |
59 conversion_patterns = (("^diff --git \w/(.+) \w/(?P<FilePath>.+)", lambda ma
tched: "Index: " + matched.group('FilePath') + "\n"), | |
60 ("^new file.*", lambda matched: "\n"), | |
61 ("^index (([0-9a-f]{7}\.\.[0-9a-f]{7})|([0-9a-f]{40}\
.\.[0-9a-f]{40})) [0-9]{6}", lambda matched: "==================================
=================================\n"), | |
62 ("^--- \w/(?P<FilePath>.+)", lambda matched: "--- " +
matched.group('FilePath') + "\n"), | |
63 ("^\+\+\+ \w/(?P<FilePath>.+)", lambda matched: "+++
" + matched.group('FilePath') + "\n")) | |
64 | |
65 for pattern, conversion in conversion_patterns: | 55 for pattern, conversion in conversion_patterns: |
66 matched = match(pattern, line) | 56 matched = pattern.match(line) |
67 if matched: | 57 if matched: |
68 return conversion(matched) | 58 return conversion(matched) |
69 return line | 59 return line |
70 | 60 |
71 | 61 |
72 # This function exists so we can unittest get_diff_converter function | 62 # This function exists so we can unittest get_diff_converter function |
73 def svn_diff_to_svn_diff(line): | 63 def svn_diff_to_svn_diff(line): |
74 return line | 64 return line |
75 | 65 |
76 | 66 |
77 # FIXME: This method belongs on DiffParser | |
78 def get_diff_converter(lines): | 67 def get_diff_converter(lines): |
79 """Gets a converter function of diff lines. | 68 """Gets a converter function of diff lines. |
80 | 69 |
81 Args: | 70 Args: |
82 lines: The lines of a diff file. | 71 lines: The lines of a diff file. |
83 If this line is git formatted, we'll return a | 72 If this line is git formatted, we'll return a |
84 converter from git to SVN. | 73 converter from git to SVN. |
85 """ | 74 """ |
86 for i, line in enumerate(lines[:-1]): | 75 for i, line in enumerate(lines[:-1]): |
87 # Stop when we find the first patch | 76 # Stop when we find the first patch |
88 if line[:3] == "+++" and lines[i + 1] == "---": | 77 if line[:3] == "+++" and lines[i + 1] == "---": |
89 break | 78 break |
90 if match(r"^diff --git \w/", line): | 79 if diff_git_pattern.match(line): |
91 return git_diff_to_svn_diff | 80 return git_diff_to_svn_diff |
92 return svn_diff_to_svn_diff | 81 return svn_diff_to_svn_diff |
93 | 82 |
94 _INITIAL_STATE = 1 | 83 _INITIAL_STATE = 1 |
95 _DECLARED_FILE_PATH = 2 | 84 _DECLARED_FILE_PATH = 2 |
96 _PROCESSING_CHUNK = 3 | 85 _PROCESSING_CHUNK = 3 |
97 | 86 |
98 | 87 |
99 class DiffFile(object): | 88 class DiffFile(object): |
100 """Contains the information for one file in a patch. | 89 """Contains the information for one file in a patch. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 files = {} | 137 files = {} |
149 state = _INITIAL_STATE | 138 state = _INITIAL_STATE |
150 current_file = None | 139 current_file = None |
151 old_diff_line = None | 140 old_diff_line = None |
152 new_diff_line = None | 141 new_diff_line = None |
153 transform_line = get_diff_converter(diff_input) | 142 transform_line = get_diff_converter(diff_input) |
154 for line in diff_input: | 143 for line in diff_input: |
155 line = line.rstrip("\n") | 144 line = line.rstrip("\n") |
156 line = transform_line(line) | 145 line = transform_line(line) |
157 | 146 |
158 file_declaration = match(r"^Index: (?P<FilePath>.+)", line) | 147 file_declaration = index_pattern.match(line) |
159 if file_declaration: | 148 if file_declaration: |
160 filename = file_declaration.group('FilePath') | 149 filename = file_declaration.group('FilePath') |
161 current_file = DiffFile(filename) | 150 current_file = DiffFile(filename) |
162 files[filename] = current_file | 151 files[filename] = current_file |
163 state = _DECLARED_FILE_PATH | 152 state = _DECLARED_FILE_PATH |
164 continue | 153 continue |
165 | 154 |
166 lines_changed = match(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<NewS
tartLine>\d+)(,\d+)? @@", line) | 155 lines_changed = lines_changed_pattern.match(line) |
167 if lines_changed: | 156 if lines_changed: |
168 if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK: | 157 if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK: |
169 _log.error('Unexpected line change without file path ' | 158 _log.error('Unexpected line change without file path ' |
170 'declaration: %r' % line) | 159 'declaration: %r' % line) |
171 old_diff_line = int(lines_changed.group('OldStartLine')) | 160 old_diff_line = int(lines_changed.group('OldStartLine')) |
172 new_diff_line = int(lines_changed.group('NewStartLine')) | 161 new_diff_line = int(lines_changed.group('NewStartLine')) |
173 state = _PROCESSING_CHUNK | 162 state = _PROCESSING_CHUNK |
174 continue | 163 continue |
175 | 164 |
176 if state == _PROCESSING_CHUNK: | 165 if state == _PROCESSING_CHUNK: |
177 if line.startswith('+'): | 166 if line.startswith('+'): |
178 current_file.add_new_line(new_diff_line, line[1:]) | 167 current_file.add_new_line(new_diff_line, line[1:]) |
179 new_diff_line += 1 | 168 new_diff_line += 1 |
180 elif line.startswith('-'): | 169 elif line.startswith('-'): |
181 current_file.add_deleted_line(old_diff_line, line[1:]) | 170 current_file.add_deleted_line(old_diff_line, line[1:]) |
182 old_diff_line += 1 | 171 old_diff_line += 1 |
183 elif line.startswith(' '): | 172 elif line.startswith(' '): |
184 current_file.add_unchanged_line(old_diff_line, new_diff_line
, line[1:]) | 173 current_file.add_unchanged_line(old_diff_line, new_diff_line
, line[1:]) |
185 old_diff_line += 1 | 174 old_diff_line += 1 |
186 new_diff_line += 1 | 175 new_diff_line += 1 |
187 elif line == '\\ No newline at end of file': | 176 elif line == '\\ No newline at end of file': |
188 # Nothing to do. We may still have some added lines. | 177 # Nothing to do. We may still have some added lines. |
189 pass | 178 pass |
190 else: | 179 else: |
191 _log.error('Unexpected diff format when parsing a ' | 180 _log.error('Unexpected diff format when parsing a ' |
192 'chunk: %r' % line) | 181 'chunk: %r' % line) |
193 return files | 182 return files |
OLD | NEW |