log: rewrite default template to use labels (issue2866)
This is a complete rewrite of the default template to use labels. This
seems ultimately useless to me in most cases. The biggest benefit of
this patch to me seems to be a fairly complicated example of the
templating engine. It was a lot of hard work to figure out the precise
acceptable syntax, since it's almost undocumented. Hat tip to Steve
Losh's smartlog template, which helped me figure out a lot of the
syntax. Hopefully later I can use the present default log template
as an example for documenting the templating engine.
A test is attached. My goal was to match the --color=debug output,
which may differ slightly in newlines from the actual ANSI escape
codes output. I consider this an acceptable invisible deviation.
There seems to be a considerable slowdown with this rewrite.
Before:
$ time hg log -T default -r .~100::. > /dev/null
real 0m0.882s
user 0m0.812s
sys 0m0.064s
$ time hg log -T default -r .~100::. > /dev/null
real 0m0.872s
user 0m0.796s
sys 0m0.068s
$ time hg log -T default -r .~100::. > /dev/null
real 0m0.917s
user 0m0.836s
sys 0m0.076s
After:
$ time hg log -T default -r .~100::. > /dev/null
real 0m1.480s
user 0m1.392s
sys 0m0.072s
$ time hg log -T default -r .~100::. > /dev/null
real 0m1.500s
user 0m1.400s
sys 0m0.088s
$ time hg log -T default -r .~100::. > /dev/null
real 0m1.462s
user 0m1.364s
sys 0m0.092s
Following the maxim, "make it work, profile, make it faster, in that
order", I deem this slowdown acceptable for now.
I suspect but have not confirmed that a big slowdown comes from
calling keywords twice in the file templates, once to test the
existence of output and again to actually list the output. If so, a
simple speedup might be to improve the templating engine to cache
keywords when called more than once on the same revision.
TODO: I found a bug while working on this. The following stack traces:
hg log -r . -T '{ifcontains(phase, "secret public", "lol", "omg")}\n'
# Read the output of a "svn log --xml" command on stdin, parse it and
# print a subset of attributes common to all svn versions tested by
# hg.
import xml.dom.minidom, sys
def xmltext(e):
return ''.join(c.data for c
in e.childNodes
if c.nodeType == c.TEXT_NODE)
def parseentry(entry):
e = {}
e['revision'] = entry.getAttribute('revision')
e['author'] = xmltext(entry.getElementsByTagName('author')[0])
e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
e['paths'] = []
paths = entry.getElementsByTagName('paths')
if paths:
paths = paths[0]
for p in paths.getElementsByTagName('path'):
action = p.getAttribute('action')
path = xmltext(p)
frompath = p.getAttribute('copyfrom-path')
fromrev = p.getAttribute('copyfrom-rev')
e['paths'].append((path, action, frompath, fromrev))
return e
def parselog(data):
entries = []
doc = xml.dom.minidom.parseString(data)
for e in doc.getElementsByTagName('logentry'):
entries.append(parseentry(e))
return entries
def printentries(entries):
fp = sys.stdout
for e in entries:
for k in ('revision', 'author', 'msg'):
fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
for path, action, fpath, frev in sorted(e['paths']):
frominfo = ''
if frev:
frominfo = ' (from %s@%s)' % (fpath, frev)
p = ' %s %s%s\n' % (action, path, frominfo)
fp.write(p.encode('utf-8'))
if __name__ == '__main__':
data = sys.stdin.read()
entries = parselog(data)
printentries(entries)