##// END OF EJS Templates
setdiscovery: make progress on most connected groups each roundtrip...
setdiscovery: make progress on most connected groups each roundtrip Consider history like this: o | o | | | o | | | o |/ o | o | | | o | | | o |/ o | o | | | o | | | o |/ o ~ Assume the left mainline is available in the remote repo and the other commits are only in the local repo. Also imagine that instead of 3 local branches with 3 commits on each, there are 1000 branches (the number of commits on each doesn't matter much here). In such a scenario, the current setdiscovery code will pick a sample size of 200 among these branches and ask the remote which of them it has. However, the discovery for each such branch is completely independent of the discovery for the others -- knowing whether the remote has a commit in one branch doesn't give us any information about the other branches. The discovery will therefore take at least 5 roundtrips (maybe more depending on which commit in each linear chain was sampled). Since the discovery for each branch is independent, there is no reason to let one branch wait for another, so this patch makes it so we sample at least as many commits as there are branches. It may still happen (it's very likely, even) that we get multiple samples from one branch and none from another, but that will even out over a few rounds and I think this is still a big improvement. Because of http header size limits, we still use the old behavior unless experimental.httppostargs=true. I've timed this by running `hg debugdiscovery mozilla-unified --debug` in the mozilla-try repo. Both repos were local. Before this patch, last part of the output was: 2249 total queries in 5276.4859s elapsed time: 5276.652634 seconds heads summary: total common heads: 13 also local heads: 4 also remote heads: 8 both: 4 local heads: 28317 common: 4 missing: 28313 remote heads: 12 common: 8 unknown: 4 local changesets: 2014901 common: 530373 missing: 1484528 common heads: 1dad417c28ad 4a108e94d3e2 4d7ef530fffb 5350524bb654 777e60ca8853 7d97fafba271 9cd2ab4d0029 a55ce37217da d38398e5144e dcc6d7a0dc00 e09297892ada e24ec6070d7b fd559328eaf3 After this patch, the output was (including all the samples, since there were so few now): taking initial sample query 2; still undecided: 1599476, sample size is: 108195 sampling from both directions query 3; still undecided: 810922, sample size is: 194158 sampling from both directions query 4; still undecided: 325882, sample size is: 137302 sampling from both directions query 5; still undecided: 111459, sample size is: 74586 sampling from both directions query 6; still undecided: 26805, sample size is: 23960 sampling from both directions query 7; still undecided: 2549, sample size is: 2528 sampling from both directions query 8; still undecided: 21, sample size is: 21 8 total queries in 24.5064s elapsed time: 24.670051 seconds heads summary: total common heads: 13 also local heads: 4 also remote heads: 8 both: 4 local heads: 28317 common: 4 missing: 28313 remote heads: 12 common: 8 unknown: 4 local changesets: 2014901 common: 530373 missing: 1484528 common heads: 1dad417c28ad 4a108e94d3e2 4d7ef530fffb 5350524bb654 777e60ca8853 7d97fafba271 9cd2ab4d0029 a55ce37217da d38398e5144e dcc6d7a0dc00 e09297892ada e24ec6070d7b fd559328eaf3 Differential Revision: https://phab.mercurial-scm.org/D2647

File last commit:

r42524:832c59d1 default
r42594:5b34972a default
Show More
webutil.py
807 lines | 26.1 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 # hgweb/webutil.py - utility library for the web interface.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Yuya Nishihara
hgweb: use absolute_import
r27046 from __future__ import absolute_import
import copy
import difflib
import os
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 import re
Yuya Nishihara
hgweb: use absolute_import
r27046
from ..i18n import _
from ..node import hex, nullid, short
from .common import (
ErrorResponse,
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 HTTP_BAD_REQUEST,
Yuya Nishihara
hgweb: use absolute_import
r27046 HTTP_NOT_FOUND,
paritygen,
)
from .. import (
context,
Yuya Nishihara
diffutil: move the module out of utils package...
r38607 diffutil,
Yuya Nishihara
hgweb: use absolute_import
r27046 error,
match,
Denis Laxalde
mdiff: add a hunkinrange helper function...
r31808 mdiff,
av6
hgweb: explain instabilities of unstable changesets
r36973 obsutil,
Yuya Nishihara
hgweb: use absolute_import
r27046 patch,
pathutil,
Augie Fackler
webutil: use pycompat.bytestr() instead of str()...
r34808 pycompat,
Martin von Zweigbergk
hgweb: use revsymbol() for creating context from changeid...
r37351 scmutil,
Yuya Nishihara
hgweb: use absolute_import
r27046 templatefilters,
av6
hgweb: display fate of obsolete changesets...
r35501 templatekw,
Yuya Nishihara
hgweb: wrap {archives} with mappinglist...
r37533 templateutil,
Yuya Nishihara
hgweb: use absolute_import
r27046 ui as uimod,
util,
)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from ..utils import (
stringutil,
)
Yuya Nishihara
hgweb: move archivespecs to webutil...
r37529 archivespecs = util.sortdict((
('zip', ('application/zip', 'zip', '.zip', None)),
('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
))
Yuya Nishihara
hgweb: forward archivelist() of hgweb to webutil...
r37532 def archivelist(ui, nodeid, url=None):
David Demelier
config: rename allow_archive to allow-archive...
r38215 allowed = ui.configlist('web', 'allow-archive', untrusted=True)
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531 archives = []
for typ, spec in archivespecs.iteritems():
if typ in allowed or ui.configbool('web', 'allow' + typ,
untrusted=True):
archives.append({
'type': typ,
'extension': spec[2],
'node': nodeid,
'url': url,
})
Yuya Nishihara
hgweb: wrap {archives} with mappinglist...
r37533 return templateutil.mappinglist(archives)
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 def up(p):
Augie Fackler
hgweb: fix up trailing slash detection on Python 3...
r36731 if p[0:1] != "/":
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 p = "/" + p
Augie Fackler
hgweb: fix up trailing slash detection on Python 3...
r36731 if p[-1:] == "/":
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 p = p[:-1]
up = os.path.dirname(p)
if up == "/":
return "/"
return up + "/"
Pierre-Yves David
hgweb: better names for _navseq arguments...
r18391 def _navseq(step, firststep=None):
if firststep:
yield firststep
if firststep >= 20 and firststep <= 40:
Pierre-Yves David
hgweb: ensure _navseq yield strictly increasing numbers...
r18392 firststep = 50
yield firststep
assert step > 0
assert firststep > 0
while step <= firststep:
step *= 10
Pierre-Yves David
hgweb: drop recursivity in _navseq...
r18390 while True:
Pierre-Yves David
hgweb: better names for _navseq arguments...
r18391 yield 1 * step
yield 3 * step
step *= 10
Pierre-Yves David
hgweb: move the `seq` function out of the revnavgen scope...
r18389
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 class revnav(object):
Pierre-Yves David
hgweb: document the revnavgen function
r18320
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 def __init__(self, repo):
Pierre-Yves David
hgweb: pass nodefunc to the revnav object...
r18404 """Navigation generation object
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 :repo: repo object we generate nav for
Pierre-Yves David
hgweb: pass nodefunc to the revnav object...
r18404 """
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 # used for hex generation
self._revlog = repo.changelog
Pierre-Yves David
hgweb: pass nodefunc to the revnav object...
r18404
Pierre-Yves David
hgweb: simplify the handling of empty repo...
r18406 def __nonzero__(self):
"""return True if any revision to navigate over"""
Pierre-Yves David
hgweb: handle filtered "0" rev in navigation...
r19094 return self._first() is not None
Gregory Szorc
py3: add __bool__ to every class defining __nonzero__...
r31476 __bool__ = __nonzero__
Pierre-Yves David
hgweb: handle filtered "0" rev in navigation...
r19094 def _first(self):
"""return the minimum non-filtered changeset or None"""
try:
timeless
py3: convert to next() function...
r29216 return next(iter(self._revlog))
Pierre-Yves David
hgweb: handle filtered "0" rev in navigation...
r19094 except StopIteration:
return None
Pierre-Yves David
hgweb: simplify the handling of empty repo...
r18406
Pierre-Yves David
hgweb: move hex creation into an object method...
r18405 def hex(self, rev):
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 return hex(self._revlog.node(rev))
Pierre-Yves David
hgweb: move hex creation into an object method...
r18405
Pierre-Yves David
hgweb: pass nodefunc to the revnav object...
r18404 def gen(self, pos, pagelen, limit):
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 """computes label and revision id for navigation link
Pierre-Yves David
hgweb: document the revnavgen function
r18320
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 :pos: is the revision relative to which we generate navigation.
:pagelen: the size of each navigation page
:limit: how far shall we link
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 The return is:
Yuya Nishihara
hgweb: wrap {changenav} and {nav} with mappinglist
r37716 - a single element mappinglist
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 - containing a dictionary with a `before` and `after` key
Yuya Nishihara
hgweb: make revnav.gen() simply build a list of mappings by one pass...
r37715 - values are dictionaries with `label` and `node` keys
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 """
Pierre-Yves David
hgweb: simplify the handling of empty repo...
r18406 if not self:
# empty repo
Yuya Nishihara
hgweb: wrap {changenav} and {nav} with mappinglist
r37716 return templateutil.mappinglist([
{'before': templateutil.mappinglist([]),
'after': templateutil.mappinglist([])},
])
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 targets = []
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403 for f in _navseq(1, pagelen):
if f > limit:
break
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 targets.append(pos + f)
targets.append(pos - f)
targets.sort()
Pierre-Yves David
hgweb: handle filtered "0" rev in navigation...
r19094 first = self._first()
Yuya Nishihara
hgweb: make revnav.gen() simply build a list of mappings by one pass...
r37715 navbefore = [{'label': '(%i)' % first, 'node': self.hex(first)}]
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 navafter = []
for rev in targets:
Pierre-Yves David
hgweb: ignore filtered revision in revnav...
r18426 if rev not in self._revlog:
continue
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 if pos < rev < limit:
Yuya Nishihara
hgweb: make revnav.gen() simply build a list of mappings by one pass...
r37715 navafter.append({'label': '+%d' % abs(rev - pos),
'node': self.hex(rev)})
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 if 0 < rev < pos:
Yuya Nishihara
hgweb: make revnav.gen() simply build a list of mappings by one pass...
r37715 navbefore.append({'label': '-%d' % abs(rev - pos),
'node': self.hex(rev)})
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254
Yuya Nishihara
hgweb: make revnav.gen() simply build a list of mappings by one pass...
r37715 navafter.append({'label': 'tip', 'node': 'tip'})
Pierre-Yves David
hgweb: move revnavgen into an object...
r18403
Yuya Nishihara
hgweb: wrap {changenav} and {nav} with mappinglist
r37716 # TODO: maybe this can be a scalar object supporting tomap()
return templateutil.mappinglist([
{'before': templateutil.mappinglist(navbefore),
'after': templateutil.mappinglist(navafter)},
])
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: introduction a filerevnav subclass...
r18408 class filerevnav(revnav):
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409
def __init__(self, repo, path):
"""Navigation generation object
:repo: repo object we generate nav for
:path: path of the file we generate nav for
"""
# used for iteration
self._changelog = repo.unfiltered().changelog
# used for hex generation
self._revlog = repo.file(path)
def hex(self, rev):
return hex(self._changelog.node(self._revlog.linkrev(rev)))
Yuya Nishihara
hgweb: extract a generator function of _siblings class...
r37717 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
# yields {'ctx': ctx}
Yuya Nishihara
hgweb: convert _siblings to a factory function of mappinggenerator...
r37718 def _ctxsgen(context, ctxs):
Yuya Nishihara
hgweb: extract a generator function of _siblings class...
r37717 for s in ctxs:
d = {
'node': s.hex(),
'rev': s.rev(),
'user': s.user(),
'date': s.date(),
'description': s.description(),
'branch': s.branch(),
}
if util.safehasattr(s, 'path'):
d['file'] = s.path()
yield d
Yuya Nishihara
hgweb: convert _siblings to a factory function of mappinggenerator...
r37718 def _siblings(siblings=None, hiderev=None):
if siblings is None:
siblings = []
siblings = [s for s in siblings if s.node() != nullid]
if len(siblings) == 1 and siblings[0].rev() == hiderev:
siblings = []
return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 def difffeatureopts(req, ui, section):
Boris Feld
webutil: pass a diffopts object to context.diff
r38585 diffopts = diffutil.difffeatureopts(ui, untrusted=True,
section=section, whitespace=True)
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391
for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'):
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 v = req.qsparams.get(k)
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 if v is not None:
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 v = stringutil.parsebool(v)
Gregory Szorc
hgweb: use parsebool for parsing diff query string options...
r34404 setattr(diffopts, k, v if v is not None else True)
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391
return diffopts
def annotate(req, fctx, ui):
diffopts = difffeatureopts(req, ui, 'annotate')
Yuya Nishihara
annotate: drop linenumber flag from fctx.annotate() (API)...
r37083 return fctx.annotate(follow=True, diffopts=diffopts)
Jun Wu
hgweb: make fctx.annotate a separated function so it could be wrapped...
r30081
Dirkjan Ochtman
hgweb: simplify parents/children generation code
r7671 def parents(ctx, hide=None):
Anton Shestakov
hgweb: use introrev() for finding parents (issue4506)...
r24136 if isinstance(ctx, context.basefilectx):
introrev = ctx.introrev()
if ctx.changectx().rev() != introrev:
Matt Harbison
hgweb: replace 'ctx._repo' with 'ctx.repo()'
r24340 return _siblings([ctx.repo()[introrev]], hide)
Dirkjan Ochtman
hgweb: simplify parents/children generation code
r7671 return _siblings(ctx.parents(), hide)
def children(ctx, hide=None):
return _siblings(ctx.children(), hide)
Matt Mackall
hgweb: minor improvements for new web style...
r6434 def renamelink(fctx):
Matt Mackall
hgweb: fix merge breakage
r6437 r = fctx.renamed()
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 if r:
Yuya Nishihara
hgweb: wrap {rename} with mappinglist...
r37921 return templateutil.mappinglist([{'file': r[0], 'node': hex(r[1])}])
return templateutil.mappinglist([])
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
def nodetagsdict(repo, node):
Yuya Nishihara
hgweb: wrap {tags} by hybridlist()...
r37922 return templateutil.hybridlist(repo.nodetags(node), name='name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596 def nodebookmarksdict(repo, node):
Yuya Nishihara
hgweb: wrap {bookmarks} by hybridlist()...
r37923 return templateutil.hybridlist(repo.nodebookmarks(node), name='name')
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def nodebranchdict(repo, ctx):
branches = []
branch = ctx.branch()
# If this is an empty repo, ctx.node() == nullid,
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 # ctx.branch() == 'default'.
try:
branchnode = repo.branchtip(branch)
except error.RepoLookupError:
branchnode = None
if branchnode == ctx.node():
Yuya Nishihara
hgweb: wrap {branches} by hybridlist()...
r37924 branches.append(branch)
return templateutil.hybridlist(branches, name='name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
def nodeinbranch(repo, ctx):
branches = []
branch = ctx.branch()
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 try:
branchnode = repo.branchtip(branch)
except error.RepoLookupError:
branchnode = None
if branch != 'default' and branchnode != ctx.node():
Yuya Nishihara
hgweb: wrap {inbranch} by hybridlist()...
r37925 branches.append(branch)
return templateutil.hybridlist(branches, name='name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
def nodebranchnodefault(ctx):
branches = []
branch = ctx.branch()
if branch != 'default':
Yuya Nishihara
hgweb: wrap {branch} and {changesetbranch} by hybridlist()...
r37926 branches.append(branch)
return templateutil.hybridlist(branches, name='name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 def _nodenamesgen(context, f, node, name):
for t in f(node):
yield {name: t}
Yuya Nishihara
hgweb: drop tmpl argument from webutil.showtag() and showbookmark()...
r37931 def showtag(repo, t1, node=nullid):
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 args = (repo.nodetags, node, 'tag')
return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Yuya Nishihara
hgweb: drop tmpl argument from webutil.showtag() and showbookmark()...
r37931 def showbookmark(repo, t1, node=nullid):
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 args = (repo.nodebookmarks, node, 'bookmark')
return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596
av6
hgweb: move branchentries code from webcommands to webutil
r26129 def branchentries(repo, stripecount, limit=0):
tips = []
heads = repo.heads()
parity = paritygen(stripecount)
sortkey = lambda item: (not item[1], item[0].rev())
Yuya Nishihara
hgweb: wrap {branches} and {entries} of branches with mappinggenerator...
r37932 def entries(context):
av6
hgweb: move branchentries code from webcommands to webutil
r26129 count = 0
if not tips:
for tag, hs, tip, closed in repo.branchmap().iterbranches():
tips.append((repo[tip], closed))
for ctx, closed in sorted(tips, key=sortkey, reverse=True):
if limit > 0 and count >= limit:
return
count += 1
if closed:
status = 'closed'
elif ctx.node() not in heads:
status = 'inactive'
else:
status = 'open'
yield {
timeless
py3: convert to next() function...
r29216 'parity': next(parity),
av6
hgweb: move branchentries code from webcommands to webutil
r26129 'branch': ctx.branch(),
'status': status,
'node': ctx.hex(),
'date': ctx.date()
}
Yuya Nishihara
hgweb: wrap {branches} and {entries} of branches with mappinggenerator...
r37932 return templateutil.mappinggenerator(entries)
av6
hgweb: move branchentries code from webcommands to webutil
r26129
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def cleanpath(repo, path):
path = path.lstrip('/')
Yuya Nishihara
hgweb: do not audit URL path as working-directory path...
r39507 auditor = pathutil.pathauditor(repo.root, realfs=False)
return pathutil.canonpath(repo.root, '', path, auditor=auditor)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
av6
style: adjust whitespaces in webutil.py...
r25999 def changectx(repo, req):
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 changeid = "tip"
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 if 'node' in req.qsparams:
changeid = req.qsparams['node']
av6
style: adjust whitespaces in webutil.py...
r25999 ipos = changeid.find(':')
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 if ipos != -1:
changeid = changeid[(ipos + 1):]
Martin von Zweigbergk
hgweb: use revsymbol() for creating context from changeid...
r37351 return scmutil.revsymbol(repo, changeid)
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991
def basechangectx(repo, req):
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 if 'node' in req.qsparams:
changeid = req.qsparams['node']
av6
style: adjust whitespaces in webutil.py...
r25999 ipos = changeid.find(':')
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 if ipos != -1:
changeid = changeid[:ipos]
Martin von Zweigbergk
hgweb: use revsymbol() for creating context from changeid...
r37351 return scmutil.revsymbol(repo, changeid)
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991
return None
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def filectx(repo, req):
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 if 'file' not in req.qsparams:
Ross Lagerwall
hgweb: avoid traceback when file or node parameters are missing...
r17289 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 path = cleanpath(repo, req.qsparams['file'])
if 'node' in req.qsparams:
changeid = req.qsparams['node']
elif 'filenode' in req.qsparams:
changeid = req.qsparams['filenode']
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 else:
Ross Lagerwall
hgweb: avoid traceback when file or node parameters are missing...
r17289 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 try:
Martin von Zweigbergk
hgweb: use revsymbol() for creating context from changeid...
r37351 fctx = scmutil.revsymbol(repo, changeid)[path]
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 fctx = repo.filectx(path, fileid=changeid)
return fctx
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 def linerange(req):
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 linerange = req.qsparams.getall('linerange')
Gregory Szorc
hgweb: perform all parameter lookup via qsparams...
r36881 if not linerange:
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 return None
if len(linerange) > 1:
raise ErrorResponse(HTTP_BAD_REQUEST,
'redundant linerange parameter')
try:
fromline, toline = map(int, linerange[0].split(':', 1))
except ValueError:
raise ErrorResponse(HTTP_BAD_REQUEST,
'invalid linerange parameter')
try:
return util.processlinerange(fromline, toline)
except error.ParseError as exc:
Augie Fackler
py3: get bytes-repr of network errors portably...
r36272 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665
def formatlinerange(fromline, toline):
return '%d:%d' % (fromline + 1, toline)
Yuya Nishihara
hgweb: wrap {succsandmarkers} with mappinggenerator...
r37933 def _succsandmarkersgen(context, mapping):
Yuya Nishihara
templatekw: switch obsfate-related template keywords to new API
r36612 repo = context.resource(mapping, 'repo')
Yuya Nishihara
templatekw: fix return type of {succsandmarkers} (BC)...
r37521 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
for item in itemmappings.tovalue(context, mapping):
av6
hgweb: link to successors of obsoleted changesets...
r35502 item['successors'] = _siblings(repo[successor]
for successor in item['successors'])
yield item
av6
hgweb: display fate of obsolete changesets...
r35501
Yuya Nishihara
hgweb: wrap {succsandmarkers} with mappinggenerator...
r37933 def succsandmarkers(context, mapping):
return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
Yuya Nishihara
templatekw: switch obsfate-related template keywords to new API
r36612 # teach templater succsandmarkers is switched to (context, mapping) API
Yuya Nishihara
templatekw: stop using _showlist() which is about to be deprecated...
r37087 succsandmarkers._requires = {'repo', 'ctx'}
Yuya Nishihara
templatekw: switch obsfate-related template keywords to new API
r36612
Yuya Nishihara
hgweb: wrap {whyunstable} with mappinggenerator...
r37934 def _whyunstablegen(context, mapping):
av6
hgweb: explain instabilities of unstable changesets
r36973 repo = context.resource(mapping, 'repo')
ctx = context.resource(mapping, 'ctx')
entries = obsutil.whyunstable(repo, ctx)
for entry in entries:
if entry.get('divergentnodes'):
entry['divergentnodes'] = _siblings(entry['divergentnodes'])
yield entry
Yuya Nishihara
hgweb: wrap {whyunstable} with mappinggenerator...
r37934 def whyunstable(context, mapping):
return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
Yuya Nishihara
templatekw: stop using _showlist() which is about to be deprecated...
r37087 whyunstable._requires = {'repo', 'ctx'}
av6
hgweb: explain instabilities of unstable changesets
r36973
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 def commonentry(repo, ctx):
Yuya Nishihara
hgweb: use scmutil.binnode() to translate None to wdir hash (issue5988)...
r39830 node = scmutil.binnode(ctx)
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 return {
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
# filectx, but I'm not pretty sure if that would always work because
# fctx.parents() != fctx.changectx.parents() for example.
'ctx': ctx,
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 'rev': ctx.rev(),
'node': hex(node),
'author': ctx.user(),
'desc': ctx.description(),
'date': ctx.date(),
'extra': ctx.extra(),
'phase': ctx.phasestr(),
av6
context: add obsolete() method to basefilectx...
r35087 'obsolete': ctx.obsolete(),
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 'succsandmarkers': succsandmarkers,
Yuya Nishihara
hgweb: wrap {instabilities} by hybridlist()...
r37935 'instabilities': templateutil.hybridlist(ctx.instabilities(),
name='instability'),
av6
hgweb: explain instabilities of unstable changesets
r36973 'whyunstable': whyunstable,
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 'branch': nodebranchnodefault(ctx),
'inbranch': nodeinbranch(repo, ctx),
'branches': nodebranchdict(repo, ctx),
'tags': nodetagsdict(repo, node),
'bookmarks': nodebookmarksdict(repo, node),
Matt Harbison
templater: drop support for old style keywords (API)...
r42524 'parent': lambda context, mapping: parents(ctx),
'child': lambda context, mapping: children(ctx),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 }
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 def changelistentry(web, ctx):
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745 '''Obtain a dictionary to be used for entries in a changelist.
This function is called when producing items for the "entries" list passed
to the "shortlog" and "changelog" templates.
'''
repo = web.repo
rev = ctx.rev()
Yuya Nishihara
hgweb: use scmutil.binnode() to translate None to wdir hash (issue5988)...
r39830 n = scmutil.binnode(ctx)
Yuya Nishihara
hgweb: drop tmpl argument from webutil.showtag() and showbookmark()...
r37931 showtags = showtag(repo, 'changelogtag', n)
Yuya Nishihara
hgweb: remove unused argument 'tmpl' from listfilediffs()
r37973 files = listfilediffs(ctx.files(), n, web.maxfiles)
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 entry = commonentry(repo, ctx)
Gregory Szorc
hgweb: ensure template mapping keys are bytes...
r41356 entry.update({
Matt Harbison
templater: drop support for old style keywords (API)...
r42524 'allparents': lambda context, mapping: parents(ctx),
'parent': lambda context, mapping: parents(ctx, rev - 1),
'child': lambda context, mapping: children(ctx, rev + 1),
Gregory Szorc
hgweb: ensure template mapping keys are bytes...
r41356 'changelogtag': showtags,
'files': files,
})
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 return entry
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745
Gregory Szorc
hgweb: extract code for emitting multiple changelist records...
r38054 def changelistentries(web, revs, maxcount, parityfn):
"""Emit up to N records for an iterable of revisions."""
repo = web.repo
count = 0
for rev in revs:
if count >= maxcount:
break
count += 1
entry = changelistentry(web, repo[rev])
entry['parity'] = next(parityfn)
yield entry
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 def symrevorshortnode(req, ctx):
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 if 'node' in req.qsparams:
return templatefilters.revescape(req.qsparams['node'])
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 else:
Yuya Nishihara
hgweb: use scmutil.binnode() to translate None to wdir hash (issue5988)...
r39830 return short(scmutil.binnode(ctx))
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602
Yuya Nishihara
hgweb: use template context to render {files} of changesetentry()...
r37970 def _listfilesgen(context, ctx, stripecount):
Yuya Nishihara
hgweb: extract generator of {files} from changesetentry()...
r37968 parity = paritygen(stripecount)
for blockno, f in enumerate(ctx.files()):
template = 'filenodelink' if f in ctx else 'filenolink'
Yuya Nishihara
hgweb: use template context to render {files} of changesetentry()...
r37970 yield context.process(template, {
Yuya Nishihara
hgweb: extract generator of {files} from changesetentry()...
r37968 'node': ctx.hex(),
'file': f,
'blockno': blockno + 1,
'parity': next(parity),
})
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 def changesetentry(web, ctx):
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 '''Obtain a dictionary to be used to render the "changeset" template.'''
Yuya Nishihara
hgweb: use scmutil.binnode() to translate None to wdir hash (issue5988)...
r39830 showtags = showtag(web.repo, 'changesettag', scmutil.binnode(ctx))
showbookmarks = showbookmark(web.repo, 'changesetbookmark',
scmutil.binnode(ctx))
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 showbranch = nodebranchnodefault(ctx)
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 basectx = basechangectx(web.repo, web.req)
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 if basectx is None:
basectx = ctx.p1()
Boris Feld
configitems: register the 'web.style' config
r34243 style = web.config('web', 'style')
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 if 'style' in web.req.qsparams:
style = web.req.qsparams['style']
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 diff = diffs(web, ctx, basectx, None, style)
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177
parity = paritygen(web.stripecount)
Yuya Nishihara
hgweb: pass ui to diffstatgen() explicitly
r38604 diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx)
Yuya Nishihara
hgweb: drop unused argument 'tmpl' from webutil.diffstat()
r38070 diffstats = diffstat(ctx, diffstatsgen, parity)
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177
return dict(
diff=diff,
Gregory Szorc
hgweb: pass modern request type into various webutil functions (API)...
r36902 symrev=symrevorshortnode(web.req, ctx),
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 basenode=basectx.hex(),
changesettag=showtags,
changesetbookmark=showbookmarks,
changesetbranch=showbranch,
Yuya Nishihara
hgweb: wrap {files} of changesetentry() with mappedgenerator...
r37969 files=templateutil.mappedgenerator(_listfilesgen,
Yuya Nishihara
hgweb: use template context to render {files} of changesetentry()...
r37970 args=(ctx, web.stripecount)),
Matt Harbison
templater: drop support for old style keywords (API)...
r42524 diffsummary=lambda context, mapping: diffsummary(diffstatsgen),
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 diffstat=diffstats,
archives=web.archivelist(ctx.hex()),
Pulkit Goyal
py3: use pycompat.strkwargs to convert kwargs keys to str...
r36452 **pycompat.strkwargs(commonentry(web.repo, ctx)))
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177
Yuya Nishihara
hgweb: use template context to render {files} of changelist entries...
r37972 def _listfilediffsgen(context, files, node, max):
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 for f in files[:max]:
Yuya Nishihara
hgweb: use template context to render {files} of changelist entries...
r37972 yield context.process('filedifflink', {'node': hex(node), 'file': f})
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 if len(files) > max:
Yuya Nishihara
hgweb: use template context to render {files} of changelist entries...
r37972 yield context.process('fileellipses', {})
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311
Yuya Nishihara
hgweb: remove unused argument 'tmpl' from listfilediffs()
r37973 def listfilediffs(files, node, max):
Yuya Nishihara
hgweb: wrap {files} of changelist entries with mappedgenerator...
r37971 return templateutil.mappedgenerator(_listfilediffsgen,
Yuya Nishihara
hgweb: use template context to render {files} of changelist entries...
r37972 args=(files, node, max))
Yuya Nishihara
hgweb: wrap {files} of changelist entries with mappedgenerator...
r37971
Yuya Nishihara
hgweb: use template context to render {lines} of {diff}...
r38006 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
Yuya Nishihara
hgweb: move prettyprintlines() closure out of diffs()...
r38004 for lineno, l in enumerate(lines, 1):
difflineno = "%d.%d" % (blockno, lineno)
if l.startswith('+'):
ltype = "difflineplus"
elif l.startswith('-'):
ltype = "difflineminus"
elif l.startswith('@'):
ltype = "difflineat"
else:
ltype = "diffline"
Yuya Nishihara
hgweb: use template context to render {lines} of {diff}...
r38006 yield context.process(ltype, {
Yuya Nishihara
hgweb: move prettyprintlines() closure out of diffs()...
r38004 'line': l,
'lineno': lineno,
'lineid': lineidprefix + "l%s" % difflineno,
'linenumber': "% 8s" % difflineno,
})
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 def _diffsgen(context, repo, ctx, basectx, files, style, stripecount,
linerange, lineidprefix):
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310 if files:
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 m = match.exact(files)
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310 else:
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 m = match.always()
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310
diffopts = patch.diffopts(repo.ui, untrusted=True)
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 parity = paritygen(stripecount)
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310
Martin von Zweigbergk
patch: pass in context objects into diffhunks() (API)...
r41767 diffhunks = patch.diffhunks(repo, basectx, ctx, m, opts=diffopts)
Denis Laxalde
diff: also yield file context objects in patch.trydiff() (API)...
r34856 for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1):
Denis Laxalde
hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm...
r31276 if style != 'raw':
header = header[1:]
lines = [h + '\n' for h in header]
for hunkrange, hunklines in hunks:
Denis Laxalde
hgweb: add a 'linerange' parameter to webutil.diffs()...
r31666 if linerange is not None and hunkrange is not None:
s1, l1, s2, l2 = hunkrange
Denis Laxalde
mdiff: add a hunkinrange helper function...
r31808 if not mdiff.hunkinrange((s2, l2), linerange):
Denis Laxalde
hgweb: add a 'linerange' parameter to webutil.diffs()...
r31666 continue
Denis Laxalde
hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm...
r31276 lines.extend(hunklines)
if lines:
Yuya Nishihara
hgweb: wrap {lines} of {diff} with mappedgenerator...
r38005 l = templateutil.mappedgenerator(_prettyprintdifflines,
Yuya Nishihara
hgweb: use template context to render {lines} of {diff}...
r38006 args=(lines, blockno,
Yuya Nishihara
hgweb: wrap {lines} of {diff} with mappedgenerator...
r38005 lineidprefix))
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 yield {
Yuya Nishihara
templater: use named function to expand template against mapping dict (API)...
r37037 'parity': next(parity),
'blockno': blockno,
Yuya Nishihara
hgweb: wrap {lines} of {diff} with mappedgenerator...
r38005 'lines': l,
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 }
def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''):
args = (web.repo, ctx, basectx, files, style, web.stripecount,
linerange, lineidprefix)
return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock')
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 def _compline(type, leftlineno, leftline, rightlineno, rightline):
Yuya Nishihara
hgweb: move compline() closure out of compare()
r38008 lineid = leftlineno and ("l%d" % leftlineno) or ''
lineid += rightlineno and ("r%d" % rightlineno) or ''
llno = '%d' % leftlineno if leftlineno else ''
rlno = '%d' % rightlineno if rightlineno else ''
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 return {
Yuya Nishihara
hgweb: move compline() closure out of compare()
r38008 'type': type,
'lineid': lineid,
'leftlineno': leftlineno,
'leftlinenumber': "% 6s" % llno,
'leftline': leftline or '',
'rightlineno': rightlineno,
'rightlinenumber': "% 6s" % rlno,
'rightline': rightline or '',
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 }
Yuya Nishihara
hgweb: move compline() closure out of compare()
r38008
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 def _getcompblockgen(context, leftlines, rightlines, opcodes):
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 for type, llo, lhi, rlo, rhi in opcodes:
Gregory Szorc
py3: convert diff opcode name to bytes...
r40192 type = pycompat.sysbytes(type)
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 len1 = lhi - llo
len2 = rhi - rlo
count = min(len1, len2)
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(count):
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 yield _compline(type=type,
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 leftlineno=llo + i + 1,
leftline=leftlines[llo + i],
rightlineno=rlo + i + 1,
rightline=rightlines[rlo + i])
if len1 > len2:
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(llo + count, lhi):
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 yield _compline(type=type,
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 leftlineno=i + 1,
leftline=leftlines[i],
rightlineno=None,
rightline=None)
elif len2 > len1:
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(rlo + count, rhi):
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 yield _compline(type=type,
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 leftlineno=None,
leftline=None,
rightlineno=i + 1,
rightline=rightlines[i])
wujek srujek
hgweb: side-by-side comparison functionality...
r17202
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 def _getcompblock(leftlines, rightlines, opcodes):
args = (leftlines, rightlines, opcodes)
return templateutil.mappinggenerator(_getcompblockgen, args=args,
name='comparisonline')
Yuya Nishihara
hgweb: convert {comparison} to a mappinggenerator with named template...
r38012 def _comparegen(context, contextnum, leftlines, rightlines):
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 '''Generator function that provides side-by-side comparison data.'''
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 s = difflib.SequenceMatcher(None, leftlines, rightlines)
Yuya Nishihara
hgweb: rename 'context' argument of webutil.compare() to avoid name conflicts...
r38011 if contextnum < 0:
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 l = _getcompblock(leftlines, rightlines, s.get_opcodes())
Yuya Nishihara
hgweb: convert {comparison} to a mappinggenerator with named template...
r38012 yield {'lines': l}
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 else:
Yuya Nishihara
hgweb: rename 'context' argument of webutil.compare() to avoid name conflicts...
r38011 for oc in s.get_grouped_opcodes(n=contextnum):
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 l = _getcompblock(leftlines, rightlines, oc)
Yuya Nishihara
hgweb: convert {comparison} to a mappinggenerator with named template...
r38012 yield {'lines': l}
Yuya Nishihara
hgweb: drop unused argument 'tmpl' from webutil.compare()
r38013 def compare(contextnum, leftlines, rightlines):
Yuya Nishihara
hgweb: convert {comparison} to a mappinggenerator with named template...
r38012 args = (contextnum, leftlines, rightlines)
return templateutil.mappinggenerator(_comparegen, args=args,
name='comparisonblock')
wujek srujek
hgweb: side-by-side comparison functionality...
r17202
Yuya Nishihara
hgweb: pass ui to diffstatgen() explicitly
r38604 def diffstatgen(ui, ctx, basectx):
Steven Brown
web: provide diff summary to the changeset page...
r14570 '''Generator function that provides the diffstat data.'''
Steven Brown
web: provide diffstat to the changeset page...
r14490
Yuya Nishihara
hgweb: pass ui to diffstatgen() explicitly
r38604 diffopts = patch.diffopts(ui, {'noprefix': False})
Yuya Nishihara
hgweb: disable diff.noprefix option for diffstat...
r35445 stats = patch.diffstatdata(
Boris Feld
webutil: pass a diffopts object to context.diff
r38585 util.iterlines(ctx.diff(basectx, opts=diffopts)))
Steven Brown
web: provide diffstat to the changeset page...
r14490 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
Steven Brown
web: provide diff summary to the changeset page...
r14570 while True:
yield stats, maxname, maxtotal, addtotal, removetotal, binary
def diffsummary(statgen):
'''Return a short summary of the diff.'''
timeless
py3: convert to next() function...
r29216 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
Steven Brown
web: provide diff summary to the changeset page...
r14570 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
len(stats), addtotal, removetotal)
Yuya Nishihara
hgweb: use template context to render {diffstat}...
r38069 def _diffstattmplgen(context, ctx, statgen, parity):
timeless
py3: convert to next() function...
r29216 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
Steven Brown
web: include all files in the diffstat...
r14561 files = ctx.files()
Steven Brown
web: provide diffstat to the changeset page...
r14490
Steven Brown
web: include all files in the diffstat...
r14561 def pct(i):
if maxtotal == 0:
return 0
return (float(i) / maxtotal) * 100
Steven Brown
web: provide diffstat to the changeset page...
r14490
Steven Brown
web: provide the file number to the diffstat templates...
r14562 fileno = 0
Steven Brown
web: include all files in the diffstat...
r14561 for filename, adds, removes, isbinary in stats:
av6
hgweb: rewrite `template = A and B or C` to be a proper ternary operator
r35315 template = 'diffstatlink' if filename in files else 'diffstatnolink'
Steven Brown
web: include all files in the diffstat...
r14561 total = adds + removes
Steven Brown
web: provide the file number to the diffstat templates...
r14562 fileno += 1
Yuya Nishihara
hgweb: use template context to render {diffstat}...
r38069 yield context.process(template, {
Yuya Nishihara
templater: use named function to expand template against mapping dict (API)...
r37037 'node': ctx.hex(),
'file': filename,
'fileno': fileno,
'total': total,
'addpct': pct(adds),
'removepct': pct(removes),
'parity': next(parity),
})
Steven Brown
web: provide diffstat to the changeset page...
r14490
Yuya Nishihara
hgweb: drop unused argument 'tmpl' from webutil.diffstat()
r38070 def diffstat(ctx, statgen, parity):
Yuya Nishihara
hgweb: wrap {diffstat} with mappedgenerator...
r38068 '''Return a diffstat template for each file in the diff.'''
Yuya Nishihara
hgweb: use template context to render {diffstat}...
r38069 args = (ctx, statgen, parity)
Yuya Nishihara
hgweb: wrap {diffstat} with mappedgenerator...
r38068 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714 class sessionvars(templateutil.wrapped):
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 def __init__(self, vars, start='?'):
Yuya Nishihara
hgweb: prefix private variables of sessionvars with '_'
r37712 self._start = start
self._vars = vars
Yuya Nishihara
hgweb: make sessionvars class less dense
r37713
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 def __getitem__(self, key):
Yuya Nishihara
hgweb: prefix private variables of sessionvars with '_'
r37712 return self._vars[key]
Yuya Nishihara
hgweb: make sessionvars class less dense
r37713
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 def __setitem__(self, key, value):
Yuya Nishihara
hgweb: prefix private variables of sessionvars with '_'
r37712 self._vars[key] = value
Yuya Nishihara
hgweb: make sessionvars class less dense
r37713
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 def __copy__(self):
Yuya Nishihara
hgweb: prefix private variables of sessionvars with '_'
r37712 return sessionvars(copy.copy(self._vars), self._start)
Yuya Nishihara
hgweb: make sessionvars class less dense
r37713
Yuya Nishihara
templater: abstract ifcontains() over wrapped types...
r38286 def contains(self, context, mapping, item):
item = templateutil.unwrapvalue(context, mapping, item)
return item in self._vars
Yuya Nishihara
templater: promote getmember() to an interface of wrapped types
r38261 def getmember(self, context, mapping, key):
Yuya Nishihara
templater: resolve type of dict key in getmember()...
r38262 key = templateutil.unwrapvalue(context, mapping, key)
Yuya Nishihara
templater: promote getmember() to an interface of wrapped types
r38261 return self._vars.get(key)
Yuya Nishihara
templater: abstract min/max away...
r38284 def getmin(self, context, mapping):
raise error.ParseError(_('not comparable'))
def getmax(self, context, mapping):
raise error.ParseError(_('not comparable'))
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 def filter(self, context, mapping, select):
# implement if necessary
raise error.ParseError(_('not filterable'))
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714 def itermaps(self, context):
Yuya Nishihara
hgweb: prefix private variables of sessionvars with '_'
r37712 separator = self._start
for key, value in sorted(self._vars.iteritems()):
Augie Fackler
webutil: use pycompat.bytestr() instead of str()...
r34808 yield {'name': key,
'value': pycompat.bytestr(value),
'separator': separator,
}
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 separator = '&'
Augie Fackler
hgweb: fix hgweb_mod as well as hgwebdir_mod
r12691
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714 def join(self, context, mapping, sep):
# could be '{separator}{name}={value|urlescape}'
raise error.ParseError(_('not displayable without template'))
def show(self, context, mapping):
return self.join(context, '')
Yuya Nishihara
templater: abstract truth testing to fix {if(list_of_empty_strings)}...
r38308 def tobool(self, context, mapping):
return bool(self._vars)
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714 def tovalue(self, context, mapping):
return self._vars
Yuya Nishihara
hgweb: alias ui module as uimod...
r27007 class wsgiui(uimod.ui):
Augie Fackler
hgweb: fix hgweb_mod as well as hgwebdir_mod
r12691 # default termwidth breaks under mod_wsgi
def termwidth(self):
return 80
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162
def getwebsubs(repo):
websubtable = []
websubdefs = repo.ui.configitems('websub')
# we must maintain interhg backwards compatibility
websubdefs += repo.ui.configitems('interhg')
for key, pattern in websubdefs:
# grab the delimiter from the character after the "s"
Pulkit Goyal
py3: slice over bytes to prevent getting ascii values...
r36198 unesc = pattern[1:2]
Augie Fackler
cleanup: migrate from re.escape to stringutil.reescape...
r38494 delim = stringutil.reescape(unesc)
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162
# identify portions of the pattern, taking care to avoid escaped
# delimiters. the replace format and flags are optional, but
# delimiters are required.
match = re.match(
Pulkit Goyal
py3: add b'' to make sure regex pattern are bytes in hgweb/webutil.py...
r36201 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 % (delim, delim, delim), pattern)
if not match:
repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
% (key, pattern))
continue
# we need to unescape the delimiter for regexp and format
Pulkit Goyal
py3: add b'' to make sure regex pattern are bytes in hgweb/webutil.py...
r36201 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 regexp = delim_re.sub(unesc, match.group(1))
format = delim_re.sub(unesc, match.group(2))
# the pattern allows for 6 regexp flags, so set them if necessary
flagin = match.group(3)
flags = 0
if flagin:
for flag in flagin.upper():
flags |= re.__dict__[flag]
try:
regexp = re.compile(regexp, flags)
websubtable.append((regexp, format))
except re.error:
repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
% (key, regexp))
return websubtable
av6
hgweb: reuse graph node-related functions from templates...
r37928
def getgraphnode(repo, ctx):
return (templatekw.getgraphnodecurrent(repo, ctx) +
templatekw.getgraphnodesymbol(ctx))