Our march towards killing wsgirequest continues.
.. api::
Various functions in hgweb.webutil now take a modern request object instead of ``wsgirequest``.
durin42 |
hg-reviewers |
Our march towards killing wsgirequest continues.
.. api::
Various functions in hgweb.webutil now take a modern request object instead of ``wsgirequest``.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
Path | Packages | |||
---|---|---|---|---|
M | hgext/highlight/__init__.py (2 lines) | |||
M | mercurial/hgweb/webcommands.py (50 lines) | |||
M | mercurial/hgweb/webutil.py (42 lines) |
if 'html' in mt: | if 'html' in mt: | ||||
pygmentize(web, 'fileline', fctx, web.tmpl) | pygmentize(web, 'fileline', fctx, web.tmpl) | ||||
return orig(web, req, fctx) | return orig(web, req, fctx) | ||||
def annotate_highlight(orig, web, req, tmpl): | def annotate_highlight(orig, web, req, tmpl): | ||||
mt = ''.join(web.tmpl('mimetype', encoding=encoding.encoding)) | mt = ''.join(web.tmpl('mimetype', encoding=encoding.encoding)) | ||||
if 'html' in mt: | if 'html' in mt: | ||||
fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
pygmentize(web, 'annotateline', fctx, web.tmpl) | pygmentize(web, 'annotateline', fctx, web.tmpl) | ||||
return orig(web, req, web.tmpl) | return orig(web, req, web.tmpl) | ||||
def generate_css(web, req, tmpl): | def generate_css(web, req, tmpl): | ||||
pg_style = web.config('web', 'pygments_style', 'colorful') | pg_style = web.config('web', 'pygments_style', 'colorful') | ||||
fmter = highlight.HtmlFormatter(style=pg_style) | fmter = highlight.HtmlFormatter(style=pg_style) | ||||
web.res.headers['Content-Type'] = 'text/css' | web.res.headers['Content-Type'] = 'text/css' |
def rawfile(web, req, tmpl): | def rawfile(web, req, tmpl): | ||||
guessmime = web.configbool('web', 'guessmime') | guessmime = web.configbool('web', 'guessmime') | ||||
path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
if not path: | if not path: | ||||
return manifest(web, req, None) | return manifest(web, req, None) | ||||
try: | try: | ||||
fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
except error.LookupError as inst: | except error.LookupError as inst: | ||||
try: | try: | ||||
return manifest(web, req, None) | return manifest(web, req, None) | ||||
except ErrorResponse: | except ErrorResponse: | ||||
raise inst | raise inst | ||||
path = fctx.path() | path = fctx.path() | ||||
text = fctx.data() | text = fctx.data() | ||||
"linenumber": "% 6d" % (lineno + 1), | "linenumber": "% 6d" % (lineno + 1), | ||||
"parity": next(parity)} | "parity": next(parity)} | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'filerevision', | 'filerevision', | ||||
file=f, | file=f, | ||||
path=webutil.up(f), | path=webutil.up(f), | ||||
text=lines(), | text=lines(), | ||||
symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
rename=webutil.renamelink(fctx), | rename=webutil.renamelink(fctx), | ||||
permissions=fctx.manifest().flags(f), | permissions=fctx.manifest().flags(f), | ||||
ishead=int(ishead), | ishead=int(ishead), | ||||
**pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | ||||
@webcommand('file') | @webcommand('file') | ||||
def file(web, req, tmpl): | def file(web, req, tmpl): | ||||
""" | """ | ||||
""" | """ | ||||
if web.req.qsparams.get('style') == 'raw': | if web.req.qsparams.get('style') == 'raw': | ||||
return rawfile(web, req, None) | return rawfile(web, req, None) | ||||
path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
if not path: | if not path: | ||||
return manifest(web, req, None) | return manifest(web, req, None) | ||||
try: | try: | ||||
return _filerevision(web, req, webutil.filectx(web.repo, req)) | return _filerevision(web, req, webutil.filectx(web.repo, web.req)) | ||||
except error.LookupError as inst: | except error.LookupError as inst: | ||||
try: | try: | ||||
return manifest(web, req, None) | return manifest(web, req, None) | ||||
except ErrorResponse: | except ErrorResponse: | ||||
raise inst | raise inst | ||||
def _search(web): | def _search(web): | ||||
MODE_REVISION = 'rev' | MODE_REVISION = 'rev' | ||||
The ``revcount`` query string argument defines the maximum numbers of | The ``revcount`` query string argument defines the maximum numbers of | ||||
changesets to render. | changesets to render. | ||||
For non-searches, the ``changelog`` template will be rendered. | For non-searches, the ``changelog`` template will be rendered. | ||||
""" | """ | ||||
query = '' | query = '' | ||||
if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
elif 'rev' in web.req.qsparams: | elif 'rev' in web.req.qsparams: | ||||
return _search(web) | return _search(web) | ||||
else: | else: | ||||
ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
symrev = 'tip' | symrev = 'tip' | ||||
def changelist(): | def changelist(): | ||||
revs = [] | revs = [] | ||||
A URL path argument is the changeset identifier to show. See ``hg help | A URL path argument is the changeset identifier to show. See ``hg help | ||||
revisions`` for possible values. If not defined, the ``tip`` changeset | revisions`` for possible values. If not defined, the ``tip`` changeset | ||||
will be shown. | will be shown. | ||||
The ``changeset`` template is rendered. Contents of the ``changesettag``, | The ``changeset`` template is rendered. Contents of the ``changesettag``, | ||||
``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many | ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many | ||||
templates related to diffs may all be used to produce the output. | templates related to diffs may all be used to produce the output. | ||||
""" | """ | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'changeset', | 'changeset', | ||||
**webutil.changesetentry(web, req, ctx)) | **webutil.changesetentry(web, ctx)) | ||||
rev = webcommand('rev')(changeset) | rev = webcommand('rev')(changeset) | ||||
def decodepath(path): | def decodepath(path): | ||||
"""Hook for mapping a path in the repository to a path in the | """Hook for mapping a path in the repository to a path in the | ||||
working copy. | working copy. | ||||
Extensions (e.g., largefiles) can override this to remap files in | Extensions (e.g., largefiles) can override this to remap files in | ||||
Because this handler can only show information for directories, it | Because this handler can only show information for directories, it | ||||
is recommended to use the ``file`` handler instead, as it can handle both | is recommended to use the ``file`` handler instead, as it can handle both | ||||
directories and files. | directories and files. | ||||
The ``manifest`` template will be rendered for this handler. | The ``manifest`` template will be rendered for this handler. | ||||
""" | """ | ||||
if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
else: | else: | ||||
ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
symrev = 'tip' | symrev = 'tip' | ||||
path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', '')) | ||||
mf = ctx.manifest() | mf = ctx.manifest() | ||||
node = ctx.node() | node = ctx.node() | ||||
files = {} | files = {} | ||||
The ``filediff`` template is rendered. | The ``filediff`` template is rendered. | ||||
This handler is registered under both the ``/diff`` and ``/filediff`` | This handler is registered under both the ``/diff`` and ``/filediff`` | ||||
paths. ``/diff`` is used in modern code. | paths. ``/diff`` is used in modern code. | ||||
""" | """ | ||||
fctx, ctx = None, None | fctx, ctx = None, None | ||||
try: | try: | ||||
fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
except LookupError: | except LookupError: | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
if path not in ctx.files(): | if path not in ctx.files(): | ||||
raise | raise | ||||
if fctx is not None: | if fctx is not None: | ||||
path = fctx.path() | path = fctx.path() | ||||
ctx = fctx.changectx() | ctx = fctx.changectx() | ||||
basectx = ctx.p1() | basectx = ctx.p1() | ||||
style = web.config('web', 'style') | style = web.config('web', 'style') | ||||
if 'style' in web.req.qsparams: | if 'style' in web.req.qsparams: | ||||
style = web.req.qsparams['style'] | style = web.req.qsparams['style'] | ||||
diffs = webutil.diffs(web, ctx, basectx, [path], style) | diffs = webutil.diffs(web, ctx, basectx, [path], style) | ||||
if fctx is not None: | if fctx is not None: | ||||
rename = webutil.renamelink(fctx) | rename = webutil.renamelink(fctx) | ||||
ctx = fctx | ctx = fctx | ||||
else: | else: | ||||
rename = [] | rename = [] | ||||
ctx = ctx | ctx = ctx | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'filediff', | 'filediff', | ||||
file=path, | file=path, | ||||
symrev=webutil.symrevorshortnode(req, ctx), | symrev=webutil.symrevorshortnode(web.req, ctx), | ||||
rename=rename, | rename=rename, | ||||
diff=diffs, | diff=diffs, | ||||
**pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | ||||
diff = webcommand('diff')(filediff) | diff = webcommand('diff')(filediff) | ||||
@webcommand('comparison') | @webcommand('comparison') | ||||
def comparison(web, req, tmpl): | def comparison(web, req, tmpl): | ||||
""" | """ | ||||
/comparison/{revision}/{path} | /comparison/{revision}/{path} | ||||
----------------------------- | ----------------------------- | ||||
Show a comparison between the old and new versions of a file from changes | Show a comparison between the old and new versions of a file from changes | ||||
made on a particular revision. | made on a particular revision. | ||||
This is similar to the ``diff`` handler. However, this form features | This is similar to the ``diff`` handler. However, this form features | ||||
a split or side-by-side diff rather than a unified diff. | 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 | The ``context`` query string argument can be used to control the lines of | ||||
context in the diff. | context in the diff. | ||||
The ``filecomparison`` template is rendered. | The ``filecomparison`` template is rendered. | ||||
""" | """ | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
if 'file' not in web.req.qsparams: | if 'file' not in web.req.qsparams: | ||||
raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | ||||
path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | path = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
parsecontext = lambda v: v == 'full' and -1 or int(v) | parsecontext = lambda v: v == 'full' and -1 or int(v) | ||||
if 'context' in web.req.qsparams: | if 'context' in web.req.qsparams: | ||||
context = parsecontext(web.req.qsparams['context']) | context = parsecontext(web.req.qsparams['context']) | ||||
else: | else: | ||||
ctx = fctx | ctx = fctx | ||||
else: | else: | ||||
rename = [] | rename = [] | ||||
ctx = ctx | ctx = ctx | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'filecomparison', | 'filecomparison', | ||||
file=path, | file=path, | ||||
symrev=webutil.symrevorshortnode(req, ctx), | symrev=webutil.symrevorshortnode(web.req, ctx), | ||||
rename=rename, | rename=rename, | ||||
leftrev=leftrev, | leftrev=leftrev, | ||||
leftnode=hex(leftnode), | leftnode=hex(leftnode), | ||||
rightrev=rightrev, | rightrev=rightrev, | ||||
rightnode=hex(rightnode), | rightnode=hex(rightnode), | ||||
comparison=comparison, | comparison=comparison, | ||||
**pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) | ||||
``ignoreblanklines`` query string arguments have the same meaning as | ``ignoreblanklines`` query string arguments have the same meaning as | ||||
their ``[annotate]`` config equivalents. It uses the hgrc boolean | their ``[annotate]`` config equivalents. It uses the hgrc boolean | ||||
parsing logic to interpret the value. e.g. ``0`` and ``false`` are | parsing logic to interpret the value. e.g. ``0`` and ``false`` are | ||||
false and ``1`` and ``true`` are true. If not defined, the server | false and ``1`` and ``true`` are true. If not defined, the server | ||||
default settings are used. | default settings are used. | ||||
The ``fileannotate`` template is rendered. | The ``fileannotate`` template is rendered. | ||||
""" | """ | ||||
fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
f = fctx.path() | f = fctx.path() | ||||
parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
ishead = fctx.filerev() in fctx.filelog().headrevs() | ishead = fctx.filerev() in fctx.filelog().headrevs() | ||||
# parents() is called once per line and several lines likely belong to | # parents() is called once per line and several lines likely belong to | ||||
# same revision. So it is worth caching. | # same revision. So it is worth caching. | ||||
# TODO there are still redundant operations within basefilectx.parents() | # TODO there are still redundant operations within basefilectx.parents() | ||||
# and from the fctx.annotate() call itself that could be cached. | # and from the fctx.annotate() call itself that could be cached. | ||||
yield p | yield p | ||||
def annotate(**map): | def annotate(**map): | ||||
if fctx.isbinary(): | if fctx.isbinary(): | ||||
mt = (mimetypes.guess_type(fctx.path())[0] | mt = (mimetypes.guess_type(fctx.path())[0] | ||||
or 'application/octet-stream') | or 'application/octet-stream') | ||||
lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)] | lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)] | ||||
else: | else: | ||||
lines = webutil.annotate(req, fctx, web.repo.ui) | lines = webutil.annotate(web.req, fctx, web.repo.ui) | ||||
previousrev = None | previousrev = None | ||||
blockparitygen = paritygen(1) | blockparitygen = paritygen(1) | ||||
for lineno, (aline, l) in enumerate(lines): | for lineno, (aline, l) in enumerate(lines): | ||||
f = aline.fctx | f = aline.fctx | ||||
rev = f.rev() | rev = f.rev() | ||||
if rev != previousrev: | if rev != previousrev: | ||||
blockhead = True | blockhead = True | ||||
"blockparity": blockparity, | "blockparity": blockparity, | ||||
"targetline": aline.lineno, | "targetline": aline.lineno, | ||||
"line": l, | "line": l, | ||||
"lineno": lineno + 1, | "lineno": lineno + 1, | ||||
"lineid": "l%d" % (lineno + 1), | "lineid": "l%d" % (lineno + 1), | ||||
"linenumber": "% 6d" % (lineno + 1), | "linenumber": "% 6d" % (lineno + 1), | ||||
"revdate": f.date()} | "revdate": f.date()} | ||||
diffopts = webutil.difffeatureopts(req, web.repo.ui, 'annotate') | diffopts = webutil.difffeatureopts(web.req, web.repo.ui, 'annotate') | ||||
diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} | diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'fileannotate', | 'fileannotate', | ||||
file=f, | file=f, | ||||
annotate=annotate, | annotate=annotate, | ||||
path=webutil.up(f), | path=webutil.up(f), | ||||
symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
rename=webutil.renamelink(fctx), | rename=webutil.renamelink(fctx), | ||||
permissions=fctx.manifest().flags(f), | permissions=fctx.manifest().flags(f), | ||||
ishead=int(ishead), | ishead=int(ishead), | ||||
diffopts=diffopts, | diffopts=diffopts, | ||||
**pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) | ||||
@webcommand('filelog') | @webcommand('filelog') | ||||
def filelog(web, req, tmpl): | def filelog(web, req, tmpl): | ||||
""" | """ | ||||
/filelog/{revision}/{path} | /filelog/{revision}/{path} | ||||
-------------------------- | -------------------------- | ||||
Show information about the history of a file in the repository. | Show information about the history of a file in the repository. | ||||
The ``revcount`` query string argument can be defined to control the | The ``revcount`` query string argument can be defined to control the | ||||
maximum number of entries to show. | maximum number of entries to show. | ||||
The ``filelog`` template will be rendered. | The ``filelog`` template will be rendered. | ||||
""" | """ | ||||
try: | try: | ||||
fctx = webutil.filectx(web.repo, req) | fctx = webutil.filectx(web.repo, web.req) | ||||
f = fctx.path() | f = fctx.path() | ||||
fl = fctx.filelog() | fl = fctx.filelog() | ||||
except error.LookupError: | except error.LookupError: | ||||
f = webutil.cleanpath(web.repo, web.req.qsparams['file']) | f = webutil.cleanpath(web.repo, web.req.qsparams['file']) | ||||
fl = web.repo.file(f) | fl = web.repo.file(f) | ||||
numrevs = len(fl) | numrevs = len(fl) | ||||
if not numrevs: # file doesn't exist at all | if not numrevs: # file doesn't exist at all | ||||
raise | raise | ||||
rev = webutil.changectx(web.repo, req).rev() | rev = webutil.changectx(web.repo, web.req).rev() | ||||
first = fl.linkrev(0) | first = fl.linkrev(0) | ||||
if rev < first: # current rev is from before file existed | if rev < first: # current rev is from before file existed | ||||
raise | raise | ||||
frev = numrevs - 1 | frev = numrevs - 1 | ||||
while fl.linkrev(frev) > rev: | while fl.linkrev(frev) > rev: | ||||
frev -= 1 | frev -= 1 | ||||
fctx = web.repo.filectx(f, fl.linkrev(frev)) | fctx = web.repo.filectx(f, fl.linkrev(frev)) | ||||
revcount = web.maxshortchanges | revcount = web.maxshortchanges | ||||
if 'revcount' in web.req.qsparams: | if 'revcount' in web.req.qsparams: | ||||
try: | try: | ||||
revcount = int(web.req.qsparams.get('revcount', revcount)) | revcount = int(web.req.qsparams.get('revcount', revcount)) | ||||
revcount = max(revcount, 1) | revcount = max(revcount, 1) | ||||
web.tmpl.defaults['sessionvars']['revcount'] = revcount | web.tmpl.defaults['sessionvars']['revcount'] = revcount | ||||
except ValueError: | except ValueError: | ||||
pass | pass | ||||
lrange = webutil.linerange(req) | lrange = webutil.linerange(web.req) | ||||
lessvars = copy.copy(web.tmpl.defaults['sessionvars']) | lessvars = copy.copy(web.tmpl.defaults['sessionvars']) | ||||
lessvars['revcount'] = max(revcount // 2, 1) | lessvars['revcount'] = max(revcount // 2, 1) | ||||
morevars = copy.copy(web.tmpl.defaults['sessionvars']) | morevars = copy.copy(web.tmpl.defaults['sessionvars']) | ||||
morevars['revcount'] = revcount * 2 | morevars['revcount'] = revcount * 2 | ||||
patch = 'patch' in web.req.qsparams | patch = 'patch' in web.req.qsparams | ||||
if patch: | if patch: | ||||
nav = revnav.gen(end - 1, revcount, count) | nav = revnav.gen(end - 1, revcount, count) | ||||
latestentry = entries[:1] | latestentry = entries[:1] | ||||
return web.sendtemplate( | return web.sendtemplate( | ||||
'filelog', | 'filelog', | ||||
file=f, | file=f, | ||||
nav=nav, | nav=nav, | ||||
symrev=webutil.symrevorshortnode(req, fctx), | symrev=webutil.symrevorshortnode(web.req, fctx), | ||||
entries=entries, | entries=entries, | ||||
descend=descend, | descend=descend, | ||||
patch=patch, | patch=patch, | ||||
latestentry=latestentry, | latestentry=latestentry, | ||||
linerange=linerange, | linerange=linerange, | ||||
revcount=revcount, | revcount=revcount, | ||||
morevars=morevars, | morevars=morevars, | ||||
lessvars=lessvars, | lessvars=lessvars, | ||||
reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame)) | reponame = re.sub(br"\W+", "-", os.path.basename(web.reponame)) | ||||
cnode = web.repo.lookup(key) | cnode = web.repo.lookup(key) | ||||
arch_version = key | arch_version = key | ||||
if cnode == key or key == 'tip': | if cnode == key or key == 'tip': | ||||
arch_version = short(cnode) | arch_version = short(cnode) | ||||
name = "%s-%s" % (reponame, arch_version) | name = "%s-%s" % (reponame, arch_version) | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
pats = [] | pats = [] | ||||
match = scmutil.match(ctx, []) | match = scmutil.match(ctx, []) | ||||
file = web.req.qsparams.get('file') | file = web.req.qsparams.get('file') | ||||
if file: | if file: | ||||
pats = ['path:' + file] | pats = ['path:' + file] | ||||
match = scmutil.match(ctx, pats, default='path') | match = scmutil.match(ctx, pats, default='path') | ||||
if pats: | if pats: | ||||
files = [f for f in ctx.manifest().keys() if match(f)] | files = [f for f in ctx.manifest().keys() if match(f)] | ||||
The ``graphtop`` query string argument can specify the starting changeset | The ``graphtop`` query string argument can specify the starting changeset | ||||
for producing ``jsdata`` variable that is used for rendering graph in | for producing ``jsdata`` variable that is used for rendering graph in | ||||
JavaScript. By default it has the same value as ``revision``. | JavaScript. By default it has the same value as ``revision``. | ||||
This handler will render the ``graph`` template. | This handler will render the ``graph`` template. | ||||
""" | """ | ||||
if 'node' in web.req.qsparams: | if 'node' in web.req.qsparams: | ||||
ctx = webutil.changectx(web.repo, req) | ctx = webutil.changectx(web.repo, web.req) | ||||
symrev = webutil.symrevorshortnode(req, ctx) | symrev = webutil.symrevorshortnode(web.req, ctx) | ||||
else: | else: | ||||
ctx = web.repo['tip'] | ctx = web.repo['tip'] | ||||
symrev = 'tip' | symrev = 'tip' | ||||
rev = ctx.rev() | rev = ctx.rev() | ||||
bg_height = 39 | bg_height = 39 | ||||
revcount = web.maxshortchanges | revcount = web.maxshortchanges | ||||
if 'revcount' in web.req.qsparams: | if 'revcount' in web.req.qsparams: |
def __len__(self): | def __len__(self): | ||||
return len(self.siblings) | return len(self.siblings) | ||||
def difffeatureopts(req, ui, section): | def difffeatureopts(req, ui, section): | ||||
diffopts = patch.difffeatureopts(ui, untrusted=True, | diffopts = patch.difffeatureopts(ui, untrusted=True, | ||||
section=section, whitespace=True) | section=section, whitespace=True) | ||||
for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'): | for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'): | ||||
v = req.req.qsparams.get(k) | v = req.qsparams.get(k) | ||||
if v is not None: | if v is not None: | ||||
v = util.parsebool(v) | v = util.parsebool(v) | ||||
setattr(diffopts, k, v if v is not None else True) | setattr(diffopts, k, v if v is not None else True) | ||||
return diffopts | return diffopts | ||||
def annotate(req, fctx, ui): | def annotate(req, fctx, ui): | ||||
diffopts = difffeatureopts(req, ui, 'annotate') | diffopts = difffeatureopts(req, ui, 'annotate') | ||||
except error.RepoError: | except error.RepoError: | ||||
man = repo.manifestlog._revlog | man = repo.manifestlog._revlog | ||||
ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))] | ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))] | ||||
return ctx | return ctx | ||||
def changectx(repo, req): | def changectx(repo, req): | ||||
changeid = "tip" | changeid = "tip" | ||||
if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
ipos = changeid.find(':') | ipos = changeid.find(':') | ||||
if ipos != -1: | if ipos != -1: | ||||
changeid = changeid[(ipos + 1):] | changeid = changeid[(ipos + 1):] | ||||
elif 'manifest' in req.req.qsparams: | elif 'manifest' in req.qsparams: | ||||
changeid = req.req.qsparams['manifest'] | changeid = req.qsparams['manifest'] | ||||
return changeidctx(repo, changeid) | return changeidctx(repo, changeid) | ||||
def basechangectx(repo, req): | def basechangectx(repo, req): | ||||
if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
ipos = changeid.find(':') | ipos = changeid.find(':') | ||||
if ipos != -1: | if ipos != -1: | ||||
changeid = changeid[:ipos] | changeid = changeid[:ipos] | ||||
return changeidctx(repo, changeid) | return changeidctx(repo, changeid) | ||||
return None | return None | ||||
def filectx(repo, req): | def filectx(repo, req): | ||||
if 'file' not in req.req.qsparams: | if 'file' not in req.qsparams: | ||||
raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') | ||||
path = cleanpath(repo, req.req.qsparams['file']) | path = cleanpath(repo, req.qsparams['file']) | ||||
if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
changeid = req.req.qsparams['node'] | changeid = req.qsparams['node'] | ||||
elif 'filenode' in req.req.qsparams: | elif 'filenode' in req.qsparams: | ||||
changeid = req.req.qsparams['filenode'] | changeid = req.qsparams['filenode'] | ||||
else: | else: | ||||
raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given') | raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given') | ||||
try: | try: | ||||
fctx = repo[changeid][path] | fctx = repo[changeid][path] | ||||
except error.RepoError: | except error.RepoError: | ||||
fctx = repo.filectx(path, fileid=changeid) | fctx = repo.filectx(path, fileid=changeid) | ||||
return fctx | return fctx | ||||
def linerange(req): | def linerange(req): | ||||
linerange = req.req.qsparams.getall('linerange') | linerange = req.qsparams.getall('linerange') | ||||
if not linerange: | if not linerange: | ||||
return None | return None | ||||
if len(linerange) > 1: | if len(linerange) > 1: | ||||
raise ErrorResponse(HTTP_BAD_REQUEST, | raise ErrorResponse(HTTP_BAD_REQUEST, | ||||
'redundant linerange parameter') | 'redundant linerange parameter') | ||||
try: | try: | ||||
fromline, toline = map(int, linerange[0].split(':', 1)) | fromline, toline = map(int, linerange[0].split(':', 1)) | ||||
except ValueError: | except ValueError: | ||||
parent=lambda **x: parents(ctx, rev - 1), | parent=lambda **x: parents(ctx, rev - 1), | ||||
child=lambda **x: children(ctx, rev + 1), | child=lambda **x: children(ctx, rev + 1), | ||||
changelogtag=showtags, | changelogtag=showtags, | ||||
files=files, | files=files, | ||||
) | ) | ||||
return entry | return entry | ||||
def symrevorshortnode(req, ctx): | def symrevorshortnode(req, ctx): | ||||
if 'node' in req.req.qsparams: | if 'node' in req.qsparams: | ||||
return templatefilters.revescape(req.req.qsparams['node']) | return templatefilters.revescape(req.qsparams['node']) | ||||
else: | else: | ||||
return short(ctx.node()) | return short(ctx.node()) | ||||
def changesetentry(web, req, ctx): | def changesetentry(web, ctx): | ||||
'''Obtain a dictionary to be used to render the "changeset" template.''' | '''Obtain a dictionary to be used to render the "changeset" template.''' | ||||
showtags = showtag(web.repo, web.tmpl, 'changesettag', ctx.node()) | showtags = showtag(web.repo, web.tmpl, 'changesettag', ctx.node()) | ||||
showbookmarks = showbookmark(web.repo, web.tmpl, 'changesetbookmark', | showbookmarks = showbookmark(web.repo, web.tmpl, 'changesetbookmark', | ||||
ctx.node()) | ctx.node()) | ||||
showbranch = nodebranchnodefault(ctx) | showbranch = nodebranchnodefault(ctx) | ||||
files = [] | files = [] | ||||
parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
for blockno, f in enumerate(ctx.files()): | for blockno, f in enumerate(ctx.files()): | ||||
template = 'filenodelink' if f in ctx else 'filenolink' | template = 'filenodelink' if f in ctx else 'filenolink' | ||||
files.append(web.tmpl(template, | files.append(web.tmpl(template, | ||||
node=ctx.hex(), file=f, blockno=blockno + 1, | node=ctx.hex(), file=f, blockno=blockno + 1, | ||||
parity=next(parity))) | parity=next(parity))) | ||||
basectx = basechangectx(web.repo, req) | basectx = basechangectx(web.repo, web.req) | ||||
if basectx is None: | if basectx is None: | ||||
basectx = ctx.p1() | basectx = ctx.p1() | ||||
style = web.config('web', 'style') | style = web.config('web', 'style') | ||||
if 'style' in req.req.qsparams: | if 'style' in web.req.qsparams: | ||||
style = req.req.qsparams['style'] | style = web.req.qsparams['style'] | ||||
diff = diffs(web, ctx, basectx, None, style) | diff = diffs(web, ctx, basectx, None, style) | ||||
parity = paritygen(web.stripecount) | parity = paritygen(web.stripecount) | ||||
diffstatsgen = diffstatgen(ctx, basectx) | diffstatsgen = diffstatgen(ctx, basectx) | ||||
diffstats = diffstat(web.tmpl, ctx, diffstatsgen, parity) | diffstats = diffstat(web.tmpl, ctx, diffstatsgen, parity) | ||||
return dict( | return dict( | ||||
diff=diff, | diff=diff, | ||||
symrev=symrevorshortnode(req, ctx), | symrev=symrevorshortnode(web.req, ctx), | ||||
basenode=basectx.hex(), | basenode=basectx.hex(), | ||||
changesettag=showtags, | changesettag=showtags, | ||||
changesetbookmark=showbookmarks, | changesetbookmark=showbookmarks, | ||||
changesetbranch=showbranch, | changesetbranch=showbranch, | ||||
files=files, | files=files, | ||||
diffsummary=lambda **x: diffsummary(diffstatsgen), | diffsummary=lambda **x: diffsummary(diffstatsgen), | ||||
diffstat=diffstats, | diffstat=diffstats, | ||||
archives=web.archivelist(ctx.hex()), | archives=web.archivelist(ctx.hex()), |