fastannotate: add hgweb support

Summary:
This adds fastannotate support for hgweb. There are some issues with "path"
handling, which will be addressed in follow up patches.

A minor change has been made in this patch to support revision numbers
(previously only global changeset hashes are supported).

Test Plan:
Run `hg serve --config fastannotate.hgweb=1` on the `hg-committed` repo, open
the following URL and confirm it's using fastannotate:
http://localhost:8000/annotate/9af6f8434430/mercurial/commands.py

Reviewers: #sourcecontrol, simonfar

Reviewed By: simonfar

Subscribers: simonfar, mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D3993636

Signature: t1:3993636:1476026586:cb0628aa7107bdbfde852a6a1471f70dcb21a5ef
This commit is contained in:
Jun Wu 2016-10-09 15:19:18 +01:00
parent edf67f905d
commit fc1e2d9c80
3 changed files with 56 additions and 6 deletions

View File

@ -22,6 +22,11 @@ be faster than the vanilla 'annotate' if the cache is present.
mainbranch = master
# add a "fastannotate" command, and replace the default "annotate" command
commands = fastannotate, annotate
# replace hgweb's annotate implementation (default: False)
# note: mainbranch should be set to a forward-only name, otherwise the
# linelog cache may be rebuilt frequently, which leads to errors and
# poor performance
hgweb = True
# use unfiltered repo for better performance
unfilteredrepo = True
# sacrifice correctness in some cases for performance (default: False)
@ -54,3 +59,7 @@ def uisetup(ui):
else:
raise hgerror.Abort(_('%s: invalid fastannotate.commands option')
% name)
if ui.configbool('fastannotate', 'hgweb'):
# local import to avoid overhead of loading hgweb for non-hgweb usages
from fastannotate import hgwebsupport
hgwebsupport.replacehgwebannotate()

View File

@ -94,7 +94,7 @@ def resolvefctx(repo, rev, path, resolverev=False, adjustctx=None):
is 'linkrev', trust the linkrev and do not adjust it. this is noticeably
faster for big repos but is incorrect for some cases.
"""
if resolverev:
if resolverev and not isinstance(rev, int):
ctx = _revsingle(repo, rev)
else:
ctx = repo[rev]
@ -352,11 +352,12 @@ class _annotatecontext(object):
"""
result = True
f = None
if len(rev) == 20 and rev in self.revmap:
f = rev
elif len(rev) == 40 and node.bin(rev) in self.revmap:
f = node.bin(rev)
else:
if not isinstance(rev, int):
if len(rev) == 20 and rev in self.revmap:
f = rev
elif len(rev) == 40 and node.bin(rev) in self.revmap:
f = node.bin(rev)
if f is None:
adjustctx = 'linkrev' if self._perfhack else True
f = self._resolvefctx(rev, adjustctx=adjustctx, resolverev=True)
result = f in self.revmap

View File

@ -0,0 +1,40 @@
# Copyright 2016-present Facebook. All Rights Reserved.
#
# hgwebsupport: fastannotate support for hgweb
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from mercurial import (
extensions,
patch,
)
from mercurial.hgweb import webutil
from fastannotate import context
def _annotate(orig, fctx, ui):
diffopts = patch.difffeatureopts(ui, untrusted=True,
section='annotate', whitespace=True)
aopts = context.annotateopts(diffopts=diffopts)
master = ui.config('fastannotate', 'mainbranch', 'default')
with context.annotatecontext(fctx.repo(), fctx.path(), aopts) as ac:
# fastannotate returns: [(nodeid, linenum, path)], [linecontent]
annotated, contents = ac.annotate(fctx.rev(), master=master,
showpath=True, showlines=True)
# convert to what fctx.annotate returns: [((fctx, number), linecontent)]
fctxmap = {} # {(nodeid, path): fctx}
repo = fctx.repo()
results = []
for i, (hsh, linenum, path) in enumerate(annotated):
if (hsh, path) not in fctxmap:
fctxmap[(hsh, path)] = context.resolvefctx(repo, hsh, path)
results.append(((fctxmap[(hsh, path)], linenum), contents[i]))
return results
def replacehgwebannotate():
extensions.wrapfunction(webutil, 'annotate', _annotate)