Mercurial > hg
view hgext/churn.py @ 6945:2cfdabe235fb
hgweb: return content iterator instead of using write() callable
This is a new version of 4879468fa28f (which was backed out in 943f066c0d58),
with an extra line removed to fix problems with hg serve. hg's internal web
server contains checking if the app isn't trying to write more bytes than
specified by the Content-Length header. The first try still contained an old
line that wrote the response, so the response was sent twice.
author | Dirkjan Ochtman <dirkjan@ochtman.nl> |
---|---|
date | Sat, 30 Aug 2008 17:13:23 +0200 |
parents | b114a8c7998f |
children | a9411e29773f |
line wrap: on
line source
# churn.py - create a graph showing who changed the most lines # # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. '''allow graphing the number of lines changed per contributor''' from mercurial.i18n import gettext as _ from mercurial import patch, cmdutil, util, node import os, sys def get_tty_width(): if 'COLUMNS' in os.environ: try: return int(os.environ['COLUMNS']) except ValueError: pass try: import termios, array, fcntl for dev in (sys.stdout, sys.stdin): try: fd = dev.fileno() if not os.isatty(fd): continue arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8) return array.array('h', arri)[1] except ValueError: pass except ImportError: pass return 80 def countrevs(ui, repo, amap, revs, progress=False): stats = {} count = pct = 0 if not revs: revs = range(len(repo)) for rev in revs: ctx2 = repo[rev] parents = ctx2.parents() if len(parents) > 1: ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) continue ctx1 = parents[0] lines = 0 ui.pushbuffer() patch.diff(repo, ctx1.node(), ctx2.node()) diff = ui.popbuffer() for l in diff.split('\n'): if (l.startswith("+") and not l.startswith("+++ ") or l.startswith("-") and not l.startswith("--- ")): lines += 1 user = util.email(ctx2.user()) user = amap.get(user, user) # remap stats[user] = stats.get(user, 0) + lines ui.debug("rev %d: %d lines by %s\n" % (rev, lines, user)) if progress: count += 1 newpct = int(100.0 * count / max(len(revs), 1)) if pct < newpct: pct = newpct ui.write("\rGenerating stats: %d%%" % pct) sys.stdout.flush() if progress: ui.write("\r") sys.stdout.flush() return stats def churn(ui, repo, **opts): '''graphs the number of lines changed The map file format used to specify aliases is fairly simple: <alias email> <actual email>''' def pad(s, l): return (s + " " * l)[:l] amap = {} aliases = opts.get('aliases') if aliases: for l in open(aliases, "r"): l = l.strip() alias, actual = l.split() amap[alias] = actual revs = util.sort([int(r) for r in cmdutil.revrange(repo, opts['rev'])]) stats = countrevs(ui, repo, amap, revs, opts.get('progress')) if not stats: return stats = util.sort([(-l, u, l) for u,l in stats.items()]) maxchurn = float(max(1, stats[0][2])) maxuser = max([len(u) for k, u, l in stats]) ttywidth = get_tty_width() ui.debug(_("assuming %i character terminal\n") % ttywidth) width = ttywidth - maxuser - 2 - 6 - 2 - 2 for k, user, churn in stats: print "%s %6d %s" % (pad(user, maxuser), churn, "*" * int(churn * width / maxchurn)) cmdtable = { "churn": (churn, [('r', 'rev', [], _('limit statistics to the specified revisions')), ('', 'aliases', '', _('file with email aliases')), ('', 'progress', None, _('show progress'))], 'hg churn [-r REVISIONS] [--aliases FILE] [--progress]'), }