##// END OF EJS Templates
hgweb: don't redundantly pass templater with requestcontext (API)...
hgweb: don't redundantly pass templater with requestcontext (API) The requestcontenxt has a ``tmpl`` attribute to access the templater. We don't need to pass the templater explicitly when passing a requestcontext instance. .. api:: Various helper functions in hgweb.webutil no longer accept a templater instance. Access the templater through the ``web`` argument instead. Differential Revision: https://phab.mercurial-scm.org/D2801

File last commit:

r36901:c68e79dc default
r36901:c68e79dc default
Show More
webcommands.py
1484 lines | 44.4 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 copy
import mimetypes
import os
import re
from ..i18n import _
av6
hgweb: make different kinds of commits look differently on /graph...
r35582 from ..node import hex, nullid, short
Yuya Nishihara
hgweb: use absolute_import
r27046
from .common import (
ErrorResponse,
HTTP_FORBIDDEN,
HTTP_NOT_FOUND,
get_contact,
paritygen,
staticfile,
)
from .. import (
archival,
Yuya Nishihara
dagop: move blockancestors() and blockdescendants() from context...
r32904 dagop,
Yuya Nishihara
hgweb: use absolute_import
r27046 encoding,
error,
graphmod,
Augie Fackler
webcommands: replace str(ctx) etc with pycompat.bytestr(ctx) etc...
r34810 pycompat,
Yuya Nishihara
hgweb: use absolute_import
r27046 revset,
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 revsetlang,
Yuya Nishihara
hgweb: use absolute_import
r27046 scmutil,
Yuya Nishihara
revset: import set classes directly from smartset module...
r31023 smartset,
Yuya Nishihara
hgweb: use absolute_import
r27046 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.
Gregory Szorc
hgweb: support using new response object for web commands...
r36886 When called, functions receive as arguments a ``requestcontext``,
``wsgirequest``, and a templater instance for generatoring output.
The functions should populate the ``rctx.res`` object with details
about the HTTP response.
Gregory Szorc
hgweb: always return iterable from @webcommand functions (API)...
r36896 The function returns a generator to be consumed by the WSGI application.
For most commands, this should be the result from
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 ``web.res.sendresponse()``. Many commands will call ``web.sendtemplate()``
to render a template.
Gregory Szorc
hgweb: support using new response object for web commands...
r36886
Gregory Szorc
webcommands: define web commands using a decorator...
r24076 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.
"""
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if web.req.qsparams.get('file'):
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return filelog(web, req, None)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 else:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return changelog(web, req, None)
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):
Boris Feld
configitems: register the 'web.guessmime' config
r34609 guessmime = web.configbool('web', 'guessmime')
Matt Mackall
hgweb: raw file mimetype guessing configurable, off by default (BC) (issue2923)...
r15004
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890 if not path:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return manifest(web, req, None)
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:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return manifest(web, req, None)
Dirkjan Ochtman
hgweb: better error messages
r6368 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
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 web.res.headers['Content-Type'] = mt
filename = (path.rpartition('/')[-1]
.replace('\\', '\\\\').replace('"', '\\"'))
web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename
web.res.setbodybytes(text)
Gregory Szorc
hgweb: always return iterable from @webcommand functions (API)...
r36896 return web.res.sendresponse()
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 def _filerevision(web, req, fctx):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 f = fctx.path()
text = fctx.data()
parity = paritygen(web.stripecount)
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 ishead = fctx.filerev() in fctx.filelog().headrevs()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
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),
timeless
py3: convert to next() function...
r29216 "parity": next(parity)}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'filerevision',
file=f,
path=webutil.up(f),
text=lines(),
symrev=webutil.symrevorshortnode(req, fctx),
rename=webutil.renamelink(fctx),
permissions=fctx.manifest().flags(f),
ishead=int(ishead),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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.
"""
Gregory Szorc
hgweb: remove one-off routing for file?style=raw...
r36888 if web.req.qsparams.get('style') == 'raw':
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return rawfile(web, req, None)
Gregory Szorc
hgweb: remove one-off routing for file?style=raw...
r36888
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
Benoit Boissinot
hgweb: do not use unassigned variables in exception handling
r6853 if not path:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return manifest(web, req, None)
Benoit Boissinot
hgweb: do not use unassigned variables in exception handling
r6853 try:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return _filerevision(web, req, 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:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return manifest(web, req, None)
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
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 def _search(web):
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: split language services to revsetlang module (API)...
r31024 tree = revsetlang.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
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 if revsetlang.depth(tree) <= 2:
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 # 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:')
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 for token, value, pos in revsetlang.tokenize(revdef)):
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 return MODE_KEYWORD, query
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 funcsused = revsetlang.funcsused(tree)
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 if not funcsused.issubset(revset.safesymbols):
return MODE_KEYWORD, query
Gregory Szorc
revset: pass repo when passing ui...
r33554 mfunc = revset.match(web.repo.ui, revdef, repo=web.repo)
Alexander Plavin
hgweb: add revset syntax support to search...
r19722 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()
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 showtags = webutil.showtag(web.repo, web.tmpl, 'changelogtag', n)
files = webutil.listfilediffs(web.tmpl, ctx.files(), n,
web.maxfiles)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 yield web.tmpl(
'searchentry',
parity=next(parity),
changelogtag=showtags,
files=files,
**pycompat.strkwargs(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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 query = web.req.qsparams['rev']
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418 revcount = web.maxchanges
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'revcount' in web.req.qsparams:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 revcount = int(web.req.qsparams.get('revcount', revcount))
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 revcount = max(revcount, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 web.tmpl.defaults['sessionvars']['revcount'] = revcount
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 except ValueError:
pass
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
Augie Fackler
webcommands: use explicit integer division for Python 3 compat...
r36571 lessvars['revcount'] = max(revcount // 2, 1)
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418 lessvars['rev'] = query
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
Alexander Plavin
hgweb: move local changelist function to the beginning of the parent one
r19418 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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'forcekw' in web.req.qsparams:
Alexander Plavin
hgweb: add link to force literal keyword search...
r19768 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)
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'search',
query=query,
node=tip.hex(),
symrev='tip',
entries=changelist,
archives=web.archivelist('tip'),
morevars=morevars,
lessvars=lessvars,
modedesc=searchfunc[1],
showforcekw=showforcekw,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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 = ''
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'node' in web.req.qsparams:
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)
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 elif 'rev' in web.req.qsparams:
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return _search(web)
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
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 entry = webutil.changelistentry(web, web.repo[rev])
timeless
py3: convert to next() function...
r29216 entry['parity'] = next(parity)
Gregory Szorc
hgweb: extract changelist entry generation into own function...
r23745 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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'revcount' in web.req.qsparams:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 revcount = int(web.req.qsparams.get('revcount', revcount))
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 revcount = max(revcount, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 web.tmpl.defaults['sessionvars']['revcount'] = revcount
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 except ValueError:
pass
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
Augie Fackler
webcommands: use explicit integer division for Python 3 compat...
r36571 lessvars['revcount'] = max(revcount // 2, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 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
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'shortlog' if shortlog else 'changelog',
changenav=changenav,
node=ctx.hex(),
rev=pos,
symrev=symrev,
changesets=count,
entries=entries,
latestentry=latestentry,
nextentry=nextentry,
archives=web.archivelist('tip'),
revcount=revcount,
morevars=morevars,
lessvars=lessvars,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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.
"""
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 return changelog(web, req, None, 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: add a sendtemplate() helper function...
r36899
return web.sendtemplate(
'changeset',
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 **webutil.changesetentry(web, req, 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.
"""
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'node' in web.req.qsparams:
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 ctx = webutil.changectx(web.repo, req)
symrev = webutil.symrevorshortnode(req, ctx)
else:
ctx = web.repo['tip']
symrev = 'tip'
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 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)
Augie Fackler
hgweb: fix up trailing slash detection on Python 3...
r36731 if path and path[-1:] != "/":
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 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,
timeless
py3: convert to next() function...
r29216 "parity": next(parity),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "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:
Augie Fackler
webcommands: unpack contents of length-1 dict portably...
r36288 k, v = next(iter(h.items()))
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 if v:
emptydirs.append(k)
h = v
path = "%s%s" % (abspath, d)
timeless
py3: convert to next() function...
r29216 yield {"parity": next(parity),
Ry4an Brase
hgweb: descend empty directories in web view...
r7305 "path": path,
"emptydirs": "/".join(emptydirs),
"basename": d}
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'manifest',
symrev=symrev,
path=abspath,
up=webutil.up(abspath),
upparity=next(parity),
fentries=filelist,
dentries=dirlist,
archives=web.archivelist(hex(node)),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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:
timeless
py3: convert to next() function...
r29216 yield {"parity": next(parity),
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "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)}
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'tags',
node=hex(web.repo.changelog.tip()),
entries=lambda **x: entries(False, False, **x),
entriesnotip=lambda **x: entries(True, False, **x),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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:
timeless
py3: convert to next() function...
r29216 yield {"parity": next(parity),
Alexander Solovyov
hgweb: add separate page with bookmarks listing
r13597 "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
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'bookmarks',
node=hex(web.repo.changelog.tip()),
lastchange=[{'date': web.repo[latestrev].date()}],
entries=lambda **x: entries(latestonly=False, **x),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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)
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'branches',
node=hex(web.repo.changelog.tip()),
entries=entries,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 yield web.tmpl(
'tagentry',
parity=next(parity),
tag=k,
node=hex(n),
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
timeless
py3: convert to next() function...
r29216 yield {'parity': next(parity),
Yuya Nishihara
hgweb: add bookmarks listing to summary page of gitweb/monoblue styles
r13924 '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
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 l.append(web.tmpl(
av6
hgweb: move entry-preparing code from webcommands to webutils.commonentry()...
r27294 'shortlogentry',
timeless
py3: convert to next() function...
r29216 parity=next(parity),
Pulkit Goyal
py3: use pycompat.strkwargs to convert kwargs keys to str...
r36452 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Laura Médioni
templates: add support for summary webcommand in json style...
r29382 for entry in reversed(l):
yield entry
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
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)
Boris Feld
configitems: register the 'web.description' config
r34235 desc = web.config("web", "description")
if not desc:
desc = 'unknown'
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'summary',
desc=desc,
owner=get_contact(web.config) or 'unknown',
lastchange=tip.date(),
tags=tagentries,
bookmarks=bookmarks,
branches=webutil.branchentries(web.repo, web.stripecount, 10),
shortlog=changelist,
node=tip.hex(),
symrev='tip',
archives=web.archivelist('tip'),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 labels=web.configlist('web', 'labels'))
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)
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
Dirkjan Ochtman
hgweb: working diff for removed files
r7183 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()
Denis Laxalde
hgweb: explictly pass basectx in webutil.diffs...
r31082 basectx = ctx.p1()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Boris Feld
configitems: register the 'web.style' config
r34243 style = web.config('web', 'style')
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'style' in web.req.qsparams:
style = web.req.qsparams['style']
Dirkjan Ochtman
hgweb: show diff header line in raw diffs
r9402
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 diffs = webutil.diffs(web, ctx, basectx, [path], 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
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'filediff',
file=path,
symrev=webutil.symrevorshortnode(req, ctx),
rename=rename,
diff=diffs,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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)
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'file' not in web.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: use web.req instead of req.req...
r36898 path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
wujek srujek
hgweb: side-by-side comparison functionality...
r17202
parsecontext = lambda v: v == 'full' and -1 or int(v)
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'context' in web.req.qsparams:
context = parsecontext(web.req.qsparams['context'])
wujek srujek
hgweb: side-by-side comparison functionality...
r17202 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):
Jun Wu
webcommands: use fctx.isbinary
r32136 if f.isbinary():
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
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 comparison = webutil.compare(web.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
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'filecomparison',
file=path,
symrev=webutil.symrevorshortnode(req, ctx),
rename=rename,
leftrev=leftrev,
leftnode=hex(leftnode),
rightrev=rightrev,
rightnode=hex(rightnode),
comparison=comparison,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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.
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 The ``ignorews``, ``ignorewsamount``, ``ignorewseol``, and
``ignoreblanklines`` query string arguments have the same meaning as
Gregory Szorc
hgweb: use parsebool for parsing diff query string options...
r34404 their ``[annotate]`` config equivalents. It uses the hgrc boolean
parsing logic to interpret the value. e.g. ``0`` and ``false`` are
false and ``1`` and ``true`` are true. If not defined, the server
default settings are used.
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391
Gregory Szorc
webcommands: document "annotate" web command
r24094 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)
Denis Laxalde
hgweb: plug followlines action in annotate view...
r32994 ishead = fctx.filerev() in fctx.filelog().headrevs()
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Gregory Szorc
hgweb: cache fctx.parents() in annotate command (issue5414)...
r30298 # parents() is called once per line and several lines likely belong to
# same revision. So it is worth caching.
# TODO there are still redundant operations within basefilectx.parents()
# and from the fctx.annotate() call itself that could be cached.
parentscache = {}
Denis Laxalde
hgweb: add link to parents of annotated revision in annotate view...
r29522 def parents(f):
Gregory Szorc
hgweb: cache fctx.parents() in annotate command (issue5414)...
r30298 rev = f.rev()
if rev not in parentscache:
parentscache[rev] = []
for p in f.parents():
entry = {
'node': p.hex(),
'rev': p.rev(),
}
parentscache[rev].append(entry)
for p in parentscache[rev]:
yield p
Denis Laxalde
hgweb: add link to parents of annotated revision in annotate view...
r29522
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 def annotate(**map):
Jun Wu
webcommands: use fctx.isbinary
r32136 if fctx.isbinary():
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 mt = (mimetypes.guess_type(fctx.path())[0]
or 'application/octet-stream')
av6
hgweb: enumerate lines in loop header, not before...
r29538 lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)]
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 else:
Gregory Szorc
hgweb: query string arguments to control whitespace for annotate...
r34391 lines = webutil.annotate(req, fctx, web.repo.ui)
Jun Wu
hgweb: make fctx.annotate a separated function so it could be wrapped...
r30081
Denis Laxalde
hgweb: display blamed revision once per block in annotate view...
r29388 previousrev = None
av6
paper: make different blocks of annotated lines have different colors
r29572 blockparitygen = paritygen(1)
Siddharth Agarwal
annotate: introduce attr for storing per-line annotate data...
r34433 for lineno, (aline, l) in enumerate(lines):
f = aline.fctx
Denis Laxalde
hgweb: display blamed revision once per block in annotate view...
r29388 rev = f.rev()
av6
paper: make different blocks of annotated lines have different colors
r29572 if rev != previousrev:
blockhead = True
blockparity = next(blockparitygen)
else:
blockhead = None
Denis Laxalde
hgweb: display blamed revision once per block in annotate view...
r29388 previousrev = rev
timeless
py3: convert to next() function...
r29216 yield {"parity": next(parity),
Alexander Solovyov
drop {short,hex}(ctx.node()) calls in favor of ctx methods
r14055 "node": f.hex(),
Denis Laxalde
hgweb: display blamed revision once per block in annotate view...
r29388 "rev": rev,
Patrick Mezard
webcommands: pass full author to annotate, fix templates (issue 1054)
r6564 "author": f.user(),
Denis Laxalde
hgweb: add link to parents of annotated revision in annotate view...
r29522 "parents": parents(f),
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(),
Denis Laxalde
hgweb: display blamed revision once per block in annotate view...
r29388 "blockhead": blockhead,
av6
paper: make different blocks of annotated lines have different colors
r29572 "blockparity": blockparity,
Siddharth Agarwal
annotate: introduce attr for storing per-line annotate data...
r34433 "targetline": aline.lineno,
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 "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
Gregory Szorc
hgweb: add HTML elements to control whitespace settings for annotate...
r34392 diffopts = webutil.difffeatureopts(req, web.repo.ui, 'annotate')
diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults}
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'fileannotate',
file=f,
annotate=annotate,
path=webutil.up(f),
symrev=webutil.symrevorshortnode(req, fctx),
rename=webutil.renamelink(fctx),
permissions=fctx.manifest().flags(f),
ishead=int(ishead),
diffopts=diffopts,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 f = webutil.cleanpath(web.repo, web.req.qsparams['file'])
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'revcount' in web.req.qsparams:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 revcount = int(web.req.qsparams.get('revcount', revcount))
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 revcount = max(revcount, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 web.tmpl.defaults['sessionvars']['revcount'] = revcount
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 except ValueError:
pass
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 lrange = webutil.linerange(req)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
Augie Fackler
webcommands: use explicit integer division for Python 3 compat...
r36571 lessvars['revcount'] = max(revcount // 2, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 morevars['revcount'] = revcount * 2
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 patch = 'patch' in web.req.qsparams
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661 if patch:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 lessvars['patch'] = morevars['patch'] = web.req.qsparams['patch']
descend = 'descend' in web.req.qsparams
Denis Laxalde
hgweb: handle a "descend" query parameter in filelog command...
r31939 if descend:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 lessvars['descend'] = morevars['descend'] = web.req.qsparams['descend']
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661
Dirkjan Ochtman
hgweb: conditionally show file logs for deleted files
r7300 count = fctx.filerev() + 1
Denis Laxalde
hgweb: simplify calculation of first revision in filelog command
r30826 start = max(0, count - revcount) # first rev on this page
Dirkjan Ochtman
hgweb: add less/more links to shortlog/filelog nav
r10246 end = min(count, start + revcount) # last rev on this page
Denis Laxalde
hgweb: restore ascending iteration on revs in filelog web command...
r30825 parity = paritygen(web.stripecount, offset=start - end)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Denis Laxalde
hgweb: build the "entries" list directly in filelog command...
r30816 repo = web.repo
revs = fctx.filelog().revs(start, end - 1)
entries = []
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661
Boris Feld
configitems: register the 'web.style' config
r34243 diffstyle = web.config('web', 'style')
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'style' in web.req.qsparams:
diffstyle = web.req.qsparams['style']
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661
Denis Laxalde
hgweb: filter diff hunks when 'linerange' and 'patch' are specified in filelog
r31667 def diff(fctx, linerange=None):
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661 ctx = fctx.changectx()
basectx = ctx.p1()
path = fctx.path()
Gregory Szorc
hgweb: don't redundantly pass templater with requestcontext (API)...
r36901 return webutil.diffs(web, ctx, basectx, [path], diffstyle,
Denis Laxalde
hgweb: prefix line id by ctx shortnode in filelog when patches are shown...
r31727 linerange=linerange,
lineidprefix='%s-' % ctx.hex()[:12])
Denis Laxalde
hgweb: add a "patch" query parameter to filelog command...
r31661
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 linerange = None
if lrange is not None:
linerange = webutil.formatlinerange(*lrange)
# deactivate numeric nav links when linerange is specified as this
# would required a dedicated "revnav" class
nav = None
Denis Laxalde
hgweb: handle a "descend" query parameter in filelog command...
r31939 if descend:
Yuya Nishihara
dagop: move blockancestors() and blockdescendants() from context...
r32904 it = dagop.blockdescendants(fctx, *lrange)
Denis Laxalde
hgweb: handle a "descend" query parameter in filelog command...
r31939 else:
Yuya Nishihara
dagop: move blockancestors() and blockdescendants() from context...
r32904 it = dagop.blockancestors(fctx, *lrange)
Denis Laxalde
hgweb: handle a "descend" query parameter in filelog command...
r31939 for i, (c, lr) in enumerate(it, 1):
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 diffs = None
if patch:
Denis Laxalde
hgweb: filter diff hunks when 'linerange' and 'patch' are specified in filelog
r31667 diffs = diff(c, linerange=lr)
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 # follow renames accross filtered (not in range) revisions
path = c.path()
entries.append(dict(
parity=next(parity),
filerev=c.rev(),
file=path,
diff=diffs,
linerange=webutil.formatlinerange(*lr),
Pulkit Goyal
py3: use pycompat.strkwargs to convert kwargs keys to str...
r36452 **pycompat.strkwargs(webutil.commonentry(repo, c))))
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 if i == revcount:
break
lessvars['linerange'] = webutil.formatlinerange(*lrange)
morevars['linerange'] = lessvars['linerange']
else:
for i in revs:
iterfctx = fctx.filectx(i)
diffs = None
if patch:
diffs = diff(iterfctx)
entries.append(dict(
parity=next(parity),
filerev=i,
file=f,
diff=diffs,
rename=webutil.renamelink(iterfctx),
Pulkit Goyal
py3: use pycompat.strkwargs to convert kwargs keys to str...
r36452 **pycompat.strkwargs(webutil.commonentry(repo, iterfctx))))
Denis Laxalde
hgweb: handle a "linerange" request parameter in filelog command...
r31665 entries.reverse()
revnav = webutil.filerevnav(web.repo, fctx.path())
nav = revnav.gen(end - 1, revcount, count)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Alexander Plavin
hgweb: always compute all entries and latestentry in filelog...
r20022 latestentry = entries[:1]
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: support using new response object for web commands...
r36886 'filelog',
file=f,
nav=nav,
symrev=webutil.symrevorshortnode(req, fctx),
entries=entries,
descend=descend,
patch=patch,
latestentry=latestentry,
linerange=linerange,
revcount=revcount,
morevars=morevars,
lessvars=lessvars,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 **pycompat.strkwargs(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.
"""
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 type_ = web.req.qsparams.get('type')
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 allowed = web.configlist("web", "allow_archive")
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 key = web.req.qsparams['node']
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
av6
hgweb: use archivespecs (dict) instead of archives (tuple) for "in" check
r30734 if type_ not in web.archivespecs:
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
Yuya Nishihara
configitems: drop redundant default of web.allow<archtype>...
r34655 web.configbool("web", "allow" + type_))):
Rocco Rutte
hgweb: Respond with HTTP 403 for disabled archive types instead of 404...
r7029 msg = 'Archive type not allowed: %s' % type_
raise ErrorResponse(HTTP_FORBIDDEN, msg)
Pulkit Goyal
py3: make regex bytes in hgweb/webcommands.py...
r36402 reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 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 = []
Martin von Zweigbergk
cleanup: rename "matchfn" to "match" where obviously a matcher...
r34085 match = scmutil.match(ctx, [])
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 file = web.req.qsparams.get('file')
Angel Ezquerra
hgweb: teach archive how to download a specific directory or file...
r18771 if file:
Gregory Szorc
hgweb: perform all parameter lookup via qsparams...
r36881 pats = ['path:' + file]
Martin von Zweigbergk
cleanup: rename "matchfn" to "match" where obviously a matcher...
r34085 match = scmutil.match(ctx, pats, default='path')
Angel Ezquerra
hgweb: respond HTTP_NOT_FOUND when an archive request does not match any files
r18968 if pats:
Martin von Zweigbergk
cleanup: rename "matchfn" to "match" where obviously a matcher...
r34085 files = [f for f in ctx.manifest().keys() if match(f)]
Angel Ezquerra
hgweb: respond HTTP_NOT_FOUND when an archive request does not match any files
r18968 if not files:
raise ErrorResponse(HTTP_NOT_FOUND,
Gregory Szorc
hgweb: perform all parameter lookup via qsparams...
r36881 'file(s) not found: %s' % file)
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_]
Gregory Szorc
hgweb: port archive command to modern response API...
r36892
web.res.headers['Content-Type'] = mimetype
web.res.headers['Content-Disposition'] = 'attachment; filename=%s%s' % (
name, extension)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 if encoding:
Gregory Szorc
hgweb: port archive command to modern response API...
r36892 web.res.headers['Content-Encoding'] = encoding
Jordi Gutiérrez Hermoso
webcommands: allow hgweb's archive to recurse into subrepos...
r17933
Gregory Szorc
hgweb: port archive command to modern response API...
r36892 web.res.setbodywillwrite()
assert list(web.res.sendresponse()) == []
bodyfh = web.res.getbodyfile()
Gregory Szorc
hgweb: refactor fake file object proxy for archiving...
r36891
archival.archive(web.repo, bodyfh, cnode, artype, prefix=name,
Martin von Zweigbergk
cleanup: rename "matchfn" to "match" where obviously a matcher...
r34085 matchfn=match,
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
Gregory Szorc
hgweb: always return iterable from @webcommand functions (API)...
r36896 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):
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 fname = web.req.qsparams['file']
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 # 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]
Gregory Szorc
hgweb: port static file handling to new response API...
r36889
staticfile(static, fname, web.res)
Gregory Szorc
hgweb: always return iterable from @webcommand functions (API)...
r36896 return web.res.sendresponse()
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.
av6
hgweb: update graph function docstring
r35412 The ``revision`` URL parameter controls the starting changeset. If it's
absent, the default is ``tip``.
Gregory Szorc
webcommands: document "graph" web command
r24097
The ``revcount`` query string argument can define the number of changesets
to show information for.
av6
hgweb: update graph function docstring
r35412 The ``graphtop`` query string argument can specify the starting changeset
for producing ``jsdata`` variable that is used for rendering graph in
JavaScript. By default it has the same value as ``revision``.
Gregory Szorc
webcommands: document "graph" web command
r24097 This handler will render the ``graph`` template.
"""
Dirkjan Ochtman
hgweb: make graph page size equal to shortlog
r10245
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'node' in web.req.qsparams:
av6
hgweb: provide symrev (symbolic revision) property to the templates...
r25602 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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 if 'revcount' in web.req.qsparams:
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 try:
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 revcount = int(web.req.qsparams.get('revcount', revcount))
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 revcount = max(revcount, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 web.tmpl.defaults['sessionvars']['revcount'] = revcount
Isaac Jurado
hgweb: ignore non numeric "revcount" parameter values (issue4091)
r20092 except ValueError:
pass
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 lessvars = copy.copy(web.tmpl.defaults['sessionvars'])
Augie Fackler
webcommands: use explicit integer division for Python 3 compat...
r36571 lessvars['revcount'] = max(revcount // 2, 1)
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 morevars = copy.copy(web.tmpl.defaults['sessionvars'])
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 morevars['revcount'] = revcount * 2
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 graphtop = web.req.qsparams.get('graphtop', ctx.hex())
Gregory Szorc
hgweb: use templater on requestcontext instance...
r36900 graphvars = copy.copy(web.tmpl.defaults['sessionvars'])
av6
hgweb: render next pages on /graph incrementally...
r35410 graphvars['graphtop'] = graphtop
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 = []
av6
hgweb: render next pages on /graph incrementally...
r35410 nextentry = []
lastrev = 0
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)
av6
hgweb: render next pages on /graph incrementally...
r35410 if len(revs) >= revcount + 1:
Alexander Plavin
hgweb: fix incorrect revisions count in graph (issue3977)...
r19487 break
av6
hgweb: render next pages on /graph incrementally...
r35410 if len(revs) > revcount:
nextentry = [webutil.commonentry(web.repo, web.repo[revs[-1]])]
revs = revs[:-1]
lastrev = revs[-1]
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.
Yuya Nishihara
revset: import set classes directly from smartset module...
r31023 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
Lucas Moscovicz
webcommands: changed code to use lazy classes when calling dagwalker...
r20761 # As we said one line above... not lazy.
av6
hgweb: filter graphmod.colored() output before iterating over it...
r35407 tree = list(item for item in graphmod.colored(dag, web.repo)
if item[1] == graphmod.CHANGESET)
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
av6
hgweb: make different kinds of commits look differently on /graph...
r35582 def nodecurrent(ctx):
wpnodes = web.repo.dirstate.parents()
if wpnodes[1] == nullid:
wpnodes = wpnodes[:1]
if ctx.node() in wpnodes:
return '@'
return ''
def nodesymbol(ctx):
if ctx.obsolete():
return 'x'
elif ctx.isunstable():
return '*'
elif ctx.closesbranch():
return '_'
else:
return 'o'
av6
hgweb: render next pages on /graph incrementally...
r35410 def fulltree():
pos = web.repo[graphtop].rev()
tree = []
if pos != -1:
revs = web.repo.changelog.revs(pos, lastrev)
dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
tree = list(item for item in graphmod.colored(dag, web.repo)
if item[1] == graphmod.CHANGESET)
return tree
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 def jsdata():
return [{'node': pycompat.bytestr(ctx),
av6
hgweb: make different kinds of commits look differently on /graph...
r35582 'graphnode': nodecurrent(ctx) + nodesymbol(ctx),
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 'vertex': vtx,
'edges': edges}
av6
hgweb: render next pages on /graph incrementally...
r35410 for (id, type, ctx, vtx, edges) in fulltree()]
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 def nodes():
av6
monoblue: make actual changeset entries have backgrounds on /graph...
r35548 parity = paritygen(web.stripecount)
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 for row, (id, type, ctx, vtx, edges) in enumerate(tree):
entry = webutil.commonentry(web.repo, ctx)
edgedata = [{'col': edge[0],
'nextcol': edge[1],
'color': (edge[2] - 1) % 6 + 1,
'width': edge[3],
'bcolor': edge[4]}
for edge in edges]
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 entry.update({'col': vtx[0],
'color': (vtx[1] - 1) % 6 + 1,
av6
monoblue: make actual changeset entries have backgrounds on /graph...
r35548 'parity': next(parity),
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 'edges': edgedata,
'row': row,
'nextrow': row + 1})
av6
hgweb: use webutil.commonentry() for nodes (but not for jsdata yet) in /graph...
r35095
av6
hgweb: split graphdata() into jsdata() and nodes()...
r35409 yield entry
Paul Boddie
hgweb: make graph data suitable for template usage...
r16773
rows = len(tree)
Dirkjan Ochtman
add graph page to hgweb
r6691
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'graph',
rev=rev,
symrev=symrev,
revcount=revcount,
uprev=uprev,
lessvars=lessvars,
morevars=morevars,
downrev=downrev,
graphvars=graphvars,
rows=rows,
bg_height=bg_height,
changesets=count,
nextentry=nextentry,
jsdata=lambda **x: jsdata(),
nodes=lambda **x: nodes(),
node=ctx.hex(),
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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
Gregory Szorc
hgweb: use web.req instead of req.req...
r36898 topicname = web.req.qsparams.get('node')
Augie Fackler
web: add a help view for getting hg help output
r12666 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}
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'helptopics',
topics=topics,
earlycommands=earlycommands,
othercommands=othercommands,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 title='Index')
Augie Fackler
web: add a help view for getting hg help output
r12666
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,
})
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'helptopics',
topics=topics,
title=topicname,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 subindex=True)
Gregory Szorc
hgweb: support rendering sub-topic indexes...
r27581
Yuya Nishihara
ui: factor out ui.load() to create a ui without loading configs (API)...
r30559 u = webutil.wsgiui.load()
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:
Yuya Nishihara
help: pass commands module by argument...
r32567 doc = helpmod.help_(u, commands, topic, subtopic=subtopic)
Yuya Nishihara
hgweb: translate Abort in help command to 404 error...
r36262 except error.Abort:
Augie Fackler
web: add a help view for getting hg help output
r12666 raise ErrorResponse(HTTP_NOT_FOUND)
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 return web.sendtemplate(
Gregory Szorc
hgweb: port most @webcommand to use modern response type...
r36887 'help',
topic=topicname,
Gregory Szorc
hgweb: add a sendtemplate() helper function...
r36899 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()