[PATCH 1 of 1] python implementation of diffstat
Alexander Solovyov
piranha at piranha.org.ua
Sun Dec 21 03:54:30 CST 2008
4 files changed, 97 insertions(+), 32 deletions(-)
mercurial/patch.py | 79 ++++++++++++++++++++++++++++++++++-----
hgext/patchbomb.py | 21 ++++------
tests/test-patchbomb.out | 26 +++++++++----
tests/test-notify.out | 3 +-
# HG changeset patch
# User Alexander Solovyov <piranha at piranha.org.ua>
# Date 1229853225 -7200
# Node ID 1797935e306ae8f95ae81f436440822592788514
# Parent 3896310bd797a3c0db22654321e88db9cc73d3e7
python implementation of diffstat
Implemented as an class, string representation of which is similar to
the output of system diffstat command. There is possibility to access
attributes of a diffstat object to get already parsed statistics in
python code.
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -9,8 +9,7 @@
The remainder of the changeset description.
- [Optional] If the diffstat program is installed, the result of
- running diffstat on the patch.
+ [Optional] The result of running diffstat on the patch.
The patch itself, as generated by "hg export".
@@ -98,17 +97,13 @@
ui.warn(_('Please enter a valid value.\n'))
def cdiffstat(ui, summary, patchlines):
- s = patch.diffstat(patchlines)
- if s:
- if summary:
- ui.write(summary, '\n')
- ui.write(s, '\n')
- ans = prompt(ui, _('Does the diffstat above look okay? '), 'y')
- if not ans.lower().startswith('y'):
- raise util.Abort(_('diffstat rejected'))
- elif s is None:
- ui.warn(_('no diffstat information available\n'))
- s = ''
+ s = str(patch.diffstat(patchlines))
+ if summary:
+ ui.write(summary, '\n')
+ ui.write(s, '\n')
+ ans = prompt(ui, _('Does the diffstat above look okay? '), 'y')
+ if not ans.lower().startswith('y'):
+ raise util.Abort(_('diffstat rejected'))
return s
def makepatch(ui, repo, patch, opts, _charsets, idx, total, patchname=None):
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1344,13 +1344,72 @@
for seqno, rev in enumerate(revs):
single(rev, seqno+1, fp)
-def diffstat(patchlines):
- if not util.find_exe('diffstat'):
- return
- output = util.filter('\n'.join(patchlines),
- 'diffstat -p1 -w79 2>%s' % util.nulldev)
- stat = [l.lstrip() for l in output.splitlines(True)]
- last = stat.pop()
- stat.insert(0, last)
- stat = ''.join(stat)
- return stat
+class diffstat(object):
+ def __init__(self, lines):
+ self.maxname = 0
+ self.maxtotal = 0
+ self.adds = 0
+ self.removes = 0
+ self.stats = {}
+ self._parse(lines)
+
+ def _parse(self, lines):
+ adds = 0
+ removes = 0
+ filename = None
+
+ for line in lines:
+ if line.startswith('diff'):
+ if filename:
+ self._add_stats(filename, adds, removes)
+ # set numbers to 0 anyway when starting new file
+ adds = 0
+ removes = 0
+ if line.startswith('diff --git'):
+ filename = gitre.search(line).group(1)
+ else:
+ # format: "diff -r ... -r ... file name"
+ filename = line.split(None, 5)[-1]
+ elif line.startswith('+') and not line.startswith('+++'):
+ adds += 1
+ elif line.startswith('-') and not line.startswith('---'):
+ removes += 1
+
+ self._add_stats(filename, adds, removes)
+
+ def _add_stats(self, filename, adds, removes):
+ if filename is None:
+ return
+ self.stats[filename] = (adds, removes)
+ self.maxname = max(self.maxname, len(filename))
+ self.maxtotal = max(self.maxtotal, adds + removes)
+ self.adds += adds
+ self.removes += removes
+
+ def __str__(self):
+ width = 78
+ countwidth = len(str(self.maxtotal))
+ graphwidth = width - countwidth - self.maxname
+ factor = 1
+
+ # The graph width can be <= 0 if there is a modified file with a
+ # filename longer than 'width'. Use a minimum of 10.
+ if graphwidth < 10:
+ graphwidth = 10
+
+ while (self.maxtotal/factor) > graphwidth:
+ factor += 1
+
+ if self.stats:
+ s = (' %d files changed, %d insertions(+), %d deletions(-)\n' %
+ (len(self.stats), self.adds, self.removes))
+
+ for filename, (adds, removes) in self.stats.items():
+ # If diffstat runs out of room it doesn't print anything, which
+ # isn't very useful, so always print at least one + or 1
+ pluses = '+' * max(adds/factor, 1)
+ minuses = '-' * max(removes/factor, 1)
+ s += ' %-*s | %*.d %s%s\n' % (self.maxname, filename, countwidth,
+ adds+removes, pluses, minuses)
+
+ return s
diff --git a/tests/test-notify.out b/tests/test-notify.out
--- a/tests/test-notify.out
+++ b/tests/test-notify.out
@@ -150,7 +150,8 @@
b
diffstat:
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ a | 1 +-
diffs (6 lines):
diff --git a/tests/test-patchbomb.out b/tests/test-patchbomb.out
--- a/tests/test-patchbomb.out
+++ b/tests/test-patchbomb.out
@@ -196,7 +196,8 @@
c
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ c | 1 +-
Displaying [PATCH] test ...
@@ -211,7 +212,8 @@
To: foo
Cc: bar
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ c | 1 +-
# HG changeset patch
@@ -232,15 +234,19 @@
a
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ a | 1 +-
b
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ b | 1 +-
Final summary:
-files patched: 2
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+ a | 1 +-
+ b | 1 +-
Write the introductory message for the patch series.
@@ -258,7 +264,9 @@
Cc: bar
-files patched: 2
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+ a | 1 +-
+ b | 1 +-
Displaying [PATCH 1 of 2] a ...
Content-Type: text/plain; charset="us-ascii"
@@ -274,7 +282,8 @@
To: foo
Cc: bar
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ a | 1 +-
# HG changeset patch
@@ -304,7 +313,8 @@
To: foo
Cc: bar
-files patched: 1
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ b | 1 +-
# HG changeset patch
More information about the Mercurial-devel
mailing list