[PATCH] hgweb: follow renames and copies in file log (issue1576)

Kevin Gessner kevin at fogcreek.com
Wed Apr 6 09:34:26 CDT 2011


# HG changeset patch
# User Kevin Gessner <kevin at fogcreek.com>
# Date 1301949717 14400
# Node ID 6df5de9f4dcbb71c4654a8d1c3181a96194d8579
# Parent  086c9f203a53ee4b20a83d06c6e966ecc8a30cbf
hgweb: follow renames and copies in file log (issue1576)

When walking the requested filectx finds a rename or copy, recursively walk
that filectx, adding as many changesets as needed, and following renames.

Links to older revisions must include the path that the file had in that
revision, so revnavgen and nodefunc must return path info from the correct
filectx.

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -631,21 +631,34 @@
     morevars = copy.copy(tmpl.defaults['sessionvars'])
     morevars['revcount'] = revcount * 2
 
-    count = fctx.filerev() + 1
-    start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
+    def follow(fctx):
+        l = []
+        while fctx:
+            l.insert(0, fctx)
+            renamed = fctx.filectx(0).renamed()
+            if renamed:
+                fctx = web.repo.filectx(renamed[0], fileid=renamed[1])
+            else:
+                fctx = None
+        return l
+
+    allfctx = follow(fctx)
+    count = sum(_fctx.filerev() + 1 for _fctx in allfctx)
+    start = max(0, count - revcount) # first rev on this page
     end = min(count, start + revcount) # last rev on this page
     parity = paritygen(web.stripecount, offset=start - end)
 
-    def entries(limit=0, **map):
+    def entries(fctx, limit=0, **map):
         l = []
 
         repo = web.repo
-        for i in xrange(start, end):
+        i = 0
+        nextfctx = None
+        while i <= fctx.filerev():
             iterfctx = fctx.filectx(i)
 
