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

Kevin Gessner kevin at fogcreek.com
Tue Apr 5 09:23:26 CDT 2011


# HG changeset patch
# User Kevin Gessner <kevin at fogcreek.com>
# Date 1301949717 14400
# Node ID 2c8959c80e96668c00f836eee93daf48d0fde463
# Parent  086c9f203a53ee4b20a83d06c6e966ecc8a30cbf
hgweb: follow renames and 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.

Known shortcomings: revnavgen can create broken links because it doesn't account
for the different path in older revisions. nodefunc is broken because
it does not map numeric fileids to the correct filectx in allfctx.

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -631,20 +631,33 @@
     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,
+            l.insert(0, {"filerev": i,
                          "file": f,
                          "node": hex(iterfctx.node()),
                          "author": iterfctx.user(),
@@ -660,17 +673,35 @@
                          "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):
+        for fctx in allfctx:
+            try:
+                found = fctx.filectx(fileid=fileid)
+                found.node()
+                return found
+            except IndexError:
+                pass
+        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):


More information about the Mercurial-devel mailing list