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)