comparison rhodecode/lib/diffs.py @ 2347:58bcaf1b2fe2 codereview

added stats of line changes and operation (A/M/D) into diffs lib
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 27 May 2012 23:28:22 +0200
parents 8fe7c1024719
children 0edbffa9e2e2
comparison
equal deleted inserted replaced
2346:8fe7c1024719 2347:58bcaf1b2fe2
169 self.__udiff, iterator_copy = tee(self.__udiff) 169 self.__udiff, iterator_copy = tee(self.__udiff)
170 return iterator_copy 170 return iterator_copy
171 171
172 def _extract_rev(self, line1, line2): 172 def _extract_rev(self, line1, line2):
173 """ 173 """
174 Extract the filename and revision hint from a line. 174 Extract the operation (A/M/D), filename and revision hint from a line.
175 """ 175 """
176 176
177 try: 177 try:
178 if line1.startswith('--- ') and line2.startswith('+++ '): 178 if line1.startswith('--- ') and line2.startswith('+++ '):
179 l1 = line1[4:].split(None, 1) 179 l1 = line1[4:].split(None, 1)
187 new_rev = l2[1] if len(l2) == 2 else 'new' 187 new_rev = l2[1] if len(l2) == 2 else 'new'
188 188
189 filename = (old_filename 189 filename = (old_filename
190 if old_filename != '/dev/null' else new_filename) 190 if old_filename != '/dev/null' else new_filename)
191 191
192 return filename, new_rev, old_rev 192 operation = 'D' if new_filename == '/dev/null' else None
193 if not operation:
194 operation = 'M' if old_filename != '/dev/null' else 'A'
195
196 return operation, filename, new_rev, old_rev
193 except (ValueError, IndexError): 197 except (ValueError, IndexError):
194 pass 198 pass
195 199
196 return None, None, None 200 return None, None, None, None
197 201
198 def _parse_gitdiff(self, diffiterator): 202 def _parse_gitdiff(self, diffiterator):
199 def line_decoder(l): 203 def line_decoder(l):
200 if l.startswith('+') and not l.startswith('+++'): 204 if l.startswith('+') and not l.startswith('+++'):
201 self.adds += 1 205 self.adds += 1
286 files = [] 290 files = []
287 try: 291 try:
288 line = lineiter.next() 292 line = lineiter.next()
289 # skip first context 293 # skip first context
290 skipfirst = True 294 skipfirst = True
295
291 while 1: 296 while 1:
292 # continue until we found the old file 297 # continue until we found the old file
293 if not line.startswith('--- '): 298 if not line.startswith('--- '):
294 line = lineiter.next() 299 line = lineiter.next()
295 continue 300 continue
296 301
297 chunks = [] 302 chunks = []
298 filename, old_rev, new_rev = \ 303 stats = [0, 0]
304 operation, filename, old_rev, new_rev = \
299 self._extract_rev(line, lineiter.next()) 305 self._extract_rev(line, lineiter.next())
300 files.append({ 306 files.append({
301 'filename': filename, 307 'filename': filename,
302 'old_revision': old_rev, 308 'old_revision': old_rev,
303 'new_revision': new_rev, 309 'new_revision': new_rev,
304 'chunks': chunks 310 'chunks': chunks,
311 'operation': operation,
312 'stats': stats,
305 }) 313 })
306 314
307 line = lineiter.next() 315 line = lineiter.next()
308 while line: 316 while line:
317
309 match = self._chunk_re.match(line) 318 match = self._chunk_re.match(line)
310 if not match: 319 if not match:
311 break 320 break
312 321
313 lines = [] 322 lines = []
344 if command in '#@': 353 if command in '#@':
345 continue 354 continue
346 elif command == '+': 355 elif command == '+':
347 affects_new = True 356 affects_new = True
348 action = 'add' 357 action = 'add'
358 stats[0] += 1
349 elif command == '-': 359 elif command == '-':
350 affects_old = True 360 affects_old = True
351 action = 'del' 361 action = 'del'
362 stats[1] += 1
352 else: 363 else:
353 affects_old = affects_new = True 364 affects_old = affects_new = True
354 action = 'unmod' 365 action = 'unmod'
355 366
356 old_line += affects_old 367 old_line += affects_old
360 'new_lineno': affects_new and new_line or '', 371 'new_lineno': affects_new and new_line or '',
361 'action': action, 372 'action': action,
362 'line': line 373 'line': line
363 }) 374 })
364 line = lineiter.next() 375 line = lineiter.next()
365
366 except StopIteration: 376 except StopIteration:
367 pass 377 pass
368 378
369 # highlight inline changes 379 # highlight inline changes
370 for _ in files: 380 for _ in files:
371 for chunk in chunks: 381 for chunk in chunks:
372 lineiter = iter(chunk) 382 lineiter = iter(chunk)
373 #first = True
374 try: 383 try:
375 while 1: 384 while 1:
376 line = lineiter.next() 385 line = lineiter.next()
377 if line['action'] != 'unmod': 386 if line['action'] != 'unmod':
378 nextline = lineiter.next() 387 nextline = lineiter.next()
380 nextline['action'] == line['action']: 389 nextline['action'] == line['action']:
381 continue 390 continue
382 self.differ(line, nextline) 391 self.differ(line, nextline)
383 except StopIteration: 392 except StopIteration:
384 pass 393 pass
385
386 return files 394 return files
387 395
388 def prepare(self): 396 def prepare(self):
389 """ 397 """
390 Prepare the passed udiff for HTML rendering. It'l return a list 398 Prepare the passed udiff for HTML rendering. It'l return a list
422 udiff_copy = self._parse_gitdiff(udiff_copy) 430 udiff_copy = self._parse_gitdiff(udiff_copy)
423 return u''.join(udiff_copy) 431 return u''.join(udiff_copy)
424 432
425 def as_html(self, table_class='code-difftable', line_class='line', 433 def as_html(self, table_class='code-difftable', line_class='line',
426 new_lineno_class='lineno old', old_lineno_class='lineno new', 434 new_lineno_class='lineno old', old_lineno_class='lineno new',
427 code_class='code', enable_comments=False): 435 code_class='code', enable_comments=False, diff_lines=None):
428 """ 436 """
429 Return udiff as html table with customized css classes 437 Return udiff as html table with customized css classes
430 """ 438 """
431 def _link_to_if(condition, label, url): 439 def _link_to_if(condition, label, url):
432 """ 440 """
438 'url': url, 446 'url': url,
439 'label': label 447 'label': label
440 } 448 }
441 else: 449 else:
442 return label 450 return label
443 diff_lines = self.prepare() 451 if diff_lines is None:
452 diff_lines = self.prepare()
444 _html_empty = True 453 _html_empty = True
445 _html = [] 454 _html = []
446 _html.append('''<table class="%(table_class)s">\n''' % { 455 _html.append('''<table class="%(table_class)s">\n''' % {
447 'table_class': table_class 456 'table_class': table_class
448 }) 457 })