Mercurial > hg-stable
changeset 31670:5e6d44511317
hgweb: handle a "linerange" request parameter in filelog command
We now handle a "linerange" URL query parameter to filter filelog using
a logic similar to followlines() revset.
The URL syntax is: log/<rev>/<file>?linerange=<fromline>:<toline>
As a result, filelog entries only consists of revision changing specified
line range.
The linerange information is propagated to "more"/"less" navigation links but
not to numeric navigation links as this would apparently require a dedicated
"revnav" class.
Only update the "paper" template in this patch.
author | Denis Laxalde <denis.laxalde@logilab.fr> |
---|---|
date | Thu, 19 Jan 2017 17:41:00 +0100 |
parents | 1cbeefa59343 |
children | aaebc80c9f1d |
files | mercurial/hgweb/webcommands.py mercurial/hgweb/webutil.py mercurial/templates/paper/filelog.tmpl tests/test-hgweb-filelog.t |
diffstat | 4 files changed, 330 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/hgweb/webcommands.py Sun Mar 26 16:51:19 2017 -0700 +++ b/mercurial/hgweb/webcommands.py Thu Jan 19 17:41:00 2017 +0100 @@ -28,6 +28,7 @@ from .. import ( archival, + context, encoding, error, graphmod, @@ -968,6 +969,8 @@ except ValueError: pass + lrange = webutil.linerange(req) + lessvars = copy.copy(tmpl.defaults['sessionvars']) lessvars['revcount'] = max(revcount / 2, 1) morevars = copy.copy(tmpl.defaults['sessionvars']) @@ -996,24 +999,49 @@ path = fctx.path() return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle) - 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), - **webutil.commonentry(repo, iterfctx))) - entries.reverse() + 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 + ancestors = context.blockancestors(fctx, *lrange) + for i, (c, lr) in enumerate(ancestors, 1): + diffs = None + if patch: + diffs = diff(c) + # 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), + **webutil.commonentry(repo, c))) + 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), + **webutil.commonentry(repo, iterfctx))) + entries.reverse() + revnav = webutil.filerevnav(web.repo, fctx.path()) + nav = revnav.gen(end - 1, revcount, count) latestentry = entries[:1] - revnav = webutil.filerevnav(web.repo, fctx.path()) - nav = revnav.gen(end - 1, revcount, count) return tmpl("filelog", file=f, nav=nav, @@ -1021,6 +1049,7 @@ entries=entries, patch=patch, latestentry=latestentry, + linerange=linerange, revcount=revcount, morevars=morevars, lessvars=lessvars,
--- a/mercurial/hgweb/webutil.py Sun Mar 26 16:51:19 2017 -0700 +++ b/mercurial/hgweb/webutil.py Thu Jan 19 17:41:00 2017 +0100 @@ -18,6 +18,7 @@ from .common import ( ErrorResponse, + HTTP_BAD_REQUEST, HTTP_NOT_FOUND, paritygen, ) @@ -317,6 +318,26 @@ return fctx +def linerange(req): + linerange = req.form.get('linerange') + if linerange is None: + return None + if len(linerange) > 1: + raise ErrorResponse(HTTP_BAD_REQUEST, + 'redundant linerange parameter') + try: + fromline, toline = map(int, linerange[0].split(':', 1)) + except ValueError: + raise ErrorResponse(HTTP_BAD_REQUEST, + 'invalid linerange parameter') + try: + return util.processlinerange(fromline, toline) + except error.ParseError as exc: + raise ErrorResponse(HTTP_BAD_REQUEST, str(exc)) + +def formatlinerange(fromline, toline): + return '%d:%d' % (fromline + 1, toline) + def commonentry(repo, ctx): node = ctx.node() return {
--- a/mercurial/templates/paper/filelog.tmpl Sun Mar 26 16:51:19 2017 -0700 +++ b/mercurial/templates/paper/filelog.tmpl Thu Jan 19 17:41:00 2017 +0100 @@ -47,6 +47,8 @@ <h3> log {file|escape} @ {rev}:<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag} + {if(linerange, +' (following lines {linerange} <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">back to filelog</a>)')} </h3> <form class="search" action="{url|urlescape}log">
--- a/tests/test-hgweb-filelog.t Sun Mar 26 16:51:19 2017 -0700 +++ b/tests/test-hgweb-filelog.t Thu Jan 19 17:41:00 2017 +0100 @@ -190,6 +190,7 @@ <h3> log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a> <span class="branchname">a-branch</span> + </h3> <form class="search" action="/log"> @@ -311,6 +312,7 @@ <h3> log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a> <span class="branchname">a-branch</span> + </h3> <form class="search" action="/log"> @@ -432,6 +434,7 @@ <h3> log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a> <span class="tag">a-tag</span> <span class="tag">a-bookmark</span> + </h3> <form class="search" action="/log"> @@ -544,6 +547,7 @@ <h3> log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a> <span class="tag">a-tag</span> <span class="tag">a-bookmark</span> + </h3> <form class="search" action="/log"> @@ -660,6 +664,264 @@ [1] + $ hg log -r 'followlines(c, 1:2, startrev=tip) and follow(c)' + changeset: 0:6563da9dcf87 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + changeset: 7:46c1a66bd8fc + branch: a-branch + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: change c + + $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1:2') + 200 Script output follows + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"> + <head> + <link rel="icon" href="/static/hgicon.png" type="image/png" /> + <meta name="robots" content="index, nofollow" /> + <link rel="stylesheet" href="/static/style-paper.css" type="text/css" /> + <script type="text/javascript" src="/static/mercurial.js"></script> + + <title>test: c history</title> + <link rel="alternate" type="application/atom+xml" + href="/atom-log/tip/c" title="Atom feed for test:c" /> + <link rel="alternate" type="application/rss+xml" + href="/rss-log/tip/c" title="RSS feed for test:c" /> + </head> + <body> + + <div class="container"> + <div class="menu"> + <div class="logo"> + <a href="https://mercurial-scm.org/"> + <img src="/static/hglogo.png" alt="mercurial" /></a> + </div> + <ul> + <li><a href="/shortlog/tip">log</a></li> + <li><a href="/graph/tip">graph</a></li> + <li><a href="/tags">tags</a></li> + <li><a href="/bookmarks">bookmarks</a></li> + <li><a href="/branches">branches</a></li> + </ul> + <ul> + <li><a href="/rev/tip">changeset</a></li> + <li><a href="/file/tip">browse</a></li> + </ul> + <ul> + <li><a href="/file/tip/c">file</a></li> + <li><a href="/diff/tip/c">diff</a></li> + <li><a href="/comparison/tip/c">comparison</a></li> + <li><a href="/annotate/tip/c">annotate</a></li> + <li class="active">file log</li> + <li><a href="/raw-file/tip/c">raw</a></li> + </ul> + <ul> + <li><a href="/help">help</a></li> + </ul> + <div class="atom-logo"> + <a href="/atom-log/tip/c" title="subscribe to atom feed"> + <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" /> + </a> + </div> + </div> + + <div class="main"> + <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2> + <h3> + log c @ 7:<a href="/rev/46c1a66bd8fc">46c1a66bd8fc</a> + <span class="branchname">a-branch</span> <span class="tag">tip</span> + (following lines 1:2 <a href="/log/tip/c">back to filelog</a>) + </h3> + + <form class="search" action="/log"> + + <p><input name="rev" id="search1" type="text" size="30" /></p> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> + </form> + + <div class="navigate"> + <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a> + <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a> + | </div> + + <table class="bigtable"> + <thead> + <tr> + <th class="age">age</th> + <th class="author">author</th> + <th class="description">description</th> + </tr> + </thead> + <tbody class="stripes2"> + <tr> + <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td> + <td class="author">test</td> + <td class="description"> + <a href="/rev/46c1a66bd8fc">change c</a> + <span class="branchhead">a-branch</span> <span class="tag">tip</span> + </td> + </tr> + + <tr> + <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td> + <td class="author">test</td> + <td class="description"> + <a href="/rev/6563da9dcf87">b</a> + + </td> + </tr> + + + </tbody> + </table> + + <div class="navigate"> + <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a> + <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a> + | + </div> + + </div> + </div> + + + + </body> + </html> + + $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1%3A2&revcount=1') + 200 Script output follows + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"> + <head> + <link rel="icon" href="/static/hgicon.png" type="image/png" /> + <meta name="robots" content="index, nofollow" /> + <link rel="stylesheet" href="/static/style-paper.css" type="text/css" /> + <script type="text/javascript" src="/static/mercurial.js"></script> + + <title>test: c history</title> + <link rel="alternate" type="application/atom+xml" + href="/atom-log/tip/c" title="Atom feed for test:c" /> + <link rel="alternate" type="application/rss+xml" + href="/rss-log/tip/c" title="RSS feed for test:c" /> + </head> + <body> + + <div class="container"> + <div class="menu"> + <div class="logo"> + <a href="https://mercurial-scm.org/"> + <img src="/static/hglogo.png" alt="mercurial" /></a> + </div> + <ul> + <li><a href="/shortlog/tip?revcount=1">log</a></li> + <li><a href="/graph/tip?revcount=1">graph</a></li> + <li><a href="/tags?revcount=1">tags</a></li> + <li><a href="/bookmarks?revcount=1">bookmarks</a></li> + <li><a href="/branches?revcount=1">branches</a></li> + </ul> + <ul> + <li><a href="/rev/tip?revcount=1">changeset</a></li> + <li><a href="/file/tip?revcount=1">browse</a></li> + </ul> + <ul> + <li><a href="/file/tip/c?revcount=1">file</a></li> + <li><a href="/diff/tip/c?revcount=1">diff</a></li> + <li><a href="/comparison/tip/c?revcount=1">comparison</a></li> + <li><a href="/annotate/tip/c?revcount=1">annotate</a></li> + <li class="active">file log</li> + <li><a href="/raw-file/tip/c">raw</a></li> + </ul> + <ul> + <li><a href="/help?revcount=1">help</a></li> + </ul> + <div class="atom-logo"> + <a href="/atom-log/tip/c" title="subscribe to atom feed"> + <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" /> + </a> + </div> + </div> + + <div class="main"> + <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2> + <h3> + log c @ 7:<a href="/rev/46c1a66bd8fc?revcount=1">46c1a66bd8fc</a> + <span class="branchname">a-branch</span> <span class="tag">tip</span> + (following lines 1:2 <a href="/log/tip/c?revcount=1">back to filelog</a>) + </h3> + + <form class="search" action="/log"> + <input type="hidden" name="revcount" value="1" /> + <p><input name="rev" id="search1" type="text" size="30" /></p> + <div id="hint">Find changesets by keywords (author, files, the commit message), revision + number or hash, or <a href="/help/revsets">revset expression</a>.</div> + </form> + + <div class="navigate"> + <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a> + <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a> + | </div> + + <table class="bigtable"> + <thead> + <tr> + <th class="age">age</th> + <th class="author">author</th> + <th class="description">description</th> + </tr> + </thead> + <tbody class="stripes2"> + <tr> + <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td> + <td class="author">test</td> + <td class="description"> + <a href="/rev/46c1a66bd8fc?revcount=1">change c</a> + <span class="branchhead">a-branch</span> <span class="tag">tip</span> + </td> + </tr> + + + </tbody> + </table> + + <div class="navigate"> + <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a> + <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a> + | + </div> + + </div> + </div> + + + + </body> + </html> + + $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1' --headeronly) + 400 invalid linerange parameter + [1] + $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:a' --headeronly) + 400 invalid linerange parameter + [1] + $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:2&linerange=3:4' --headeronly) + 400 redundant linerange parameter + [1] + $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=3:2' --headeronly) + 400 line range must be positive + [1] + $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=0:1' --headeronly) + 400 fromline must be strictly positive + [1] + should show base link, use spartan because it shows it $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=spartan') @@ -829,6 +1091,7 @@ <h3> log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a> <span class="branchname">a-branch</span> + </h3> <form class="search" action="/log">