[PATCH 2 of 8 V2] hgweb: handle a "linerange" request parameter in filelog command

Denis Laxalde denis at laxalde.org
Sat Feb 25 04:05:59 EST 2017


# HG changeset patch
# User Denis Laxalde <denis.laxalde at logilab.fr>
# Date 1484844060 -3600
#      Thu Jan 19 17:41:00 2017 +0100
# Node ID 43d99fe8dcb510540db19366fcac8159d4e26691
# Parent  17c6195ce42f3cbb47cee53aeb4e6a4e5074878a
# Available At https://hg.logilab.org/users/dlaxalde/hg
#              hg pull https://hg.logilab.org/users/dlaxalde/hg -r 43d99fe8dcb5
# EXP-Topic linerange-log/hgweb-filelog
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 the gitweb template got updated for now.

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -28,6 +28,7 @@ from .common import (
 
 from .. import (
     archival,
+    context,
     encoding,
     error,
     graphmod,
@@ -969,6 +970,8 @@ def filelog(web, req, tmpl):
         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'])
@@ -982,26 +985,48 @@ def filelog(web, req, tmpl):
     repo = web.repo
     revs = fctx.filelog().revs(start, end - 1)
     entries = []
-    for i in revs:
-        iterfctx = fctx.filectx(i)
-        entries.append(dict(
-            parity=next(parity),
-            filerev=i,
-            file=f,
-            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):
+            # follow renames accross filtered (not in range) revisions
+            path = c.path()
+            entries.append(dict(
+                parity=next(parity),
+                filerev=c.rev(),
+                file=path,
+                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)
+            entries.append(dict(
+                parity=next(parity),
+                filerev=i,
+                file=f,
+                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,
                 symrev=webutil.symrevorshortnode(req, fctx),
                 entries=entries,
                 latestentry=latestentry,
+                linerange=linerange,
                 revcount=revcount,
                 morevars=morevars,
                 lessvars=lessvars,
diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
--- a/mercurial/hgweb/webutil.py
+++ b/mercurial/hgweb/webutil.py
@@ -18,6 +18,7 @@ from ..node import hex, nullid, short
 
 from .common import (
     ErrorResponse,
+    HTTP_BAD_REQUEST,
     HTTP_NOT_FOUND,
     paritygen,
 )
@@ -313,6 +314,25 @@ def filectx(repo, req):
 
     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:
+        try:
+            fromline, toline = map(int, linerange[0].split(':', 1))
+        except ValueError:
+            raise ValueError('invalid linerange parameter')
+        return util.processlinerange(fromline, toline)
+    except ValueError 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 {
diff --git a/mercurial/templates/gitweb/filelog.tmpl b/mercurial/templates/gitweb/filelog.tmpl
--- a/mercurial/templates/gitweb/filelog.tmpl
+++ b/mercurial/templates/gitweb/filelog.tmpl
@@ -31,7 +31,9 @@ revisions |
 {nav%filenav}
 </div>
 
-<div class="title" >{file|urlescape}</div>
+<div class="title">{file|urlescape}{if(linerange,
+' (following lines {linerange}  <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">back to filelog</a>)'
+)}</div>
 
 <table>
 {entries%filelogentry}
diff --git a/tests/test-hgweb-filelog.t b/tests/test-hgweb-filelog.t
--- a/tests/test-hgweb-filelog.t
+++ b/tests/test-hgweb-filelog.t
@@ -654,6 +654,219 @@ before addition - error
   
   [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?style=gitweb&linerange=1:2')
+  200 Script output follows
+  
+  <?xml version="1.0" encoding="ascii"?>
+  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" 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-gitweb.css" type="text/css" />
+  <script type="text/javascript" src="/static/mercurial.js"></script>
+  
+  <title>test: File revisions</title>
+  <link rel="alternate" type="application/atom+xml"
+     href="/atom-log" title="Atom feed for test"/>
+  <link rel="alternate" type="application/rss+xml"
+     href="/rss-log" title="RSS feed for test"/>
+  </head>
+  <body>
+  
+  <div class="page_header">
+  <a href="https://mercurial-scm.org/" title="Mercurial" style="float: right;">Mercurial</a>
+  <a href="/">Mercurial</a>  / file revisions
+  </div>
+  
+  <div class="page_nav">
+  <a href="/summary?style=gitweb">summary</a> |
+  <a href="/shortlog?style=gitweb">shortlog</a> |
+  <a href="/log?style=gitweb">changelog</a> |
+  <a href="/graph?style=gitweb">graph</a> |
+  <a href="/tags?style=gitweb">tags</a> |
+  <a href="/bookmarks?style=gitweb">bookmarks</a> |
+  <a href="/branches?style=gitweb">branches</a> |
+  <a href="/file/tip/c?style=gitweb">file</a> |
+  revisions |
+  <a href="/annotate/tip/c?style=gitweb">annotate</a> |
+  <a href="/diff/tip/c?style=gitweb">diff</a> |
+  <a href="/comparison/tip/c?style=gitweb">comparison</a> |
+  <a href="/rss-log/tip/c">rss</a> |
+  <a href="/help?style=gitweb">help</a>
+  <br/>
+   
+  </div>
+  
+  <div class="title">c (following lines 1:2  <a href="/log/tip/c?style=gitweb">back to filelog</a>)</div>
+  
+  <table>
+  
+  <tr class="parity1">
+  <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+  <td><i>test</i></td>
+  <td>
+  <a class="list" href="/rev/46c1a66bd8fc?style=gitweb">
+  <b>change c</b>
+  <span class="logtags"><span class="branchtag" title="a-branch">a-branch</span> <span class="tagtag" title="tip">tip</span> </span>
+  </a>
+  </td>
+  <td class="link">
+  <a href="/file/46c1a66bd8fc/c?style=gitweb">file</a> |
+  <a href="/diff/46c1a66bd8fc/c?style=gitweb">diff</a> |
+  <a href="/annotate/46c1a66bd8fc/c?style=gitweb">annotate</a>
+  
+  </td>
+  </tr>
+  <tr class="parity0">
+  <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+  <td><i>test</i></td>
+  <td>
+  <a class="list" href="/rev/6563da9dcf87?style=gitweb">
+  <b>b</b>
+  <span class="logtags"></span>
+  </a>
+  </td>
+  <td class="link">
+  <a href="/file/6563da9dcf87/b?style=gitweb">file</a> |
+  <a href="/diff/6563da9dcf87/b?style=gitweb">diff</a> |
+  <a href="/annotate/6563da9dcf87/b?style=gitweb">annotate</a>
+  
+  </td>
+  </tr>
+  </table>
+  
+  <div class="page_nav">
+  <a href="/log/tip/c?linerange=1%3A2&revcount=30&style=gitweb">less</a>
+  <a href="/log/tip/c?linerange=1%3A2&revcount=120&style=gitweb">more</a>
+   
+  </div>
+  
+  <div class="page_footer">
+  <div class="page_footer_text">test</div>
+  <div class="rss_logo">
+  <a href="/rss-log">RSS</a>
+  <a href="/atom-log">Atom</a>
+  </div>
+  <br />
+  
+  </div>
+  </body>
+  </html>
+  
+  $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=gitweb&linerange=1:2&revcount=1')
+  200 Script output follows
+  
+  <?xml version="1.0" encoding="ascii"?>
+  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" 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-gitweb.css" type="text/css" />
+  <script type="text/javascript" src="/static/mercurial.js"></script>
+  
+  <title>test: File revisions</title>
+  <link rel="alternate" type="application/atom+xml"
+     href="/atom-log" title="Atom feed for test"/>
+  <link rel="alternate" type="application/rss+xml"
+     href="/rss-log" title="RSS feed for test"/>
+  </head>
+  <body>
+  
+  <div class="page_header">
+  <a href="https://mercurial-scm.org/" title="Mercurial" style="float: right;">Mercurial</a>
+  <a href="/">Mercurial</a>  / file revisions
+  </div>
+  
+  <div class="page_nav">
+  <a href="/summary?revcount=1&style=gitweb">summary</a> |
+  <a href="/shortlog?revcount=1&style=gitweb">shortlog</a> |
+  <a href="/log?revcount=1&style=gitweb">changelog</a> |
+  <a href="/graph?revcount=1&style=gitweb">graph</a> |
+  <a href="/tags?revcount=1&style=gitweb">tags</a> |
+  <a href="/bookmarks?revcount=1&style=gitweb">bookmarks</a> |
+  <a href="/branches?revcount=1&style=gitweb">branches</a> |
+  <a href="/file/tip/c?revcount=1&style=gitweb">file</a> |
+  revisions |
+  <a href="/annotate/tip/c?revcount=1&style=gitweb">annotate</a> |
+  <a href="/diff/tip/c?revcount=1&style=gitweb">diff</a> |
+  <a href="/comparison/tip/c?revcount=1&style=gitweb">comparison</a> |
+  <a href="/rss-log/tip/c">rss</a> |
+  <a href="/help?revcount=1&style=gitweb">help</a>
+  <br/>
+   
+  </div>
+  
+  <div class="title">c (following lines 1:2  <a href="/log/tip/c?revcount=1&style=gitweb">back to filelog</a>)</div>
+  
+  <table>
+  
+  <tr class="parity0">
+  <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
+  <td><i>test</i></td>
+  <td>
+  <a class="list" href="/rev/46c1a66bd8fc?revcount=1&style=gitweb">
+  <b>change c</b>
+  <span class="logtags"><span class="branchtag" title="a-branch">a-branch</span> <span class="tagtag" title="tip">tip</span> </span>
+  </a>
+  </td>
+  <td class="link">
+  <a href="/file/46c1a66bd8fc/c?revcount=1&style=gitweb">file</a> |
+  <a href="/diff/46c1a66bd8fc/c?revcount=1&style=gitweb">diff</a> |
+  <a href="/annotate/46c1a66bd8fc/c?revcount=1&style=gitweb">annotate</a>
+  
+  </td>
+  </tr>
+  </table>
+  
+  <div class="page_nav">
+  <a href="/log/tip/c?linerange=1%3A2&revcount=1&style=gitweb">less</a>
+  <a href="/log/tip/c?linerange=1%3A2&revcount=2&style=gitweb">more</a>
+   
+  </div>
+  
+  <div class="page_footer">
+  <div class="page_footer_text">test</div>
+  <div class="rss_logo">
+  <a href="/rss-log">RSS</a>
+  <a href="/atom-log">Atom</a>
+  </div>
+  <br />
+  
+  </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')


More information about the Mercurial-devel mailing list