Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Side by Side Diff: patch.py

Issue 10894036: Fix hunk handling for 'default hunk header values'. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Add verification code for the number of commas Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | testing_support/patches_data.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # coding=utf8 1 # coding=utf8
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Utility functions to handle patches.""" 5 """Utility functions to handle patches."""
6 6
7 import posixpath 7 import posixpath
8 import os 8 import os
9 import re 9 import re
10 10
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 """Parsed hunk data container.""" 128 """Parsed hunk data container."""
129 129
130 def __init__(self, start_src, lines_src, start_dst, lines_dst): 130 def __init__(self, start_src, lines_src, start_dst, lines_dst):
131 self.start_src = start_src 131 self.start_src = start_src
132 self.lines_src = lines_src 132 self.lines_src = lines_src
133 self.start_dst = start_dst 133 self.start_dst = start_dst
134 self.lines_dst = lines_dst 134 self.lines_dst = lines_dst
135 self.variation = self.lines_dst - self.lines_src 135 self.variation = self.lines_dst - self.lines_src
136 self.text = [] 136 self.text = []
137 137
138 def __repr__(self):
139 return '%s<(%d, %d) to (%d, %d)>' % (
140 self.__class__.__name__,
141 self.start_src, self.lines_src, self.start_dst, self.lines_dst)
142
138 143
139 class FilePatchDiff(FilePatchBase): 144 class FilePatchDiff(FilePatchBase):
140 """Patch for a single file.""" 145 """Patch for a single file."""
141 146
142 def __init__(self, filename, diff, svn_properties): 147 def __init__(self, filename, diff, svn_properties):
143 super(FilePatchDiff, self).__init__(filename) 148 super(FilePatchDiff, self).__init__(filename)
144 if not diff: 149 if not diff:
145 self._fail('File doesn\'t have a diff.') 150 self._fail('File doesn\'t have a diff.')
146 self.diff_header, self.diff_hunks = self._split_header(diff) 151 self.diff_header, self.diff_hunks = self._split_header(diff)
147 self.svn_properties = svn_properties or [] 152 self.svn_properties = svn_properties or []
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 def _split_hunks(self): 233 def _split_hunks(self):
229 """Splits the hunks and does verification.""" 234 """Splits the hunks and does verification."""
230 hunks = [] 235 hunks = []
231 for line in self.diff_hunks.splitlines(True): 236 for line in self.diff_hunks.splitlines(True):
232 if line.startswith('@@'): 237 if line.startswith('@@'):
233 match = re.match(r'^@@ -([\d,]+) \+([\d,]+) @@.*$', line) 238 match = re.match(r'^@@ -([\d,]+) \+([\d,]+) @@.*$', line)
234 # File add will result in "-0,0 +1" but file deletion will result in 239 # File add will result in "-0,0 +1" but file deletion will result in
235 # "-1,N +0,0" where N is the number of lines deleted. That's from diff 240 # "-1,N +0,0" where N is the number of lines deleted. That's from diff
236 # and svn diff. git diff doesn't exhibit this behavior. 241 # and svn diff. git diff doesn't exhibit this behavior.
237 # svn diff for a single line file rewrite "@@ -1 +1 @@". Fun. 242 # svn diff for a single line file rewrite "@@ -1 +1 @@". Fun.
243 # "@@ -1 +1,N @@" is also valid where N is the length of the new file.
238 if not match: 244 if not match:
239 self._fail('Hunk header is unparsable') 245 self._fail('Hunk header is unparsable')
240 if ',' in match.group(1): 246 count = match.group(1).count(',')
247 if not count:
248 start_src = int(match.group(1))
249 lines_src = 1
250 elif count == 1:
241 start_src, lines_src = map(int, match.group(1).split(',', 1)) 251 start_src, lines_src = map(int, match.group(1).split(',', 1))
242 else: 252 else:
243 start_src = int(match.group(1)) 253 self._fail('Hunk header is malformed')
244 lines_src = 0 254
245 if ',' in match.group(2): 255 count = match.group(2).count(',')
256 if not count:
257 start_dst = int(match.group(2))
258 lines_dst = 1
259 elif count == 1:
246 start_dst, lines_dst = map(int, match.group(2).split(',', 1)) 260 start_dst, lines_dst = map(int, match.group(2).split(',', 1))
247 else: 261 else:
248 start_dst = int(match.group(2)) 262 self._fail('Hunk header is malformed')
249 lines_dst = 0
250 new_hunk = Hunk(start_src, lines_src, start_dst, lines_dst) 263 new_hunk = Hunk(start_src, lines_src, start_dst, lines_dst)
251 if hunks: 264 if hunks:
252 if new_hunk.start_src <= hunks[-1].start_src: 265 if new_hunk.start_src <= hunks[-1].start_src:
253 self._fail('Hunks source lines are not ordered') 266 self._fail('Hunks source lines are not ordered')
254 if new_hunk.start_dst <= hunks[-1].start_dst: 267 if new_hunk.start_dst <= hunks[-1].start_dst:
255 self._fail('Hunks destination lines are not ordered') 268 self._fail('Hunks destination lines are not ordered')
256 hunks.append(new_hunk) 269 hunks.append(new_hunk)
257 continue 270 continue
258 hunks[-1].text.append(line) 271 hunks[-1].text.append(line)
259 272
260 if len(hunks) == 1: 273 if len(hunks) == 1:
261 if hunks[0].start_src == 0 and hunks[0].lines_src == 0: 274 if hunks[0].start_src == 0 and hunks[0].lines_src == 0:
262 self.is_new = True 275 self.is_new = True
263 if hunks[0].start_dst == 0 and hunks[0].lines_dst == 0: 276 if hunks[0].start_dst == 0 and hunks[0].lines_dst == 0:
264 self.is_delete = True 277 self.is_delete = True
265 278
266 if self.is_new and self.is_delete: 279 if self.is_new and self.is_delete:
267 self._fail('Hunk header is all 0') 280 self._fail('Hunk header is all 0')
268 281
269 if not self.is_new and not self.is_delete: 282 if not self.is_new and not self.is_delete:
270 for hunk in hunks: 283 for hunk in hunks:
271 variation = ( 284 variation = (
272 len([1 for i in hunk.text if i.startswith('+')]) - 285 len([1 for i in hunk.text if i.startswith('+')]) -
273 len([1 for i in hunk.text if i.startswith('-')])) 286 len([1 for i in hunk.text if i.startswith('-')]))
274 if variation != hunk.variation: 287 if variation != hunk.variation:
275 self._fail( 288 self._fail(
276 'Hunk header is incorrect: %d vs %d' % ( 289 'Hunk header is incorrect: %d vs %d; %r' % (
277 variation, hunk.variation)) 290 variation, hunk.variation, hunk))
278 if not hunk.start_src: 291 if not hunk.start_src:
279 self._fail( 292 self._fail(
280 'Hunk header start line is incorrect: %d' % hunk.start_src) 293 'Hunk header start line is incorrect: %d' % hunk.start_src)
281 if not hunk.start_dst: 294 if not hunk.start_dst:
282 self._fail( 295 self._fail(
283 'Hunk header start line is incorrect: %d' % hunk.start_dst) 296 'Hunk header start line is incorrect: %d' % hunk.start_dst)
284 hunk.start_src -= 1 297 hunk.start_src -= 1
285 hunk.start_dst -= 1 298 hunk.start_dst -= 1
286 if self.is_new and hunks: 299 if self.is_new and hunks:
287 hunks[0].start_dst -= 1 300 hunks[0].start_dst -= 1
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 def __iter__(self): 518 def __iter__(self):
506 for patch in self.patches: 519 for patch in self.patches:
507 yield patch 520 yield patch
508 521
509 def __getitem__(self, key): 522 def __getitem__(self, key):
510 return self.patches[key] 523 return self.patches[key]
511 524
512 @property 525 @property
513 def filenames(self): 526 def filenames(self):
514 return [p.filename for p in self.patches] 527 return [p.filename for p in self.patches]
OLDNEW
« no previous file with comments | « no previous file | testing_support/patches_data.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698