##// END OF EJS Templates
narrow: rework logic to check whether we need to widen and narrow...
narrow: rework logic to check whether we need to widen and narrow This patch reworks logic which calculates whether we need to extend or narrow our working copy or not. We filter the addincludes, removeincludes, addexcludes and removeexcludes passed from user to the actual added and removed includes and excludes. What that means is a user can pass an already included path as addincludes, a path which is not included as removeincludes etc. In such situations the old logic use to think we need to do some work, whereas we don't need to do that work. In old logic, even if we don't have anything new to include but it believes we need to call widen, this adds some good amount of work on large repository. A widen calls involves computing incomming csets, calling the narrow_widen() which in non-ellipses cases goes through all the set of csets which are available which can take ~2-3 mins on large repos. Those 2-3 minutes are spend on doing nothing which a client can prevent by checking is there really anything which needs to be included. The tests changes shows that we don't go to the server anymore in such cases which is nice. Differential Revision: https://phab.mercurial-scm.org/D5183

File last commit:

r39246:303dae01 default
r40462:30a7d3b6 default
Show More
support.py
122 lines | 4.2 KiB | text/x-python | PythonLexer
# Copyright 2016-present Facebook. All Rights Reserved.
#
# support: fastannotate support for hgweb, and filectx
#
# 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 (
context as hgcontext,
dagop,
extensions,
hgweb,
patch,
util,
)
from . import (
context,
revmap,
)
class _lazyfctx(object):
"""delegates to fctx but do not construct fctx when unnecessary"""
def __init__(self, repo, node, path):
self._node = node
self._path = path
self._repo = repo
def node(self):
return self._node
def path(self):
return self._path
@util.propertycache
def _fctx(self):
return context.resolvefctx(self._repo, self._node, self._path)
def __getattr__(self, name):
return getattr(self._fctx, name)
def _convertoutputs(repo, annotated, contents):
"""convert fastannotate outputs to vanilla annotate format"""
# fastannotate returns: [(nodeid, linenum, path)], [linecontent]
# convert to what fctx.annotate returns: [annotateline]
results = []
fctxmap = {}
annotateline = dagop.annotateline
for i, (hsh, linenum, path) in enumerate(annotated):
if (hsh, path) not in fctxmap:
fctxmap[(hsh, path)] = _lazyfctx(repo, hsh, path)
# linenum: the user wants 1-based, we have 0-based.
lineno = linenum + 1
fctx = fctxmap[(hsh, path)]
line = contents[i]
results.append(annotateline(fctx=fctx, lineno=lineno, text=line))
return results
def _getmaster(fctx):
"""(fctx) -> str"""
return fctx._repo.ui.config('fastannotate', 'mainbranch') or 'default'
def _doannotate(fctx, follow=True, diffopts=None):
"""like the vanilla fctx.annotate, but do it via fastannotate, and make
the output format compatible with the vanilla fctx.annotate.
may raise Exception, and always return line numbers.
"""
master = _getmaster(fctx)
annotated = contents = None
with context.fctxannotatecontext(fctx, follow, diffopts) as ac:
try:
annotated, contents = ac.annotate(fctx.rev(), master=master,
showpath=True, showlines=True)
except Exception:
ac.rebuild() # try rebuild once
fctx._repo.ui.debug('fastannotate: %s: rebuilding broken cache\n'
% fctx._path)
try:
annotated, contents = ac.annotate(fctx.rev(), master=master,
showpath=True, showlines=True)
except Exception:
raise
assert annotated and contents
return _convertoutputs(fctx._repo, annotated, contents)
def _hgwebannotate(orig, fctx, ui):
diffopts = patch.difffeatureopts(ui, untrusted=True,
section='annotate', whitespace=True)
return _doannotate(fctx, diffopts=diffopts)
def _fctxannotate(orig, self, follow=False, linenumber=False, skiprevs=None,
diffopts=None):
if skiprevs:
# skiprevs is not supported yet
return orig(self, follow, linenumber, skiprevs=skiprevs,
diffopts=diffopts)
try:
return _doannotate(self, follow, diffopts)
except Exception as ex:
self._repo.ui.debug('fastannotate: falling back to the vanilla '
'annotate: %r\n' % ex)
return orig(self, follow=follow, skiprevs=skiprevs,
diffopts=diffopts)
def _remotefctxannotate(orig, self, follow=False, skiprevs=None, diffopts=None):
# skipset: a set-like used to test if a fctx needs to be downloaded
skipset = None
with context.fctxannotatecontext(self, follow, diffopts) as ac:
skipset = revmap.revmap(ac.revmappath)
return orig(self, follow, skiprevs=skiprevs, diffopts=diffopts,
prefetchskip=skipset)
def replacehgwebannotate():
extensions.wrapfunction(hgweb.webutil, 'annotate', _hgwebannotate)
def replacefctxannotate():
extensions.wrapfunction(hgcontext.basefilectx, 'annotate', _fctxannotate)