Mercurial > public > mercurial-scm > hg
comparison mercurial/patch.py @ 7547:4949729ee9ee
python implementation of diffstat
Implemented as two functions: diffstat, which yields lines of text,
formatted as a usual diffstat output, and diffstatdata, which is called
inside diffstat to do real performing and yield file names with
appropriate data (numbers of added and removed lines).
author | Alexander Solovyov <piranha@piranha.org.ua> |
---|---|
date | Thu, 25 Dec 2008 10:48:24 +0200 |
parents | ca044918fdf1 |
children | e05aa73ce2b7 |
comparison
equal
deleted
inserted
replaced
7546:c7f48414f3ad | 7547:4949729ee9ee |
---|---|
7 # of the GNU General Public License, incorporated herein by reference. | 7 # of the GNU General Public License, incorporated herein by reference. |
8 | 8 |
9 from i18n import _ | 9 from i18n import _ |
10 from node import hex, nullid, short | 10 from node import hex, nullid, short |
11 import base85, cmdutil, mdiff, util, revlog, diffhelpers, copies | 11 import base85, cmdutil, mdiff, util, revlog, diffhelpers, copies |
12 import cStringIO, email.Parser, os, re, errno | 12 import cStringIO, email.Parser, os, re, errno, math |
13 import sys, tempfile, zlib | 13 import sys, tempfile, zlib |
14 | 14 |
15 gitre = re.compile('diff --git a/(.*) b/(.*)') | 15 gitre = re.compile('diff --git a/(.*) b/(.*)') |
16 | 16 |
17 class PatchError(Exception): | 17 class PatchError(Exception): |
1342 fp.close() | 1342 fp.close() |
1343 | 1343 |
1344 for seqno, rev in enumerate(revs): | 1344 for seqno, rev in enumerate(revs): |
1345 single(rev, seqno+1, fp) | 1345 single(rev, seqno+1, fp) |
1346 | 1346 |
1347 def diffstat(patchlines): | 1347 def diffstatdata(lines): |
1348 if not util.find_exe('diffstat'): | 1348 filename = None |
1349 return | 1349 for line in lines: |
1350 output = util.filter('\n'.join(patchlines), | 1350 if line.startswith('diff'): |
1351 'diffstat -p1 -w79 2>%s' % util.nulldev) | 1351 if filename: |
1352 stat = [l.lstrip() for l in output.splitlines(True)] | 1352 yield (filename, adds, removes) |
1353 last = stat.pop() | 1353 # set numbers to 0 anyway when starting new file |
1354 stat.insert(0, last) | 1354 adds = 0 |
1355 stat = ''.join(stat) | 1355 removes = 0 |
1356 return stat | 1356 if line.startswith('diff --git'): |
1357 filename = gitre.search(line).group(1) | |
1358 else: | |
1359 # format: "diff -r ... -r ... file name" | |
1360 filename = line.split(None, 5)[-1] | |
1361 elif line.startswith('+') and not line.startswith('+++'): | |
1362 adds += 1 | |
1363 elif line.startswith('-') and not line.startswith('---'): | |
1364 removes += 1 | |
1365 yield (filename, adds, removes) | |
1366 | |
1367 def diffstat(lines): | |
1368 output = [] | |
1369 stats = list(diffstatdata(lines)) | |
1370 width = util.termwidth() - 2 | |
1371 | |
1372 maxtotal, maxname = 0, 0 | |
1373 totaladds, totalremoves = 0, 0 | |
1374 for filename, adds, removes in stats: | |
1375 totaladds += adds | |
1376 totalremoves += removes | |
1377 maxname = max(maxname, len(filename)) | |
1378 maxtotal = max(maxtotal, adds+removes) | |
1379 | |
1380 countwidth = len(str(maxtotal)) | |
1381 graphwidth = width - countwidth - maxname | |
1382 if graphwidth < 10: | |
1383 graphwidth = 10 | |
1384 | |
1385 factor = int(math.ceil(float(maxtotal) / graphwidth)) | |
1386 | |
1387 for filename, adds, removes in stats: | |
1388 # If diffstat runs out of room it doesn't print anything, which | |
1389 # isn't very useful, so always print at least one + or - if there | |
1390 # were at least some changes | |
1391 pluses = '+' * max(adds/factor, int(bool(adds))) | |
1392 minuses = '-' * max(removes/factor, int(bool(removes))) | |
1393 output.append(' %-*s | %*.d %s%s\n' % (maxname, filename, countwidth, | |
1394 adds+removes, pluses, minuses)) | |
1395 | |
1396 if stats: | |
1397 output.append(' %d files changed, %d insertions(+), %d deletions(-)\n' % | |
1398 (len(stats), totaladds, totalremoves)) | |
1399 | |
1400 return ''.join(output) |