##// END OF EJS Templates
hgweb: rename 'context' argument of webutil.compare() to avoid name conflicts...
hgweb: rename 'context' argument of webutil.compare() to avoid name conflicts The meaning of 'context' depends on context. Here it is the number of the context lines in unified diff.

File last commit:

r38011:4e407c7b default
r38011:4e407c7b default
Show More
webutil.py
759 lines | 24.4 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,
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):
Yuya Nishihara
hgweb: move archivelist() of hgwebdir to webutil
r37531 allowed = ui.configlist('web', 'allow_archive', untrusted=True)
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):
Jun Wu
hgweb: make fctx.annotate a separated function so it could be wrapped...
r30081 diffopts = patch.difffeatureopts(ui, untrusted=True,
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 section=section, whitespace=True)
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('/')
Augie Fackler
pathutil: tease out a new library to break an import cycle from canonpath use
r20033 return pathutil.canonpath(repo.root, '', path)
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):
node = ctx.node()
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),
'parent': lambda **x: parents(ctx),
'child': lambda **x: children(ctx),
}
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()
n = ctx.node()
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)
entry.update(
av6
hgweb: add parents to json-log (issue5074)...
r28709 allparents=lambda **x: parents(ctx),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 parent=lambda **x: parents(ctx, rev - 1),
child=lambda **x: children(ctx, rev + 1),
changelogtag=showtags,
files=files,
)
return entry
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745
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:
return short(ctx.node())
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: drop tmpl argument from webutil.showtag() and showbookmark()...
r37931 showtags = showtag(web.repo, 'changesettag', ctx.node())
showbookmarks = showbookmark(web.repo, 'changesetbookmark', ctx.node())
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)
diffstatsgen = diffstatgen(ctx, basectx)
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 diffstats = diffstat(web.tmpl, 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)),
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 diffsummary=lambda **x: diffsummary(diffstatsgen),
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:
m = match.exact(repo.root, repo.getcwd(), files)
else:
m = match.always(repo.root, repo.getcwd())
diffopts = patch.diffopts(repo.ui, untrusted=True)
Denis Laxalde
hgweb: explictly pass basectx in webutil.diffs...
r31082 node1 = basectx.node()
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310 node2 = ctx.node()
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
Denis Laxalde
hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm...
r31276 diffhunks = patch.diffhunks(repo, node1, node2, 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:
len1 = lhi - llo
len2 = rhi - rlo
count = min(len1, len2)
for i in 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:
for i in 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:
for i in 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: rename 'context' argument of webutil.compare() to avoid name conflicts...
r38011 def compare(tmpl, 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: move getblock() closure out of compare()...
r38009 yield tmpl.generate('comparisonblock', {'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: move getblock() closure out of compare()...
r38009 yield tmpl.generate('comparisonblock', {'lines': l})
wujek srujek
hgweb: side-by-side comparison functionality...
r17202
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 def diffstatgen(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: disable diff.noprefix option for diffstat...
r35445 stats = patch.diffstatdata(
util.iterlines(ctx.diff(basectx, noprefix=False)))
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)
def diffstat(tmpl, ctx, statgen, parity):
'''Return a diffstat template for each file in the diff.'''
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
templater: use named function to expand template against mapping dict (API)...
r37037 yield tmpl.generate(template, {
'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: 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
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, '')
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]
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 delim = re.escape(unesc)
# 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))