-            l.insert(0, {"parity": parity.next(),
-                         "filerev": i,
-                         "file": f,
+            l.insert(0, {"filerev": i,
+                         "file": iterfctx.path(),
                          "node": hex(iterfctx.node()),
                          "author": iterfctx.user(),
                          "date": iterfctx.date(),
@@ -660,17 +673,38 @@
                          "inbranch": webutil.nodeinbranch(repo, iterfctx),
                          "branches": webutil.nodebranchdict(repo, iterfctx)})
 
+            i += 1
+
+            renamed = iterfctx.renamed()
+            if renamed and not nextfctx:
+                nextfctx = repo.filectx(renamed[0], fileid=renamed[1])
+
+        if (limit == 0 or len(l) < limit) and nextfctx:
+            l.extend(entries(nextfctx, limit, **map))
+
         if limit > 0:
             l = l[:limit]
 
         for e in l:
+            e["parity"] = parity.next()
             yield e
 
-    nodefunc = lambda x: fctx.filectx(fileid=x)
+    def nodefunc(fileid):
+        if fileid == '0':
+            return allfctx[0].filectx(0)
+        if fileid == 'tip':
+            fctx = allfctx[len(allfctx)-1]
+            return fctx.filectx(fctx.filelog().tip())
+        for fctx in allfctx:
+            c = fctx.filerev()
+            if fileid < c:
+                return fctx.filectx(fileid)
+            fileid -= c
+        return None
     nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
     return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
-                entries=lambda **x: entries(limit=0, **x),
-                latestentry=lambda **x: entries(limit=1, **x),
+                entries=lambda **x: entries(fctx, limit=revcount, **x),
+                latestentry=lambda **x: entries(fctx, limit=1, **x),
                 revcount=revcount, morevars=morevars, lessvars=lessvars)
 
 def archive(web, req, tmpl):
diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
--- a/mercurial/hgweb/webutil.py
+++ b/mercurial/hgweb/webutil.py
@@ -21,6 +21,12 @@
     return up + "/"
 
 def revnavgen(pos, pagelen, limit, nodefunc):
+    def path(ctx):
+        fn = getattr(ctx, 'path', None)
+        if fn:
+            return fn()
+        return None
+
     def seq(factor, limit=None):
         if limit:
             yield limit
@@ -43,20 +49,24 @@
             break
         last = f
         if pos + f < limit:
-            navafter.append(("+%d" % f, hex(nodefunc(pos + f).node())))
+            ctx = nodefunc(pos + f)
+            navafter.append(("+%d" % f, hex(ctx.node()), path(ctx)))
         if pos - f >= 0:
-            navbefore.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
+            ctx = nodefunc(pos - f)
+            navbefore.insert(0, ("-%d" % f, hex(ctx.node()), path(ctx)))
 
-    navafter.append(("tip", "tip"))
+    ctx = nodefunc("tip")
+    navafter.append(("tip", "tip", path(ctx)))
     try:
-        navbefore.insert(0, ("(0)", hex(nodefunc('0').node())))
+        ctx = nodefunc("0")
+        navbefore.insert(0, ("(0)", hex(ctx.node()), path(ctx)))
     except error.RepoError:
         pass
 
     def gen(l):
         def f(**map):
-            for label, node in l:
-                yield {"label": label, "node": node}
+            for label, node, file in l:
+                yield {"label": label, "node": node, "file": file}
         return f
 
     return (dict(before=gen(navbefore), after=gen(navafter)),)
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
@@ -177,12 +177,12 @@
     <th class="author">author</th>
     <th class="description">description</th>
    </tr>
-   <tr class="parity0">
+   <tr class="parity1">
     <td class="age">1970-01-01</td>
     <td class="author">test</td>
     <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
    </tr>
-   <tr class="parity1">
+   <tr class="parity0">
     <td class="age">1970-01-01</td>
     <td class="author">test</td>
     <td class="description"><a href="/rev/5ed941583260">first a</a></td>
@@ -276,12 +276,12 @@
     <th class="author">author</th>
     <th class="description">description</th>
    </tr>
-   <tr class="parity0">
+   <tr class="parity1">
     <td class="age">1970-01-01</td>
     <td class="author">test</td>
     <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
    </tr>
-   <tr class="parity1">
+   <tr class="parity0">
     <td class="age">1970-01-01</td>
     <td class="author">test</td>
     <td class="description"><a href="/rev/5ed941583260">first a</a></td>
@@ -589,9 +589,9 @@
   
   <h2>c revision history</h2>
   
-  <p>navigate: <small class="navigate"><a href="/log/1a6696706df2/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
+  <p>navigate: <small class="navigate"><a href="/log/6563da9dcf87/b?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
   
-  <table class="logEntry parity0">
+  <table class="logEntry parity1">
    <tr>
     <th class="age">1970-01-01:</th>
     <th class="firstline"><a href="/rev/b7682196df1c?style=spartan">change c</a></th>
@@ -616,7 +616,7 @@
   </table>
   
   
-  <table class="logEntry parity1">
+  <table class="logEntry parity0">
    <tr>
     <th class="age">1970-01-01:</th>
     <th class="firstline"><a href="/rev/1a6696706df2?style=spartan">mv b</a></th>
@@ -649,6 +649,31 @@
   </table>
   
   
+  <table class="logEntry parity1">
+   <tr>
+    <th class="age">1970-01-01:</th>
+    <th class="firstline"><a href="/rev/6563da9dcf87?style=spartan">b</a></th>
+   </tr>
+   <tr>
+    <th class="revision">revision 0:</td>
+    <td class="node">
+     <a href="/file/6563da9dcf87/b?style=spartan">6563da9dcf87</a>
+     <a href="/diff/6563da9dcf87/b?style=spartan">(diff)</a>
+     <a href="/annotate/6563da9dcf87/b?style=spartan">(annotate)</a>
+    </td>
+   </tr>
+   
+   <tr>
+    <th class="author">author:</th>
+    <td class="author">&#116;&#101;&#115;&#116;</td>
+   </tr>
+   <tr>
+    <th class="date">date:</th>
+    <td class="date">Thu Jan 01 00:00:00 1970 +0000</td>
+   </tr>
+  </table>
+  
+  
   
   
   


More information about the Mercurial-devel mailing list