##// END OF EJS Templates
dirstate: add prefix and suffix arguments to backup...
dirstate: add prefix and suffix arguments to backup This would allow the code explicitly copying dirstate to use this method instead. Use of this method will increase encapsulation (the dirstate class will be sole owner of its on-disk storage).

File last commit:

r28712:80e92247 default
r29189:930d4ee4 default
Show More
webcommands.py
1304 lines | 40.0 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 #
# 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
split out hgweb commands into a separate file, move some code around
r5591
Yuya Nishihara
hgweb: use absolute_import
r27046 from __future__ import absolute_import
import cgi
import copy
import mimetypes
import os
import re
from ..i18n import _
from ..node import hex, short
from .common import (
ErrorResponse,
HTTP_FORBIDDEN,
HTTP_NOT_FOUND,
HTTP_OK,
get_contact,
paritygen,
staticfile,
)
from .. import (
archival,
encoding,
error,
graphmod,
patch,
revset,
scmutil,
templatefilters,
templater,
util,
)
from . import (
webutil,
)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 __all__ = []
Gregory Szorc
webcommands: define a dict of available commands...
r24077 commands = {}
Gregory Szorc
webcommands: define web commands using a decorator...
r24076
class webcommand(object):
"""Decorator used to register a web command handler.
The decorator takes as its positional arguments the name/path the
command should be accessible under.
Usage:
Dirkjan Ochtman
hgweb: explicitly check if requested command exists
r5963
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('mycommand')
def mycommand(web, req, tmpl):
pass
"""
Dirkjan Ochtman
hgweb: explicitly check if requested command exists
r5963
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 def __init__(self, name):
self.name = name
def __call__(self, func):
__all__.append(self.name)
Gregory Szorc
webcommands: define a dict of available commands...
r24077 commands[self.name] = func
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 return func
@webcommand('log')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def log(web, req, tmpl):
Gregory Szorc
webcommands: document "log" web command
r24087 """
/log[/{revision}[/{path}]]
--------------------------
Show repository or file history.
For URLs of the form ``/log/{revision}``, a list of changesets starting at
the specified changeset identifier is shown. If ``{revision}`` is not
defined, the default is ``tip``. This form is equivalent to the
``changelog`` handler.
For URLs of the form ``/log/{revision}/{file}``, the history for a specific
file will be shown. This form is equivalent to the ``filelog`` handler.
"""
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'file' in req.form and req.form['file'][0]:
Dirkjan Ochtman
hgweb: centralize req.write() calls
r5964 return filelog(web, req, tmpl)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 else:
Dirkjan Ochtman
hgweb: centralize req.write() calls
r5964 return changelog(web, req, tmpl)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('rawfile')
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890 def rawfile(web, req, tmpl):
Matt Mackall
hgweb: raw file mimetype guessing configurable, off by default (BC) (issue2923)...
r15004 guessmime = web.configbool('web', 'guessmime', False)
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890 if not path:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 content = manifest(web, req, tmpl)
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, web.ctype)
return content
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
try:
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 fctx = webutil.filectx(web.repo, req)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.LookupError as inst:
Dirkjan Ochtman
hgweb: better error messages
r6368 try:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 content = manifest(web, req, tmpl)
Dirkjan Ochtman
hgweb: better error messages
r6368 req.respond(HTTP_OK, web.ctype)
return content
except ErrorResponse:
raise inst
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
path = fctx.path()
text = fctx.data()
Matt Mackall
hgweb: raw file mimetype guessing configurable, off by default (BC) (issue2923)...
r15004 mt = 'application/binary'
if guessmime:
mt = mimetypes.guess_type(path)[0]
if mt is None:
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if util.binary(text):
mt = 'application/binary'
else:
mt = 'text/plain'
Julian Cowley
hgweb: specify a charset when sending raw text files...
r11332 if mt.startswith('text/'):
mt += '; charset="%s"' % encoding.encoding
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 req.respond(HTTP_OK, mt, path, body=text)
return []
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 def _filerevision(web, req, tmpl, fctx):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 f = fctx.path()
text = fctx.data()
parity = paritygen(web.stripecount)
Alexander Plavin
hgweb: import the whole util module in webcommands instead of just one function...
r19657 if util.binary(text):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
text = '(binary:%s)' % mt
def lines():
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 for lineno, t in enumerate(text.splitlines(True)):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 yield {"line": t,
"lineid": "l%d" % (lineno + 1),
"linenumber": "% 6d" % (lineno + 1),
"parity": parity.next()}
return tmpl("filerevision",
file=f,
path=webutil.up(f),
text=lines(),
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=webutil.symrevorshortnode(req, fctx),
Matt Mackall
hgweb: minor improvements for new web style...
r6434 rename=webutil.renamelink(fctx),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 permissions=fctx.manifest().flags(f),
**webutil.commonentry(web.repo, fctx))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('file')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def file(web, req, tmpl):
Gregory Szorc
webcommands: document "file" web command
r24088 """
/file/{revision}[/{path}]
-------------------------
Show information about a directory or file in the repository.
Info about the ``path`` given as a URL parameter will be rendered.
If ``path`` is a directory, information about the entries in that
directory will be rendered. This form is equivalent to the ``manifest``
handler.
If ``path`` is a file, information about that file will be shown via
the ``filerevision`` template.
If ``path`` is not defined, information about the root directory will
be rendered.
"""
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
Benoit Boissinot
hgweb: do not use unassigned variables in exception handling
r6853 if not path:
Patrick Mezard
Merge with crew-stable
r6857 return manifest(web, req, tmpl)
Benoit Boissinot
hgweb: do not use unassigned variables in exception handling
r6853 try:
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.LookupError as inst:
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 try:
Patrick Mezard
Merge with crew-stable
r6857 return manifest(web, req, tmpl)
Benoit Boissinot
hgweb: do not use unassigned variables in exception handling
r6853 except ErrorResponse:
raise inst
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247 def _search(web, req, tmpl):
Alexander Plavin
hgweb: add string constants for search mode names...
r19656 MODE_REVISION = 'rev'
MODE_KEYWORD = 'keyword'
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 MODE_REVSET = 'revset'
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247
Alexander Plavin
hgweb: search() function supports direct pointing to revision...
r19633 def revsearch(ctx):
yield ctx
Alexander Plavin
hgweb: pass arguments which a function depends on explicitly in search...
r19632 def keywordsearch(query):
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize string in hgweb search query...
r15727 lower = encoding.lower
qw = lower(query).split()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
def revgen():
Pierre-Yves David
hgweb: prevent traceback during search when filtered (issue3783)...
r18497 cl = web.repo.changelog
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 for i in xrange(len(web.repo) - 1, 0, -100):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 l = []
Alexander Plavin
hgweb: fix duplication for some search queries...
r19491 for j in cl.revs(max(0, i - 99), i):
Matt Mackall
use repo[changeid] to get a changectx
r6747 ctx = web.repo[j]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 l.append(ctx)
l.reverse()
for e in l:
yield e
for ctx in revgen():
miss = 0
for q in qw:
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize string in hgweb search query...
r15727 if not (q in lower(ctx.user()) or
q in lower(ctx.description()) or
q in lower(" ".join(ctx.files()))):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 miss = 1
break
if miss:
continue
Alexander Plavin
hgweb: separate search itself and template generation...
r19533 yield ctx
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 def revsetsearch(revs):
for r in revs:
yield web.repo[r]
Alexander Plavin
hgweb: add dynamic search function selection, depending on the query...
r19631 searchfuncs = {
Wagner Bruna
hgweb, i18n: do not translate search mode description...
r20004 MODE_REVISION: (revsearch, 'exact revision search'),
MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
MODE_REVSET: (revsetsearch, 'revset expression search'),
Alexander Plavin
hgweb: add dynamic search function selection, depending on the query...
r19631 }
Alexander Plavin
hgweb: pass arguments which a function depends on explicitly in search...
r19632 def getsearchmode(query):
Alexander Plavin
hgweb: search() function supports direct pointing to revision...
r19633 try:
ctx = web.repo[query]
except (error.RepoError, error.LookupError):
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 # query is not an exact revision pointer, need to
Mads Kiilerich
spelling: random spell checker fixes
r19951 # decide if it's a revset expression or keywords
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 pass
Alexander Plavin
hgweb: search() function supports direct pointing to revision...
r19633 else:
Alexander Plavin
hgweb: add string constants for search mode names...
r19656 return MODE_REVISION, ctx
Alexander Plavin
hgweb: add dynamic search function selection, depending on the query...
r19631
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 revdef = 'reverse(%s)' % query
try:
Yuya Nishihara
revset: move validation of incomplete parsing to parse() function...
r25251 tree = revset.parse(revdef)
Yuya Nishihara
hgweb: unify import style of error classes...
r27009 except error.ParseError:
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 # can't parse to a revset tree
return MODE_KEYWORD, query
if revset.depth(tree) <= 2:
# no revset syntax used
return MODE_KEYWORD, query
Augie Fackler
cleanup: use __builtins__.any instead of util.any...
r25149 if any((token, (value or '')[:3]) == ('string', 're:')
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 for token, value, pos in revset.tokenize(revdef)):
return MODE_KEYWORD, query
funcsused = revset.funcsused(tree)
if not funcsused.issubset(revset.safesymbols):
return MODE_KEYWORD, query
mfunc = revset.match(web.repo.ui, revdef)
try:
Yuya Nishihara
revset: make match function initiate query from full set by default...
r24114 revs = mfunc(web.repo)
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 return MODE_REVSET, revs
# ParseError: wrongly placed tokens, wrongs arguments, etc
# RepoLookupError: no such revision, e.g. in 'revision:'
# Abort: bookmark/tag not exists
# LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
Yuya Nishihara
hgweb: unify import style of error classes...
r27009 except (error.ParseError, error.RepoLookupError, error.Abort,
LookupError):
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 return MODE_KEYWORD, query
Alexander Plavin
hgweb: separate search itself and template generation...
r19533 def changelist(**map):
count = 0
Alexander Plavin
hgweb: pass variable with current search mode name to the search template
r19765 for ctx in searchfunc[0](funcarg):
Andrew Beekhof
webcommands: fix increments lost by 894875eae49b
r6659 count += 1
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 n = ctx.node()
showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
yield tmpl('searchentry',
parity=parity.next(),
changelogtag=showtags,
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 files=files,
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 **webutil.commonentry(web.repo, ctx))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247 if count >= revcount:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 break
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418 query = req.form['rev'][0]
revcount = web.maxchanges
if 'revcount' in req.form:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
revcount = int(req.form.get('revcount', [revcount])[0])
revcount = max(revcount, 1)
tmpl.defaults['sessionvars']['revcount'] = revcount
except ValueError:
pass
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418
lessvars = copy.copy(tmpl.defaults['sessionvars'])
lessvars['revcount'] = max(revcount / 2, 1)
lessvars['rev'] = query
morevars = copy.copy(tmpl.defaults['sessionvars'])
morevars['revcount'] = revcount * 2
morevars['rev'] = query
Alexander Plavin
hgweb: pass arguments which a function depends on explicitly in search...
r19632 mode, funcarg = getsearchmode(query)
Alexander Plavin
hgweb: add link to force literal keyword search...
r19768
if 'forcekw' in req.form:
showforcekw = ''
showunforcekw = searchfuncs[mode][1]
mode = MODE_KEYWORD
funcarg = query
else:
if mode != MODE_KEYWORD:
showforcekw = searchfuncs[MODE_KEYWORD][1]
else:
showforcekw = ''
showunforcekw = ''
Alexander Plavin
hgweb: add dynamic search function selection, depending on the query...
r19631 searchfunc = searchfuncs[mode]
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 tip = web.repo['tip']
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 parity = paritygen(web.stripecount)
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247 entries=changelist, archives=web.archivelist("tip"),
Alexander Plavin
hgweb: pass variable with current search mode name to the search template
r19765 morevars=morevars, lessvars=lessvars,
Alexander Plavin
hgweb: add link to force literal keyword search...
r19768 modedesc=searchfunc[1],
showforcekw=showforcekw, showunforcekw=showunforcekw)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('changelog')
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247 def changelog(web, req, tmpl, shortlog=False):
Gregory Szorc
webcommands: document "changelog" web command
r24089 """
/changelog[/{revision}]
-----------------------
Show information about multiple changesets.
If the optional ``revision`` URL argument is absent, information about
all changesets starting at ``tip`` will be rendered. If the ``revision``
argument is present, changesets will be shown starting from the specified
revision.
If ``revision`` is absent, the ``rev`` query string argument may be
defined. This will perform a search for changesets.
The argument for ``rev`` can be a single revision, a revision set,
or a literal keyword to search for in changeset data (equivalent to
Wagner Bruna
webcommands: fix typo in changelog documentation
r24867 :hg:`log -k`).
Gregory Szorc
webcommands: document "changelog" web command
r24089
The ``revcount`` query string argument defines the maximum numbers of
changesets to render.
For non-searches, the ``changelog`` template will be rendered.
"""
Dirkjan Ochtman
hgweb: add less/more links for search logs (issue1972)
r10247
Alexander Plavin
hgweb: show current search query in the input field
r19396 query = ''
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'node' in req.form:
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 ctx = webutil.changectx(web.repo, req)
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev = webutil.symrevorshortnode(req, ctx)
Alexander Plavin
hgweb: cleaner if conditions in changelog() function...
r19534 elif 'rev' in req.form:
Alexander Plavin
hgweb: always run search when a query is entered (bc)...
r19634 return _search(web, req, tmpl)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 else:
Alexander Plavin
hgweb: cleaner if conditions in changelog() function...
r19534 ctx = web.repo['tip']
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev = 'tip'
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Alexander Plavin
hgweb: always compute all entries and latestentry in changelog...
r19737 def changelist():
Pierre-Yves David
hgweb: use changelog for iteration...
r18427 revs = []
Alexander Plavin
hgweb: fix incorrect way to count revisions in log (issue3977)...
r19486 if pos != -1:
revs = web.repo.changelog.revs(pos, 0)
curcount = 0
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745 for rev in revs:
Alexander Plavin
hgweb: fix incorrect way to count revisions in log (issue3977)...
r19486 curcount += 1
Alexander Plavin
hgweb: add nextentry variable for easy pagination in changelog...
r19738 if curcount > revcount + 1:
Alexander Plavin
hgweb: fix incorrect way to count revisions in log (issue3977)...
r19486 break
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745
entry = webutil.changelistentry(web, web.repo[rev], tmpl)
entry['parity'] = parity.next()
yield entry
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if shortlog:
revcount = web.maxshortchanges
else:
revcount = web.maxchanges
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 if 'revcount' in req.form:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
revcount = int(req.form.get('revcount', [revcount])[0])
revcount = max(revcount, 1)
tmpl.defaults['sessionvars']['revcount'] = revcount
except ValueError:
pass
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246
lessvars = copy.copy(tmpl.defaults['sessionvars'])
Md. O. Shayan
hgweb: set minimum number of revision to display to 1 when revcount is 0...
r13931 lessvars['revcount'] = max(revcount / 2, 1)
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 morevars = copy.copy(tmpl.defaults['sessionvars'])
morevars['revcount'] = revcount * 2
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 count = len(web.repo)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 pos = ctx.rev()
Alexander Plavin
hgweb: fix incorrect way to count revisions in log (issue3977)...
r19486 parity = paritygen(web.stripecount)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Alexander Plavin
hgweb: always compute all entries and latestentry in changelog...
r19737 entries = list(changelist())
latestentry = entries[:1]
Alexander Plavin
hgweb: add nextentry variable for easy pagination in changelog...
r19738 if len(entries) > revcount:
nextentry = entries[-1:]
entries = entries[:-1]
else:
nextentry = []
Alexander Plavin
hgweb: always compute all entries and latestentry in changelog...
r19737
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
Alexander Plavin
hgweb: always compute all entries and latestentry in changelog...
r19737 entries=entries,
Alexander Plavin
hgweb: add nextentry variable for easy pagination in changelog...
r19738 latestentry=latestentry, nextentry=nextentry,
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 archives=web.archivelist("tip"), revcount=revcount,
Alexander Plavin
hgweb: show current search query in the input field
r19396 morevars=morevars, lessvars=lessvars, query=query)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('shortlog')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def shortlog(web, req, tmpl):
Gregory Szorc
webcommands: document "shortlog" web command
r24086 """
/shortlog
---------
Show basic information about a set of changesets.
This accepts the same parameters as the ``changelog`` handler. The only
difference is the ``shortlog`` template will be rendered instead of the
``changelog`` template.
"""
Mads Kiilerich
check-code: check for spaces around = for named parameters
r19872 return changelog(web, req, tmpl, shortlog=True)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('changeset')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def changeset(web, req, tmpl):
Gregory Szorc
webcommands: document "changeset" web command
r24085 """
/changeset[/{revision}]
-----------------------
Show information about a single changeset.
A URL path argument is the changeset identifier to show. See ``hg help
revisions`` for possible values. If not defined, the ``tip`` changeset
will be shown.
The ``changeset`` template is rendered. Contents of the ``changesettag``,
``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
templates related to diffs may all be used to produce the output.
"""
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 ctx = webutil.changectx(web.repo, req)
Gregory Szorc
hgweb: extract changeset template mapping generation to own function...
r24177 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 rev = webcommand('rev')(changeset)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Martin Geisler
hgweb: add hook for remapping repository path into virtual paths...
r16448 def decodepath(path):
"""Hook for mapping a path in the repository to a path in the
working copy.
Extensions (e.g., largefiles) can override this to remap files in
the virtual file system presented by the manifest command below."""
return path
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('manifest')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def manifest(web, req, tmpl):
Gregory Szorc
webcommands: document "manifest" web command
r24090 """
/manifest[/{revision}[/{path}]]
-------------------------------
Show information about a directory.
Wagner Bruna
webcommands: fix description of manifest default behavior
r24868 If the URL path arguments are omitted, information about the root
Gregory Szorc
webcommands: document "manifest" web command
r24090 directory for the ``tip`` changeset will be shown.
Because this handler can only show information for directories, it
is recommended to use the ``file`` handler instead, as it can handle both
directories and files.
The ``manifest`` template will be rendered for this handler.
"""
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 if 'node' in req.form:
ctx = webutil.changectx(web.repo, req)
symrev = webutil.symrevorshortnode(req, ctx)
else:
ctx = web.repo['tip']
symrev = 'tip'
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
mf = ctx.manifest()
node = ctx.node()
files = {}
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 dirs = {}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 parity = paritygen(web.stripecount)
if path and path[-1] != "/":
path += "/"
l = len(path)
abspath = "/" + path
Martin Geisler
hgweb: add hook for remapping repository path into virtual paths...
r16448 for full, n in mf.iteritems():
# the virtual path (working copy path) used for the full
# (repository) path
f = decodepath(full)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 if f[:l] != path:
continue
remain = f[l:]
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 elements = remain.split('/')
if len(elements) == 1:
Martin Geisler
hgweb: add hook for remapping repository path into virtual paths...
r16448 files[remain] = full
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 else:
h = dirs # need to retain ref to dirs (root)
for elem in elements[0:-1]:
if elem not in h:
h[elem] = {}
h = h[elem]
if len(h) > 1:
break
h[None] = None # denotes files present
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Dirkjan Ochtman
hgweb: fix problems with empty repositories
r7565 if mf and not files and not dirs:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
def filelist(**map):
Matt Mackall
replace util.sort with sorted built-in...
r8209 for f in sorted(files):
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 full = files[f]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
fctx = ctx.filectx(full)
yield {"file": full,
"parity": parity.next(),
"basename": f,
Matt Mackall
use repo[changeid] to get a changectx
r6747 "date": fctx.date(),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "size": fctx.size(),
"permissions": mf.flags(full)}
def dirlist(**map):
Matt Mackall
replace util.sort with sorted built-in...
r8209 for d in sorted(dirs):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 emptydirs = []
h = dirs[d]
while isinstance(h, dict) and len(h) == 1:
Matt Mackall
many, many trivial check-code fixups
r10282 k, v = h.items()[0]
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 if v:
emptydirs.append(k)
h = v
path = "%s%s" % (abspath, d)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 yield {"parity": parity.next(),
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 "path": path,
"emptydirs": "/".join(emptydirs),
"basename": d}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
return tmpl("manifest",
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=symrev,
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 path=abspath,
up=webutil.up(abspath),
upparity=parity.next(),
fentries=filelist,
dentries=dirlist,
archives=web.archivelist(hex(node)),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 **webutil.commonentry(web.repo, ctx))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('tags')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def tags(web, req, tmpl):
Gregory Szorc
webcommands: document "tags" web command
r24084 """
/tags
-----
Show information about tags.
No arguments are accepted.
The ``tags`` template is rendered.
"""
Matt Mackall
hgweb: fix iterator reuse in atom feed generation
r18029 i = list(reversed(web.repo.tagslist()))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 parity = paritygen(web.stripecount)
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 def entries(notip, latestonly, **map):
t = i
if notip:
t = [(k, n) for k, n in i if k != "tip"]
if latestonly:
t = t[:1]
for k, n in t:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 yield {"parity": parity.next(),
"tag": k,
Matt Mackall
use repo[changeid] to get a changectx
r6747 "date": web.repo[n].date(),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "node": hex(n)}
return tmpl("tags",
node=hex(web.repo.changelog.tip()),
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 entries=lambda **x: entries(False, False, **x),
entriesnotip=lambda **x: entries(True, False, **x),
latestentry=lambda **x: entries(True, True, **x))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('bookmarks')
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597 def bookmarks(web, req, tmpl):
Gregory Szorc
webcommands: document "bookmarks" web command
r24083 """
/bookmarks
----------
Show information about bookmarks.
No arguments are accepted.
The ``bookmarks`` template is rendered.
"""
Kevin Bullock
hgweb: don't attempt to show hidden bookmarks (issue3774)...
r18478 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
av6
hgweb: sort bookmarks in revlog order of their nodes...
r28711 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
i = sorted(i, key=sortkey, reverse=True)
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597 parity = paritygen(web.stripecount)
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 def entries(latestonly, **map):
av6
hgweb: sort bookmarks early...
r28710 t = i
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 if latestonly:
av6
hgweb: sort bookmarks early...
r28710 t = i[:1]
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 for k, n in t:
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597 yield {"parity": parity.next(),
"bookmark": k,
"date": web.repo[n].date(),
"node": hex(n)}
av6
hgweb: generate last change date for an empty atom-bookmarks feed (issue5022)...
r28712 if i:
latestrev = i[0][1]
else:
latestrev = -1
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597 return tmpl("bookmarks",
node=hex(web.repo.changelog.tip()),
av6
hgweb: generate last change date for an empty atom-bookmarks feed (issue5022)...
r28712 lastchange=[{"date": web.repo[latestrev].date()}],
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 entries=lambda **x: entries(latestonly=False, **x),
latestentry=lambda **x: entries(latestonly=True, **x))
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('branches')
Sune Foldager
webcommands: add 'branches' command, similar to 'tags'
r8352 def branches(web, req, tmpl):
Gregory Szorc
webcommands: document "branches" web command
r24082 """
/branches
---------
Show information about branches.
All known branches are contained in the output, even closed branches.
No arguments are accepted.
The ``branches`` template is rendered.
"""
av6
hgweb: move branchentries code from webcommands to webutil
r26129 entries = webutil.branchentries(web.repo, web.stripecount)
latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
Sune Foldager
webcommands: add 'branches' command, similar to 'tags'
r8352 return tmpl('branches', node=hex(web.repo.changelog.tip()),
av6
hgweb: move branchentries code from webcommands to webutil
r26129 entries=entries, latestentry=latestentry)
Sune Foldager
webcommands: add 'branches' command, similar to 'tags'
r8352
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('summary')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def summary(web, req, tmpl):
Gregory Szorc
webcommands: document "summary" web command
r24091 """
/summary
--------
Show a summary of repository state.
Information about the latest changesets, bookmarks, tags, and branches
is captured by this handler.
The ``summary`` template is rendered.
"""
Patrick Mezard
webcommands: do not modify repo.tagslist()...
r17261 i = reversed(web.repo.tagslist())
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
def tagentries(**map):
parity = paritygen(web.stripecount)
count = 0
for k, n in i:
if k == "tip": # skip tip
continue
Andrew Beekhof
webcommands: fix increments lost by 894875eae49b
r6659 count += 1
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 if count > 10: # limit to 10 tags
break
yield tmpl("tagentry",
parity=parity.next(),
tag=k,
node=hex(n),
Matt Mackall
use repo[changeid] to get a changectx
r6747 date=web.repo[n].date())
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Yuya Nishihara
hgweb: add bookmarks listing to summary page of gitweb/monoblue styles
r13924 def bookmarks(**map):
parity = paritygen(web.stripecount)
Kevin Bullock
hgweb: make 'summary' work with hidden changesets (issue3810)...
r18563 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
av6
hgweb: sort bookmarks in revlog order of their nodes...
r28711 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
marks = sorted(marks, key=sortkey, reverse=True)
for k, n in marks[:10]: # limit to 10 bookmarks
Yuya Nishihara
hgweb: add bookmarks listing to summary page of gitweb/monoblue styles
r13924 yield {'parity': parity.next(),
'bookmark': k,
'date': web.repo[n].date(),
'node': hex(n)}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 def changelist(**map):
Matt Mackall
many, many trivial check-code fixups
r10282 parity = paritygen(web.stripecount, offset=start - end)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 l = [] # build a list in forward order for efficiency
Kevin Bullock
hgweb: make 'summary' work with hidden changesets (issue3810)...
r18563 revs = []
if start < end:
revs = web.repo.changelog.revs(start, end - 1)
for i in revs:
Matt Mackall
use repo[changeid] to get a changectx
r6747 ctx = web.repo[i]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: no do not use listinsert(0, ...)...
r18319 l.append(tmpl(
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 'shortlogentry',
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 parity=parity.next(),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 **webutil.commonentry(web.repo, ctx)))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Pierre-Yves David
hgweb: no do not use listinsert(0, ...)...
r18319 l.reverse()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 yield l
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 tip = web.repo['tip']
count = len(web.repo)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 start = max(0, count - web.maxchanges)
end = min(count, start + web.maxchanges)
return tmpl("summary",
desc=web.config("web", "description", "unknown"),
owner=get_contact(web.config) or "unknown",
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 lastchange=tip.date(),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 tags=tagentries,
Yuya Nishihara
hgweb: add bookmarks listing to summary page of gitweb/monoblue styles
r13924 bookmarks=bookmarks,
av6
hgweb: limit branches shown on summary page to 10...
r26131 branches=webutil.branchentries(web.repo, web.stripecount, 10),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 shortlog=changelist,
Patrick Mezard
webcommands: remove unncessary access to repo.changelog...
r12059 node=tip.hex(),
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev='tip',
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 archives=web.archivelist("tip"))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('filediff')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def filediff(web, req, tmpl):
Gregory Szorc
webcommands: document "filediff" web command
r24092 """
/diff/{revision}/{path}
-----------------------
Show how a file changed in a particular commit.
The ``filediff`` template is rendered.
Mads Kiilerich
spelling: trivial spell checking
r26781 This handler is registered under both the ``/diff`` and ``/filediff``
Gregory Szorc
webcommands: document "filediff" web command
r24092 paths. ``/diff`` is used in modern code.
"""
Dirkjan Ochtman
hgweb: working diff for removed files
r7183 fctx, ctx = None, None
try:
fctx = webutil.filectx(web.repo, req)
Benoit Boissinot
remove unused variables
r7280 except LookupError:
Dirkjan Ochtman
hgweb: working diff for removed files
r7183 ctx = webutil.changectx(web.repo, req)
path = webutil.cleanpath(web.repo, req.form['file'][0])
if path not in ctx.files():
raise
if fctx is not None:
path = fctx.path()
Matt Mackall
hgweb: fix filediff base calculation...
r16722 ctx = fctx.changectx()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310 parity = paritygen(web.stripecount)
Dirkjan Ochtman
hgweb: show diff header line in raw diffs
r9402 style = web.config('web', 'style', 'paper')
if 'style' in req.form:
style = req.form['style'][0]
Weiwen
hgweb: display diff for a changeset against any parents (issue2810)...
r17991 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
av6
webcommands: test that fctx is not None in filediff()...
r27160 if fctx is not None:
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 rename = webutil.renamelink(fctx)
ctx = fctx
else:
rename = []
ctx = ctx
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 return tmpl("filediff",
file=path,
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=webutil.symrevorshortnode(req, ctx),
Dirkjan Ochtman
hgweb: working diff for removed files
r7183 rename=rename,
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 diff=diffs,
**webutil.commonentry(web.repo, ctx))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 diff = webcommand('diff')(filediff)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('comparison')
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 def comparison(web, req, tmpl):
Gregory Szorc
webcommands: document "comparison" web command
r24093 """
/comparison/{revision}/{path}
-----------------------------
Show a comparison between the old and new versions of a file from changes
made on a particular revision.
This is similar to the ``diff`` handler. However, this form features
a split or side-by-side diff rather than a unified diff.
The ``context`` query string argument can be used to control the lines of
context in the diff.
The ``filecomparison`` template is rendered.
"""
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 ctx = webutil.changectx(web.repo, req)
Ross Lagerwall
hgweb: avoid traceback when file or node parameters are missing...
r17289 if 'file' not in req.form:
raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 path = webutil.cleanpath(web.repo, req.form['file'][0])
parsecontext = lambda v: v == 'full' and -1 or int(v)
if 'context' in req.form:
context = parsecontext(req.form['context'][0])
else:
context = parsecontext(web.config('web', 'comparisoncontext', '5'))
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 def filelines(f):
Alexander Plavin
hgweb: import the whole util module in webcommands instead of just one function...
r19657 if util.binary(f.data()):
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 mt = mimetypes.guess_type(f.path())[0]
if not mt:
mt = 'application/octet-stream'
return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
return f.data().splitlines()
av6
webcommands: get correct parents when comparing a removed file (issue4962)...
r27158 fctx = None
FUJIWARA Katsunori
hgweb: show revisions and hashes gotten from changelog in "comparison" page...
r21123 parent = ctx.p1()
leftrev = parent.rev()
leftnode = parent.node()
rightrev = ctx.rev()
rightnode = ctx.node()
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 if path in ctx:
fctx = ctx[path]
rightlines = filelines(fctx)
FUJIWARA Katsunori
hgweb: make "comparison" get parent from not filelog but changelog...
r21121 if path not in parent:
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 leftlines = ()
else:
FUJIWARA Katsunori
hgweb: make "comparison" get parent from not filelog but changelog...
r21121 pfctx = parent[path]
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 leftlines = filelines(pfctx)
else:
rightlines = ()
av6
webcommands: get correct parents when comparing a removed file (issue4962)...
r27158 pfctx = ctx.parents()[0][path]
leftlines = filelines(pfctx)
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302
comparison = webutil.compare(tmpl, context, leftlines, rightlines)
av6
webcommands: get correct parents when comparing a removed file (issue4962)...
r27158 if fctx is not None:
av6
webcommands: stop using ersatz if-else ternary operator for rename variable...
r27159 rename = webutil.renamelink(fctx)
av6
webcommands: get correct parents when comparing a removed file (issue4962)...
r27158 ctx = fctx
else:
av6
webcommands: stop using ersatz if-else ternary operator for rename variable...
r27159 rename = []
av6
webcommands: get correct parents when comparing a removed file (issue4962)...
r27158 ctx = ctx
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 return tmpl('filecomparison',
file=path,
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=webutil.symrevorshortnode(req, ctx),
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 rename=rename,
wujek srujek
hgweb: fixes traceback for invalid files by removing top-level template...
r17302 leftrev=leftrev,
leftnode=hex(leftnode),
rightrev=rightrev,
rightnode=hex(rightnode),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 comparison=comparison,
**webutil.commonentry(web.repo, ctx))
wujek srujek
hgweb: side-by-side comparison functionality...
r17202
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('annotate')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def annotate(web, req, tmpl):
Gregory Szorc
webcommands: document "annotate" web command
r24094 """
/annotate/{revision}/{path}
---------------------------
Show changeset information for each line in a file.
The ``fileannotate`` template is rendered.
"""
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 fctx = webutil.filectx(web.repo, req)
f = fctx.path()
parity = paritygen(web.stripecount)
Siddharth Agarwal
webcommands.annotate: explicitly only honor whitespace diffopts...
r23689 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
section='annotate', whitespace=True)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
def annotate(**map):
last = None
Alexander Plavin
hgweb: import the whole util module in webcommands instead of just one function...
r19657 if util.binary(fctx.data()):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 mt = (mimetypes.guess_type(fctx.path())[0]
or 'application/octet-stream')
lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
'(binary:%s)' % mt)])
else:
Patrick Mezard
annotate: support diff whitespace filtering flags (issue3030)...
r15528 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
diffopts=diffopts))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 for lineno, ((f, targetline), l) in lines:
fnode = f.filenode()
if last != fnode:
last = fnode
yield {"parity": parity.next(),
Alexander Solovyov
drop {short,hex}(ctx.node()) calls in favor of ctx methods
r14055 "node": f.hex(),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "rev": f.rev(),
Patrick Mezard
webcommands: pass full author to annotate, fix templates (issue 1054)
r6564 "author": f.user(),
Dirkjan Ochtman
hgweb: show cset node and description when hovering over annotate prefix
r6657 "desc": f.description(),
Benoit Boissinot
templates: export extra as a dict to templates...
r18581 "extra": f.extra(),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "file": f.path(),
"targetline": targetline,
"line": l,
Gregory Szorc
hgweb: expose raw line numbers to templates...
r24712 "lineno": lineno + 1,
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "lineid": "l%d" % (lineno + 1),
Oli Thissen
hgweb: added revision date to annotate line data...
r13199 "linenumber": "% 6d" % (lineno + 1),
"revdate": f.date()}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
return tmpl("fileannotate",
file=f,
annotate=annotate,
path=webutil.up(f),
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=webutil.symrevorshortnode(req, fctx),
Matt Mackall
hgweb: minor improvements for new web style...
r6434 rename=webutil.renamelink(fctx),
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 permissions=fctx.manifest().flags(f),
**webutil.commonentry(web.repo, fctx))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('filelog')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def filelog(web, req, tmpl):
Gregory Szorc
webcommands: document "filelog" web command
r24095 """
/filelog/{revision}/{path}
--------------------------
Show information about the history of a file in the repository.
The ``revcount`` query string argument can be defined to control the
maximum number of entries to show.
The ``filelog`` template will be rendered.
"""
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300
try:
fctx = webutil.filectx(web.repo, req)
f = fctx.path()
fl = fctx.filelog()
Matt Mackall
errors: move revlog errors...
r7633 except error.LookupError:
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 f = webutil.cleanpath(web.repo, req.form['file'][0])
fl = web.repo.file(f)
numrevs = len(fl)
if not numrevs: # file doesn't exist at all
raise
rev = webutil.changectx(web.repo, req).rev()
Matt Mackall
linkrev: take a revision number rather than a hash
r7361 first = fl.linkrev(0)
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 if rev < first: # current rev is from before file existed
raise
frev = numrevs - 1
Matt Mackall
linkrev: take a revision number rather than a hash
r7361 while fl.linkrev(frev) > rev:
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 frev -= 1
Matt Mackall
linkrev: take a revision number rather than a hash
r7361 fctx = web.repo.filectx(f, fl.linkrev(frev))
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 revcount = web.maxshortchanges
if 'revcount' in req.form:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
revcount = int(req.form.get('revcount', [revcount])[0])
revcount = max(revcount, 1)
tmpl.defaults['sessionvars']['revcount'] = revcount
except ValueError:
pass
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246
lessvars = copy.copy(tmpl.defaults['sessionvars'])
Md. O. Shayan
hgweb: set minimum number of revision to display to 1 when revcount is 0...
r13931 lessvars['revcount'] = max(revcount / 2, 1)
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 morevars = copy.copy(tmpl.defaults['sessionvars'])
morevars['revcount'] = revcount * 2
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 count = fctx.filerev() + 1
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
end = min(count, start + revcount) # last rev on this page
Matt Mackall
many, many trivial check-code fixups
r10282 parity = paritygen(web.stripecount, offset=start - end)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Alexander Plavin
hgweb: always compute all entries and latestentry in filelog...
r20022 def entries():
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 l = []
Benoit Boissinot
web: use the correct filectx in filelog
r7612 repo = web.repo
Alexander Plavin
hgweb: use semantically suitable filelog.revs in filelog...
r20023 revs = fctx.filelog().revs(start, end - 1)
Pierre-Yves David
hgweb: `limit` argument is actually `latestonly` renames and enforce...
r18402 for i in revs:
Benoit Boissinot
web: use the correct filectx in filelog
r7612 iterfctx = fctx.filectx(i)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 l.append(dict(
parity=parity.next(),
filerev=i,
file=f,
rename=webutil.renamelink(iterfctx),
**webutil.commonentry(repo, iterfctx)))
Pierre-Yves David
hgweb: no do not use listinsert(0, ...)...
r18319 for e in reversed(l):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 yield e
Alexander Plavin
hgweb: always compute all entries and latestentry in filelog...
r20022 entries = list(entries())
latestentry = entries[:1]
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 revnav = webutil.filerevnav(web.repo, fctx.path())
nav = revnav.gen(end - 1, revcount, count)
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 return tmpl("filelog",
file=f,
nav=nav,
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 symrev=webutil.symrevorshortnode(req, fctx),
Alexander Plavin
hgweb: always compute all entries and latestentry in filelog...
r20022 entries=entries,
latestentry=latestentry,
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 revcount=revcount,
morevars=morevars,
lessvars=lessvars,
**webutil.commonentry(web.repo, fctx))
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('archive')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def archive(web, req, tmpl):
Gregory Szorc
webcommands: document "archive" web command
r24096 """
/archive/{revision}.{format}[/{path}]
-------------------------------------
Obtain an archive of repository content.
The content and type of the archive is defined by a URL path parameter.
``format`` is the file extension of the archive type to be generated. e.g.
``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
server configuration.
The optional ``path`` URL parameter controls content to include in the
archive. If omitted, every file in the specified revision is present in the
archive. If included, only the specified file or contents of the specified
directory will be included in the archive.
No template is used for this handler. Raw, binary content is generated.
"""
Ali Saidi
fix traceback in hgweb when URL doesn't end in one of the archive specs...
r6669 type_ = req.form.get('type', [None])[0]
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 allowed = web.configlist("web", "allow_archive")
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 key = req.form['node'][0]
Rocco Rutte
hgweb: Respond with HTTP 403 for disabled archive types instead of 404...
r7029 if type_ not in web.archives:
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 msg = 'Unsupported archive type: %s' % type_
raise ErrorResponse(HTTP_NOT_FOUND, msg)
Rocco Rutte
hgweb: Respond with HTTP 403 for disabled archive types instead of 404...
r7029 if not ((type_ in allowed or
web.configbool("web", "allow" + type_, False))):
msg = 'Archive type not allowed: %s' % type_
raise ErrorResponse(HTTP_FORBIDDEN, msg)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
cnode = web.repo.lookup(key)
arch_version = key
if cnode == key or key == 'tip':
arch_version = short(cnode)
name = "%s-%s" % (reponame, arch_version)
Angel Ezquerra
hgweb: teach archive how to download a specific directory or file...
r18771
ctx = webutil.changectx(web.repo, req)
pats = []
Matt Harbison
hgweb: fix a crash when using web.archivesubrepos...
r23232 matchfn = scmutil.match(ctx, [])
Angel Ezquerra
hgweb: teach archive how to download a specific directory or file...
r18771 file = req.form.get('file', None)
if file:
Angel Ezquerra
hgweb: respond HTTP_NOT_FOUND when an archive request does not match any files
r18968 pats = ['path:' + file[0]]
matchfn = scmutil.match(ctx, pats, default='path')
if pats:
files = [f for f in ctx.manifest().keys() if matchfn(f)]
if not files:
raise ErrorResponse(HTTP_NOT_FOUND,
'file(s) not found: %s' % file[0])
Angel Ezquerra
hgweb: teach archive how to download a specific directory or file...
r18771
Gregory Szorc
hgweb: move archive related attributes to requestcontext...
r26136 mimetype, artype, extension, encoding = web.archivespecs[type_]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 headers = [
('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
Mads Kiilerich
hgweb: make type a mandatory parameter to request.respond...
r18347 ]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 if encoding:
headers.append(('Content-Encoding', encoding))
Mads Kiilerich
hgweb: simplify wsgirequest header handling...
r18348 req.headers.extend(headers)
Mads Kiilerich
hgweb: make type a mandatory parameter to request.respond...
r18347 req.respond(HTTP_OK, mimetype)
Jordi Gutiérrez Hermoso
webcommands: allow hgweb's archive to recurse into subrepos...
r17933
archival.archive(web.repo, req, cnode, artype, prefix=name,
Angel Ezquerra
hgweb: teach archive how to download a specific directory or file...
r18771 matchfn=matchfn,
Jordi Gutiérrez Hermoso
webcommands: allow hgweb's archive to recurse into subrepos...
r17933 subrepos=web.configbool("web", "archivesubrepos"))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 return []
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('static')
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def static(web, req, tmpl):
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 fname = req.form['file'][0]
# a repo owner may set web.static in .hg/hgrc to get any file
# readable by the user running the CGI script
Brendan Cully
Allow hgweb to search for templates in more than one path....
r7107 static = web.config("web", "static", None, untrusted=False)
if not static:
Mads Kiilerich
templater: introduce templatepaths for getting paths searched for templates...
r22634 tp = web.templatepath or templater.templatepaths()
Brendan Cully
Allow hgweb to search for templates in more than one path....
r7107 if isinstance(tp, str):
tp = [tp]
Brendan Cully
Allow per-file shadowing of static directory in templatepath
r7288 static = [os.path.join(p, 'static') for p in tp]
Mads Kiilerich
hgweb: simplify internal staticfile return codes
r18645 staticfile(static, fname, req)
return []
Dirkjan Ochtman
add graph page to hgweb
r6691
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('graph')
Dirkjan Ochtman
add graph page to hgweb
r6691 def graph(web, req, tmpl):
Gregory Szorc
webcommands: document "graph" web command
r24097 """
/graph[/{revision}]
-------------------
Show information about the graphical topology of the repository.
Information rendered by this handler can be used to create visual
representations of repository topology.
The ``revision`` URL parameter controls the starting changeset.
The ``revcount`` query string argument can define the number of changesets
to show information for.
This handler will render the ``graph`` template.
"""
Dirkjan Ochtman
hgweb: make graph page size equal to shortlog
r10245
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 if 'node' in req.form:
ctx = webutil.changectx(web.repo, req)
symrev = webutil.symrevorshortnode(req, ctx)
else:
ctx = web.repo['tip']
symrev = 'tip'
Patrick Mezard
hgweb: fix graph view paging...
r17318 rev = ctx.rev()
Dirkjan Ochtman
add graph page to hgweb
r6691 bg_height = 39
Dirkjan Ochtman
hgweb: make graph page size equal to shortlog
r10245 revcount = web.maxshortchanges
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 if 'revcount' in req.form:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
revcount = int(req.form.get('revcount', [revcount])[0])
revcount = max(revcount, 1)
tmpl.defaults['sessionvars']['revcount'] = revcount
except ValueError:
pass
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345
lessvars = copy.copy(tmpl.defaults['sessionvars'])
Md. O. Shayan
hgweb: set minimum number of revision to display to 1 when revcount is 0...
r13931 lessvars['revcount'] = max(revcount / 2, 1)
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 morevars = copy.copy(tmpl.defaults['sessionvars'])
morevars['revcount'] = revcount * 2
Patrick Mezard
hgweb: fix graph view paging...
r17318 count = len(web.repo)
pos = rev
uprev = min(max(0, count - 1), rev + revcount)
Dirkjan Ochtman
add graph page to hgweb
r6691 downrev = max(0, rev - revcount)
Pierre-Yves David
hgweb: pass repo object to revnav construction...
r18409 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
Dirkjan Ochtman
add graph page to hgweb
r6691
Pierre-Yves David
hgweb: walk the graph through the changelog...
r18428 tree = []
Alexander Plavin
hgweb: fix incorrect revisions count in graph (issue3977)...
r19487 if pos != -1:
allrevs = web.repo.changelog.revs(pos, 0)
revs = []
for i in allrevs:
revs.append(i)
if len(revs) >= revcount:
break
Lucas Moscovicz
webcommands: changed code to use lazy classes when calling dagwalker...
r20761 # We have to feed a baseset to dagwalker as it is expecting smartset
# object. This does not have a big impact on hgweb performance itself
# since hgweb graphing code is not itself lazy yet.
dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
# As we said one line above... not lazy.
Pierre-Yves David
hgweb: walk the graph through the changelog...
r18428 tree = list(graphmod.colored(dag, web.repo))
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
def getcolumns(tree):
cols = 0
for (id, type, ctx, vtx, edges) in tree:
if type != graphmod.CHANGESET:
continue
cols = max(cols, max([edge[0] for edge in edges] or [0]),
max([edge[1] for edge in edges] or [0]))
return cols
Yuya Nishihara
hgweb: add option to convert encoding of graphdata()...
r28211 def graphdata(usetuples, encodestr):
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 data = []
row = 0
for (id, type, ctx, vtx, edges) in tree:
if type != graphmod.CHANGESET:
continue
node = str(ctx)
Yuya Nishihara
hgweb: add option to convert encoding of graphdata()...
r28211 age = encodestr(templatefilters.age(ctx.date()))
desc = templatefilters.firstline(encodestr(ctx.description()))
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 desc = cgi.escape(templatefilters.nonempty(desc))
Yuya Nishihara
hgweb: add option to convert encoding of graphdata()...
r28211 user = cgi.escape(templatefilters.person(encodestr(ctx.user())))
branch = cgi.escape(encodestr(ctx.branch()))
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 try:
branchnode = web.repo.branchtip(branch)
except error.RepoLookupError:
branchnode = None
branch = branch, branchnode == ctx.node()
if usetuples:
data.append((node, vtx, edges, desc, user, age, branch,
Yuya Nishihara
hgweb: add option to convert encoding of graphdata()...
r28211 [cgi.escape(encodestr(x)) for x in ctx.tags()],
[cgi.escape(encodestr(x))
for x in ctx.bookmarks()]))
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 else:
Augie Fackler
webcommands: move from dict() construction to {} literals...
r20678 edgedata = [{'col': edge[0], 'nextcol': edge[1],
'color': (edge[2] - 1) % 6 + 1,
'width': edge[3], 'bcolor': edge[4]}
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 for edge in edges]
data.append(
Augie Fackler
webcommands: move from dict() construction to {} literals...
r20678 {'node': node,
'col': vtx[0],
'color': (vtx[1] - 1) % 6 + 1,
'edges': edgedata,
'row': row,
'nextrow': row + 1,
'desc': desc,
'user': user,
'age': age,
'bookmarks': webutil.nodebookmarksdict(
web.repo, ctx.node()),
'branches': webutil.nodebranchdict(web.repo, ctx),
'inbranch': webutil.nodeinbranch(web.repo, ctx),
'tags': webutil.nodetagsdict(web.repo, ctx.node())})
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
row += 1
return data
cols = getcolumns(tree)
rows = len(tree)
canvasheight = (rows + 1) * bg_height - 27
Dirkjan Ochtman
add graph page to hgweb
r6691
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
uprev=uprev,
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 lessvars=lessvars, morevars=morevars, downrev=downrev,
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773 cols=cols, rows=rows,
canvaswidth=(cols + 1) * bg_height,
truecanvasheight=rows * bg_height,
canvasheight=canvasheight, bg_height=bg_height,
Yuya Nishihara
templatefilters: make json filter be byte-transparent (BC) (issue4926)...
r28212 # {jsdata} will be passed to |json, so it must be in utf-8
jsdata=lambda **x: graphdata(True, encoding.fromlocal),
Yuya Nishihara
hgweb: add option to convert encoding of graphdata()...
r28211 nodes=lambda **x: graphdata(False, str),
Patrick Mezard
hgweb: fix graph view paging...
r17318 node=ctx.hex(), changenav=changenav)
Augie Fackler
web: add a help view for getting hg help output
r12666
def _getdoc(e):
doc = e[0].__doc__
if doc:
av6
hgweb: replace some str.split() calls by str.partition() or str.rpartition()...
r26846 doc = _(doc).partition('\n')[0]
Augie Fackler
web: add a help view for getting hg help output
r12666 else:
doc = _('(no help text available)')
return doc
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 @webcommand('help')
Augie Fackler
web: add a help view for getting hg help output
r12666 def help(web, req, tmpl):
Gregory Szorc
webcommands: document "help" web command
r24081 """
/help[/{topic}]
---------------
Render help documentation.
This web command is roughly equivalent to :hg:`help`. If a ``topic``
is defined, that help topic will be rendered. If not, an index of
available help topics will be rendered.
The ``help`` template will be rendered when requesting help for a topic.
``helptopics`` will be rendered for the index of help topics.
"""
Yuya Nishihara
hgweb: use absolute_import
r27046 from .. import commands, help as helpmod # avoid cycle
Augie Fackler
web: add a help view for getting hg help output
r12666
topicname = req.form.get('node', [None])[0]
if not topicname:
def topics(**map):
Mads Kiilerich
cleanup: avoid _ for local unused tmp variables - that is reserved for i18n...
r22199 for entries, summary, _doc in helpmod.helptable:
Mads Kiilerich
help: use the first topic name from helptable, not the longest alias...
r17322 yield {'topic': entries[0], 'summary': summary}
Augie Fackler
web: add a help view for getting hg help output
r12666
early, other = [], []
av6
hgweb: replace some str.split() calls by str.partition() or str.rpartition()...
r26846 primary = lambda s: s.partition('|')[0]
Augie Fackler
web: add a help view for getting hg help output
r12666 for c, e in commands.table.iteritems():
doc = _getdoc(e)
if 'DEPRECATED' in doc or c.startswith('debug'):
continue
cmd = primary(c)
if cmd.startswith('^'):
early.append((cmd[1:], doc))
else:
other.append((cmd, doc))
early.sort()
other.sort()
def earlycommands(**map):
for c, doc in early:
yield {'topic': c, 'summary': doc}
def othercommands(**map):
for c, doc in other:
yield {'topic': c, 'summary': doc}
return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
othercommands=othercommands, title='Index')
Gregory Szorc
hgweb: support rendering sub-topic indexes...
r27581 # Render an index of sub-topics.
if topicname in helpmod.subtopics:
topics = []
for entries, summary, _doc in helpmod.subtopics[topicname]:
topics.append({
'topic': '%s.%s' % (topicname, entries[0]),
'basename': entries[0],
'summary': summary,
})
return tmpl('helptopics', topics=topics, title=topicname,
subindex=True)
Matt Mackall
hgweb: another fix for the help termwidth bug
r12696 u = webutil.wsgiui()
Adrian Buehlmann
hgweb: show help with verbose sections included...
r17146 u.verbose = True
Gregory Szorc
hgweb: support rendering a sub-topic...
r27582
# Render a page from a sub-topic.
if '.' in topicname:
# TODO implement support for rendering sections, like
# `hg help` works.
topic, subtopic = topicname.split('.', 1)
if topic not in helpmod.subtopics:
raise ErrorResponse(HTTP_NOT_FOUND)
else:
topic = topicname
subtopic = None
Augie Fackler
web: add a help view for getting hg help output
r12666 try:
Gregory Szorc
hgweb: support rendering a sub-topic...
r27582 doc = helpmod.help_(u, topic, subtopic=subtopic)
Augie Fackler
web: add a help view for getting hg help output
r12666 except error.UnknownCommand:
raise ErrorResponse(HTTP_NOT_FOUND)
return tmpl('help', topic=topicname, doc=doc)
FUJIWARA Katsunori
i18n: extract doc string of each web commands as translatable one...
r24859
# tell hggettext to extract docstrings from these functions:
i18nfunctions = commands.values()