##// END OF EJS Templates
auto-upgrade: add a test case with no permission to lock the repository...
auto-upgrade: add a test case with no permission to lock the repository This show the current behavior when the repository is unlockable. The current behavior is to abort, which is probably not great. Now that we have a proper test, we can think about the behavior we want in a later changeset. Differential Revision: https://phab.mercurial-scm.org/D12615

File last commit:

r49801:642e31cb default
r50091:1c233af9 default
Show More
webutil.py
943 lines | 26.9 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>
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 #
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
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 _
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 from ..node import hex, short
Gregory Szorc
py3: manually import pycompat.setattr where it is needed...
r43357 from ..pycompat import setattr
Yuya Nishihara
hgweb: use absolute_import
r27046
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
Augie Fackler
formatting: blacken the codebase...
r43346 from ..utils import stringutil
archivespecs = util.sortdict(
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'zip', (b'application/zip', b'zip', b'.zip', None)),
(b'gz', (b'application/x-gzip', b'tgz', b'.tar.gz', None)),
(b'bz2', (b'application/x-bzip2', b'tbz2', b'.tar.bz2', None)),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 )
Yuya Nishihara
hgweb: move archivespecs to webutil...
r37529
Yuya Nishihara
hgweb: forward archivelist() of hgweb to webutil...
r37532 def archivelist(ui, nodeid, url=None):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 allowed = ui.configlist(b'web', b'allow-archive', untrusted=True)
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531 archives = []
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for typ, spec in archivespecs.items():
Augie Fackler
formatting: blacken the codebase...
r43346 if typ in allowed or ui.configbool(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'web', b'allow' + typ, untrusted=True
Augie Fackler
formatting: blacken the codebase...
r43346 ):
archives.append(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 {
b'type': typ,
b'extension': spec[2],
b'node': nodeid,
b'url': url,
}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531
Yuya Nishihara
hgweb: wrap {archives} with mappinglist...
r37533 return templateutil.mappinglist(archives)
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 def up(p):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if p[0:1] != b"/":
p = b"/" + p
if p[-1:] == b"/":
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 p = p[:-1]
up = os.path.dirname(p)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if up == b"/":
return b"/"
return up + b"/"
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class revnav:
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
Augie Fackler
formatting: blacken the codebase...
r43346 return templateutil.mappinglist(
[
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'before': templateutil.mappinglist([]),
b'after': templateutil.mappinglist([]),
Augie Fackler
formatting: blacken the codebase...
r43346 },
]
)
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 navbefore = [{b'label': b'(%i)' % first, b'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:
Augie Fackler
formatting: blacken the codebase...
r43346 navafter.append(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 {b'label': b'+%d' % abs(rev - pos), b'node': self.hex(rev)}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
hgweb: generate revnav in two phase...
r18425 if 0 < rev < pos:
Augie Fackler
formatting: blacken the codebase...
r43346 navbefore.append(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 {b'label': b'-%d' % abs(rev - pos), b'node': self.hex(rev)}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 navafter.append({b'label': b'tip', b'node': b'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()
Augie Fackler
formatting: blacken the codebase...
r43346 return templateutil.mappinglist(
[
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'before': templateutil.mappinglist(navbefore),
b'after': templateutil.mappinglist(navafter),
Augie Fackler
formatting: blacken the codebase...
r43346 },
]
)
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)))
Augie Fackler
formatting: blacken the codebase...
r43346
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 = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'node': s.hex(),
b'rev': s.rev(),
b'user': s.user(),
b'date': s.date(),
b'description': s.description(),
b'branch': s.branch(),
Yuya Nishihara
hgweb: extract a generator function of _siblings class...
r37717 }
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if util.safehasattr(s, b'path'):
d[b'file'] = s.path()
Yuya Nishihara
hgweb: extract a generator function of _siblings class...
r37717 yield d
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: convert _siblings to a factory function of mappinggenerator...
r37718 def _siblings(siblings=None, hiderev=None):
if siblings is None:
siblings = []
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 siblings = [s for s in siblings if s.node() != s.repo().nullid]
Yuya Nishihara
hgweb: convert _siblings to a factory function of mappinggenerator...
r37718 if len(siblings) == 1 and siblings[0].rev() == hiderev:
siblings = []
return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 def difffeatureopts(req, ui, section):
Augie Fackler
formatting: blacken the codebase...
r43346 diffopts = diffutil.difffeatureopts(
ui, untrusted=True, section=section, whitespace=True
)
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for k in (
b'ignorews',
b'ignorewsamount',
b'ignorewseol',
b'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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 def annotate(req, fctx, ui):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 diffopts = difffeatureopts(req, ui, b'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
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: simplify parents/children generation code
r7671 def children(ctx, hide=None):
return _siblings(ctx.children(), hide)
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.mappinglist([{b'file': r[0], b'node': hex(r[1])}])
Yuya Nishihara
hgweb: wrap {rename} with mappinglist...
r37921 return templateutil.mappinglist([])
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def nodetagsdict(repo, node):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.hybridlist(repo.nodetags(node), name=b'name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596 def nodebookmarksdict(repo, node):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.hybridlist(repo.nodebookmarks(node), name=b'name')
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.hybridlist(branches, name=b'name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if branch != b'default' and branchnode != ctx.node():
Yuya Nishihara
hgweb: wrap {inbranch} by hybridlist()...
r37925 branches.append(branch)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.hybridlist(branches, name=b'name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def nodebranchnodefault(ctx):
branches = []
branch = ctx.branch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if branch != b'default':
Yuya Nishihara
hgweb: wrap {branch} and {changesetbranch} by hybridlist()...
r37926 branches.append(branch)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.hybridlist(branches, name=b'name')
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 def _nodenamesgen(context, f, node, name):
for t in f(node):
yield {name: t}
Augie Fackler
formatting: blacken the codebase...
r43346
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 def showtag(repo, t1, node=None):
if node is None:
node = repo.nullid
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = (repo.nodetags, node, b'tag')
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 def showbookmark(repo, t1, node=None):
if node is None:
node = repo.nullid
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = (repo.nodebookmarks, node, b'bookmark')
Yuya Nishihara
hgweb: wrap {changelogtag}, {changesettag}, and {changesetbookmark}...
r37930 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
Alexander Solovyov
hgweb: add display of bookmarks for changelog and changeset
r13596
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = b'closed'
av6
hgweb: move branchentries code from webcommands to webutil
r26129 elif ctx.node() not in heads:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = b'inactive'
av6
hgweb: move branchentries code from webcommands to webutil
r26129 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = b'open'
av6
hgweb: move branchentries code from webcommands to webutil
r26129 yield {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'parity': next(parity),
b'branch': ctx.branch(),
b'status': status,
b'node': ctx.hex(),
b'date': ctx.date(),
av6
hgweb: move branchentries code from webcommands to webutil
r26129 }
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
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def cleanpath(repo, path):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = path.lstrip(b'/')
Yuya Nishihara
hgweb: do not audit URL path as working-directory path...
r39507 auditor = pathutil.pathauditor(repo.root, realfs=False)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return pathutil.canonpath(repo.root, b'', path, auditor=auditor)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Augie Fackler
formatting: blacken the codebase...
r43346
av6
style: adjust whitespaces in webutil.py...
r25999 def changectx(repo, req):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 changeid = b"tip"
if b'node' in req.qsparams:
changeid = req.qsparams[b'node']
ipos = changeid.find(b':')
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 if ipos != -1:
Augie Fackler
formatting: blacken the codebase...
r43346 changeid = changeid[(ipos + 1) :]
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991
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
Augie Fackler
formatting: blacken the codebase...
r43346
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 def basechangectx(repo, req):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'node' in req.qsparams:
changeid = req.qsparams[b'node']
ipos = changeid.find(b':')
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
Augie Fackler
formatting: blacken the codebase...
r43346
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 def filectx(repo, req):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'file' not in req.qsparams:
raise ErrorResponse(HTTP_NOT_FOUND, b'file not given')
path = cleanpath(repo, req.qsparams[b'file'])
if b'node' in req.qsparams:
changeid = req.qsparams[b'node']
elif b'filenode' in req.qsparams:
changeid = req.qsparams[b'filenode']
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ErrorResponse(HTTP_NOT_FOUND, b'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
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 def linerange(req):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 linerange = req.qsparams.getall(b'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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ErrorResponse(HTTP_BAD_REQUEST, b'redundant linerange parameter')
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fromline, toline = map(int, linerange[0].split(b':', 1))
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 except ValueError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ErrorResponse(HTTP_BAD_REQUEST, b'invalid linerange parameter')
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 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
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 def formatlinerange(fromline, toline):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'%d:%d' % (fromline + 1, toline)
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: wrap {succsandmarkers} with mappinggenerator...
r37933 def _succsandmarkersgen(context, mapping):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo = context.resource(mapping, b'repo')
Yuya Nishihara
templatekw: fix return type of {succsandmarkers} (BC)...
r37521 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
for item in itemmappings.tovalue(context, mapping):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 item[b'successors'] = _siblings(
repo[successor] for successor in item[b'successors']
Augie Fackler
formatting: blacken the codebase...
r43346 )
av6
hgweb: link to successors of obsoleted changesets...
r35502 yield item
av6
hgweb: display fate of obsolete changesets...
r35501
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: wrap {succsandmarkers} with mappinggenerator...
r37933 def succsandmarkers(context, mapping):
return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
templatekw: switch obsfate-related template keywords to new API
r36612 # teach templater succsandmarkers is switched to (context, mapping) API
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 succsandmarkers._requires = {b'repo', b'ctx'}
Yuya Nishihara
templatekw: switch obsfate-related template keywords to new API
r36612
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: wrap {whyunstable} with mappinggenerator...
r37934 def _whyunstablegen(context, mapping):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo = context.resource(mapping, b'repo')
ctx = context.resource(mapping, b'ctx')
av6
hgweb: explain instabilities of unstable changesets
r36973
entries = obsutil.whyunstable(repo, ctx)
for entry in entries:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if entry.get(b'divergentnodes'):
entry[b'divergentnodes'] = _siblings(entry[b'divergentnodes'])
av6
hgweb: explain instabilities of unstable changesets
r36973 yield entry
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: wrap {whyunstable} with mappinggenerator...
r37934 def whyunstable(context, mapping):
return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 whyunstable._requires = {b'repo', b'ctx'}
av6
hgweb: explain instabilities of unstable changesets
r36973
Augie Fackler
formatting: blacken the codebase...
r43346
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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'ctx': ctx,
b'rev': ctx.rev(),
b'node': hex(node),
b'author': ctx.user(),
b'desc': ctx.description(),
b'date': ctx.date(),
b'extra': ctx.extra(),
b'phase': ctx.phasestr(),
b'obsolete': ctx.obsolete(),
b'succsandmarkers': succsandmarkers,
b'instabilities': templateutil.hybridlist(
ctx.instabilities(), name=b'instability'
Augie Fackler
formatting: blacken the codebase...
r43346 ),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'whyunstable': whyunstable,
b'branch': nodebranchnodefault(ctx),
b'inbranch': nodeinbranch(repo, ctx),
b'branches': nodebranchdict(repo, ctx),
b'tags': nodetagsdict(repo, node),
b'bookmarks': nodebookmarksdict(repo, node),
b'parent': lambda context, mapping: parents(ctx),
b'child': lambda context, mapping: children(ctx),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 }
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 def changelistentry(web, ctx):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Obtain a dictionary to be used for entries in a changelist.
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745
This function is called when producing items for the "entries" list passed
to the "shortlog" and "changelog" templates.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745 repo = web.repo
rev = ctx.rev()
Yuya Nishihara
hgweb: use scmutil.binnode() to translate None to wdir hash (issue5988)...
r39830 n = scmutil.binnode(ctx)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 showtags = showtag(repo, b'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)
Augie Fackler
formatting: blacken the codebase...
r43346 entry.update(
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'allparents': lambda context, mapping: parents(ctx),
b'parent': lambda context, mapping: parents(ctx, rev - 1),
b'child': lambda context, mapping: children(ctx, rev + 1),
b'changelogtag': showtags,
b'files': files,
Augie Fackler
formatting: blacken the codebase...
r43346 }
)
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
Augie Fackler
formatting: blacken the codebase...
r43346
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])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 entry[b'parity'] = next(parityfn)
Gregory Szorc
hgweb: extract code for emitting multiple changelist records...
r38054
yield entry
Augie Fackler
formatting: blacken the codebase...
r43346
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 def symrevorshortnode(req, ctx):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'node' in req.qsparams:
return templatefilters.revescape(req.qsparams[b'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
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Jordi Gutiérrez Hermoso
hgweb: add a status property to file list context...
r44115 filesadded = ctx.filesadded()
Yuya Nishihara
hgweb: extract generator of {files} from changesetentry()...
r37968 for blockno, f in enumerate(ctx.files()):
Jordi Gutiérrez Hermoso
hgweb: add a status property to file list context...
r44115 if f not in ctx:
status = b'removed'
elif f in filesadded:
status = b'added'
else:
status = b'modified'
template = b'filenolink' if status == b'removed' else b'filenodelink'
Augie Fackler
formatting: blacken the codebase...
r43346 yield context.process(
template,
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'node': ctx.hex(),
b'file': f,
b'blockno': blockno + 1,
b'parity': next(parity),
Jordi Gutiérrez Hermoso
hgweb: add a status property to file list context...
r44115 b'status': status,
Augie Fackler
formatting: blacken the codebase...
r43346 },
)
Yuya Nishihara
hgweb: extract generator of {files} from changesetentry()...
r37968
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.'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 showtags = showtag(web.repo, b'changesettag', scmutil.binnode(ctx))
Augie Fackler
formatting: blacken the codebase...
r43346 showbookmarks = showbookmark(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 web.repo, b'changesetbookmark', scmutil.binnode(ctx)
Augie Fackler
formatting: blacken the codebase...
r43346 )
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 style = web.config(b'web', b'style')
if b'style' in web.req.qsparams:
style = web.req.qsparams[b'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,
Augie Fackler
formatting: blacken the codebase...
r43346 files=templateutil.mappedgenerator(
_listfilesgen, 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()),
Augie Fackler
formatting: blacken the codebase...
r43346 **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]:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield context.process(b'filedifflink', {b'node': hex(node), b'file': f})
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 if len(files) > max:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield context.process(b'fileellipses', {})
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: remove unused argument 'tmpl' from listfilediffs()
r37973 def listfilediffs(files, node, max):
Augie Fackler
formatting: blacken the codebase...
r43346 return templateutil.mappedgenerator(
_listfilediffsgen, 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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 difflineno = b"%d.%d" % (blockno, lineno)
if l.startswith(b'+'):
ltype = b"difflineplus"
elif l.startswith(b'-'):
ltype = b"difflineminus"
elif l.startswith(b'@'):
ltype = b"difflineat"
Yuya Nishihara
hgweb: move prettyprintlines() closure out of diffs()...
r38004 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ltype = b"diffline"
Augie Fackler
formatting: blacken the codebase...
r43346 yield context.process(
ltype,
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'line': l,
b'lineno': lineno,
b'lineid': lineidprefix + b"l%s" % difflineno,
b'linenumber': b"% 8s" % difflineno,
Augie Fackler
formatting: blacken the codebase...
r43346 },
)
Yuya Nishihara
hgweb: move prettyprintlines() closure out of diffs()...
r38004
Augie Fackler
formatting: blacken the codebase...
r43346 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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if style != b'raw':
Denis Laxalde
hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm...
r31276 header = header[1:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lines = [h + b'\n' for h in header]
Denis Laxalde
hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm...
r31276 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:
Augie Fackler
formatting: blacken the codebase...
r43346 l = templateutil.mappedgenerator(
_prettyprintdifflines, args=(lines, blockno, lineidprefix)
)
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 yield {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'parity': next(parity),
b'blockno': blockno,
b'lines': l,
Yuya Nishihara
hgweb: convert {diff} to a mappinggenerator with named template...
r38007 }
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=b''):
Augie Fackler
formatting: blacken the codebase...
r43346 args = (
web.repo,
ctx,
basectx,
files,
style,
web.stripecount,
linerange,
lineidprefix,
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return templateutil.mappinggenerator(
_diffsgen, args=args, name=b'diffblock'
)
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 def _compline(type, leftlineno, leftline, rightlineno, rightline):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lineid = leftlineno and (b"l%d" % leftlineno) or b''
lineid += rightlineno and (b"r%d" % rightlineno) or b''
llno = b'%d' % leftlineno if leftlineno else b''
rlno = b'%d' % rightlineno if rightlineno else b''
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 return {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'type': type,
b'lineid': lineid,
b'leftlineno': leftlineno,
b'leftlinenumber': b"% 6s" % llno,
b'leftline': leftline or b'',
b'rightlineno': rightlineno,
b'rightlinenumber': b"% 6s" % rlno,
b'rightline': rightline or b'',
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010 }
Yuya Nishihara
hgweb: move compline() closure out of compare()
r38008
Augie Fackler
formatting: blacken the codebase...
r43346
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):
Augie Fackler
formatting: blacken the codebase...
r43346 yield _compline(
type=type,
leftlineno=llo + i + 1,
leftline=leftlines[llo + i],
rightlineno=rlo + i + 1,
rightline=rightlines[rlo + i],
)
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 if len1 > len2:
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(llo + count, lhi):
Augie Fackler
formatting: blacken the codebase...
r43346 yield _compline(
type=type,
leftlineno=i + 1,
leftline=leftlines[i],
rightlineno=None,
rightline=None,
)
Yuya Nishihara
hgweb: move getblock() closure out of compare()...
r38009 elif len2 > len1:
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(rlo + count, rhi):
Augie Fackler
formatting: blacken the codebase...
r43346 yield _compline(
type=type,
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)
Augie Fackler
formatting: blacken the codebase...
r43346 return templateutil.mappinggenerator(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _getcompblockgen, args=args, name=b'comparisonline'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
hgweb: convert comparison {lines} to a mappinggenerator with named template...
r38010
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())
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield {b'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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield {b'lines': l}
Yuya Nishihara
hgweb: convert {comparison} to a mappinggenerator with named template...
r38012
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: blacken the codebase...
r43346 return templateutil.mappinggenerator(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _comparegen, args=args, name=b'comparisonblock'
Augie Fackler
formatting: blacken the codebase...
r43346 )
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 diffopts = patch.diffopts(ui, {b'noprefix': False})
Augie Fackler
formatting: blacken the codebase...
r43346 stats = patch.diffstatdata(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
Augie Fackler
formatting: blacken the codebase...
r43346
Steven Brown
web: provide diff summary to the changeset page...
r14570 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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return _(b' %d files changed, %d insertions(+), %d deletions(-)\n') % (
Augie Fackler
formatting: blacken the codebase...
r43346 len(stats),
addtotal,
removetotal,
)
Steven Brown
web: provide diff summary to the changeset page...
r14570
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 template = b'diffstatlink' if filename in files else b'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
Augie Fackler
formatting: blacken the codebase...
r43346 yield context.process(
template,
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'node': ctx.hex(),
b'file': filename,
b'fileno': fileno,
b'total': total,
b'addpct': pct(adds),
b'removepct': pct(removes),
b'parity': next(parity),
Augie Fackler
formatting: blacken the codebase...
r43346 },
)
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)
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714 class sessionvars(templateutil.wrapped):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def __init__(self, vars, start=b'?'):
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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b'not comparable'))
Yuya Nishihara
templater: abstract min/max away...
r38284
def getmax(self, context, mapping):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b'not comparable'))
Yuya Nishihara
templater: abstract min/max away...
r38284
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467 def filter(self, context, mapping, select):
# implement if necessary
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b'not filterable'))
Yuya Nishihara
templater: introduce filter() function to remove empty items from list...
r38467
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
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for key, value in sorted(self._vars.items()):
Augie Fackler
formatting: blacken the codebase...
r43346 yield {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'name': key,
b'value': pycompat.bytestr(value),
b'separator': separator,
Augie Fackler
webutil: use pycompat.bytestr() instead of str()...
r34808 }
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 separator = b'&'
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}'
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b'not displayable without template'))
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714
def show(self, context, mapping):
Matt Harbison
webutil: add missing argument to join()...
r44159 return self.join(context, mapping, b'')
Yuya Nishihara
hgweb: lift {sessionvars} to a wrapped type...
r37714
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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 def getwebsubs(repo):
websubtable = []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 websubdefs = repo.ui.configitems(b'websub')
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 # we must maintain interhg backwards compatibility
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 websubdefs += repo.ui.configitems(b'interhg')
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 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])*$'
Augie Fackler
formatting: blacken the codebase...
r43346 % (delim, delim, delim),
pattern,
)
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 if not match:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"websub: invalid pattern for %s: %s\n") % (key, pattern)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 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:
Connor Sheehan
hgweb: fix websub regex flag syntax on Python 3...
r43189 for flag in pycompat.sysstr(flagin.upper()):
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 flags |= re.__dict__[flag]
try:
regexp = re.compile(regexp, flags)
websubtable.append((regexp, format))
except re.error:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"websub: invalid regexp for %s: %s\n") % (key, regexp)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 return websubtable
av6
hgweb: reuse graph node-related functions from templates...
r37928
Augie Fackler
formatting: blacken the codebase...
r43346
av6
hgweb: reuse graph node-related functions from templates...
r37928 def getgraphnode(repo, ctx):
Augie Fackler
formatting: blacken the codebase...
r43346 return templatekw.getgraphnodecurrent(
Martin von Zweigbergk
graphlog: use '%' for other context in merge conflict...
r44819 repo, ctx, {}
Augie Fackler
formatting: blacken the codebase...
r43346 ) + templatekw.getgraphnodesymbol(ctx)