Patchwork [2,of,3] hgweb: move entry-preparing code from webcommands to webutils.makeentry()

login
register
mail settings
Submitter Anton Shestakov
Date Nov. 17, 2015, 1:33 p.m.
Message ID <8fcd6c9323c1affd43a7.1447767237@neuro>
Download mbox | patch
Permalink /patch/11427/
State Superseded
Delegated to: Yuya Nishihara
Headers show

Comments

Anton Shestakov - Nov. 17, 2015, 1:33 p.m.
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1447396536 -28800
#      Fri Nov 13 14:35:36 2015 +0800
# Node ID 8fcd6c9323c1affd43a7ac5ee3b3c598b646bde7
# Parent  f6968049b048311f60d496f3c899e58fb649d884
hgweb: move entry-preparing code from webcommands to webutils.makeentry()

The new function is used to prefill basic information about a ctx, such as
revision number and hash, author, commit message, etc. Before, every webcommand
used to get this basic information on its own using some boilerplate code, and
some things in some places just weren't available (e.g. branch/tag/bookmark
info for the current hgweb revision in filelog).
Yuya Nishihara - Nov. 18, 2015, 2:27 p.m.
On Tue, 17 Nov 2015 21:33:57 +0800, Anton Shestakov wrote:
> # HG changeset patch
> # User Anton Shestakov <av6@dwimlabs.net>
> # Date 1447396536 -28800
> #      Fri Nov 13 14:35:36 2015 +0800
> # Node ID 8fcd6c9323c1affd43a7ac5ee3b3c598b646bde7
> # Parent  f6968049b048311f60d496f3c899e58fb649d884
> hgweb: move entry-preparing code from webcommands to webutils.makeentry()
> 
> The new function is used to prefill basic information about a ctx, such as
> revision number and hash, author, commit message, etc. Before, every webcommand
> used to get this basic information on its own using some boilerplate code, and
> some things in some places just weren't available (e.g. branch/tag/bookmark
> info for the current hgweb revision in filelog).
> 
> diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
> --- a/mercurial/hgweb/webcommands.py
> +++ b/mercurial/hgweb/webcommands.py
> @@ -116,24 +116,14 @@ def _filerevision(web, req, tmpl, fctx):
>                     "linenumber": "% 6d" % (lineno + 1),
>                     "parity": parity.next()}
>  
> -    return tmpl("filerevision",
> -                file=f,
> -                path=webutil.up(f),
> -                text=lines(),
> -                rev=fctx.rev(),
> -                symrev=webutil.symrevorshortnode(req, fctx),
> -                node=fctx.hex(),
> -                author=fctx.user(),
> -                date=fctx.date(),
> -                desc=fctx.description(),
> -                extra=fctx.extra(),
> -                branch=webutil.nodebranchnodefault(fctx),
> -                parent=webutil.parents(fctx),
> -                child=webutil.children(fctx),
> -                rename=webutil.renamelink(fctx),
> -                tags=webutil.nodetagsdict(web.repo, fctx.node()),
> -                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
> -                permissions=fctx.manifest().flags(f))
> +    return tmpl("filerevision", **webutil.makeentry(web.repo, fctx, {
> +        'file': f,
> +        'path': webutil.up(f),
> +        'text': lines(),
> +        'symrev': webutil.symrevorshortnode(req, fctx),
> +        'rename': webutil.renamelink(fctx),
> +        'permissions': fctx.manifest().flags(f),
> +    }))

This is minor thing, but I prefer

    return tmpl("filerevision",
                file=f,
                ...
                **webutil.commonentry(web.repo, fctx))

because webutil has similar functions named xxxentry(). A good thing of this
style is that you can get TypeError if rev=ctx.rev() is specified twice, for
example.
Anton Shestakov - Nov. 18, 2015, 3:19 p.m.
On Wed, 18 Nov 2015 23:27:18 +0900
Yuya Nishihara <yuya@tcha.org> wrote:

> On Tue, 17 Nov 2015 21:33:57 +0800, Anton Shestakov wrote:
> > # HG changeset patch
> > # User Anton Shestakov <av6@dwimlabs.net>
> > # Date 1447396536 -28800
> > #      Fri Nov 13 14:35:36 2015 +0800
> > # Node ID 8fcd6c9323c1affd43a7ac5ee3b3c598b646bde7
> > # Parent  f6968049b048311f60d496f3c899e58fb649d884
> > hgweb: move entry-preparing code from webcommands to
> > webutils.makeentry()
> > 
> > The new function is used to prefill basic information about a ctx,
> > such as revision number and hash, author, commit message, etc.
> > Before, every webcommand used to get this basic information on its
> > own using some boilerplate code, and some things in some places
> > just weren't available (e.g. branch/tag/bookmark info for the
> > current hgweb revision in filelog).
> > 
> > diff --git a/mercurial/hgweb/webcommands.py
> > b/mercurial/hgweb/webcommands.py ---
> > a/mercurial/hgweb/webcommands.py +++
> > b/mercurial/hgweb/webcommands.py @@ -116,24 +116,14 @@ def
> > _filerevision(web, req, tmpl, fctx): "linenumber": "% 6d" % (lineno
> > + 1), "parity": parity.next()}
> >  
> > -    return tmpl("filerevision",
> > -                file=f,
> > -                path=webutil.up(f),
> > -                text=lines(),
> > -                rev=fctx.rev(),
> > -                symrev=webutil.symrevorshortnode(req, fctx),
> > -                node=fctx.hex(),
> > -                author=fctx.user(),
> > -                date=fctx.date(),
> > -                desc=fctx.description(),
> > -                extra=fctx.extra(),
> > -                branch=webutil.nodebranchnodefault(fctx),
> > -                parent=webutil.parents(fctx),
> > -                child=webutil.children(fctx),
> > -                rename=webutil.renamelink(fctx),
> > -                tags=webutil.nodetagsdict(web.repo, fctx.node()),
> > -                bookmarks=webutil.nodebookmarksdict(web.repo,
> > fctx.node()),
> > -                permissions=fctx.manifest().flags(f))
> > +    return tmpl("filerevision", **webutil.makeentry(web.repo,
> > fctx, {
> > +        'file': f,
> > +        'path': webutil.up(f),
> > +        'text': lines(),
> > +        'symrev': webutil.symrevorshortnode(req, fctx),
> > +        'rename': webutil.renamelink(fctx),
> > +        'permissions': fctx.manifest().flags(f),
> > +    }))  
> 
> This is minor thing, but I prefer
> 
>     return tmpl("filerevision",
>                 file=f,
>                 ...
>                 **webutil.commonentry(web.repo, fctx))
> 
> because webutil has similar functions named xxxentry(). A good thing
> of this style is that you can get TypeError if rev=ctx.rev() is
> specified twice, for example.

It might be a nice bonus, but makeentry() is supposed to first fill some
defaults and then allow to override them (that happens in
webutil.changelist() entry with "parent" and "child"). So sometimes
you're supposed to have a duplicate key. Also, because the result of
this function needs to have lower priority than the explicit keyword
args to tmpl(), and it's a syntax error to have something like this:

tmpl("filerevision", **commonentry(web.repo, fctx), file=f)

... the only other possible syntax I see is this:

tmpl("filerevision", **commonentry(web.repo, fctx, file=f))

Which, thanks to python's coding style, quickly devolves into:

tmpl("filerevision", **commonentry(web.repo, fctx,
                                   file=f,
                                   text=lines(),
                                   ...))

And that indentation level kills my soul. So I stick with {}, which
needs to be indented much less.

I'm open to different names for the function (after all, naming is
hard), but if I saw a function called commonentry(), I'd think it's
what there's in makeentry() now, but without entry.update(more). I.e.
commonentry() implies that it just fills common data and then you're
supposed to .update() it with extra things on your own. makeentry()
sounds like it could do something like that (and it does).

Anyway, I can resend fixed patch #1 and then, if you would expand you
yesterday's idea and/or give some hints, I could work on making a
separate templatekw table for hgweb instead. That sounds like a much
better idea, actually.
Yuya Nishihara - Nov. 20, 2015, 1:40 p.m.
On Wed, 18 Nov 2015 23:19:26 +0800, Anton Shestakov wrote:
> On Wed, 18 Nov 2015 23:27:18 +0900
> Yuya Nishihara <yuya@tcha.org> wrote:
> > On Tue, 17 Nov 2015 21:33:57 +0800, Anton Shestakov wrote:
> > > +    return tmpl("filerevision", **webutil.makeentry(web.repo,
> > > fctx, {
> > > +        'file': f,
> > > +        'path': webutil.up(f),
> > > +        'text': lines(),
> > > +        'symrev': webutil.symrevorshortnode(req, fctx),
> > > +        'rename': webutil.renamelink(fctx),
> > > +        'permissions': fctx.manifest().flags(f),
> > > +    }))  
> > 
> > This is minor thing, but I prefer
> > 
> >     return tmpl("filerevision",
> >                 file=f,
> >                 ...
> >                 **webutil.commonentry(web.repo, fctx))
> > 
> > because webutil has similar functions named xxxentry(). A good thing
> > of this style is that you can get TypeError if rev=ctx.rev() is
> > specified twice, for example.
> 
> It might be a nice bonus, but makeentry() is supposed to first fill some
> defaults and then allow to override them (that happens in
> webutil.changelist() entry with "parent" and "child"). So sometimes
> you're supposed to have a duplicate key.

Is it common to override the defaults? If not, we can do it explicitly
to show that it does change the behavior of common keywords.

  entry = commonentry(web.repo, ctx)
  entry['parent'] = ...
  return entry

> Also, because the result of
> this function needs to have lower priority than the explicit keyword
> args to tmpl(), and it's a syntax error to have something like this:
> 
> tmpl("filerevision", **commonentry(web.repo, fctx), file=f)
> 
> ... the only other possible syntax I see is this:
> 
> tmpl("filerevision", **commonentry(web.repo, fctx, file=f))
> 
> Which, thanks to python's coding style, quickly devolves into:
> 
> tmpl("filerevision", **commonentry(web.repo, fctx,
>                                    file=f,
>                                    text=lines(),
>                                    ...))
> 
> And that indentation level kills my soul. So I stick with {}, which
> needs to be indented much less.

Yep, I hate it too.
Anton Shestakov - Nov. 20, 2015, 3:11 p.m.
On Fri, 20 Nov 2015 22:40:15 +0900
Yuya Nishihara <yuya@tcha.org> wrote:

> On Wed, 18 Nov 2015 23:19:26 +0800, Anton Shestakov wrote:
> > On Wed, 18 Nov 2015 23:27:18 +0900
> > Yuya Nishihara <yuya@tcha.org> wrote:  
> > > On Tue, 17 Nov 2015 21:33:57 +0800, Anton Shestakov wrote:  
> > > > +    return tmpl("filerevision", **webutil.makeentry(web.repo,
> > > > fctx, {
> > > > +        'file': f,
> > > > +        'path': webutil.up(f),
> > > > +        'text': lines(),
> > > > +        'symrev': webutil.symrevorshortnode(req, fctx),
> > > > +        'rename': webutil.renamelink(fctx),
> > > > +        'permissions': fctx.manifest().flags(f),
> > > > +    }))    
> > > 
> > > This is minor thing, but I prefer
> > > 
> > >     return tmpl("filerevision",
> > >                 file=f,
> > >                 ...
> > >                 **webutil.commonentry(web.repo, fctx))
> > > 
> > > because webutil has similar functions named xxxentry(). A good
> > > thing of this style is that you can get TypeError if
> > > rev=ctx.rev() is specified twice, for example.  
> > 
> > It might be a nice bonus, but makeentry() is supposed to first fill
> > some defaults and then allow to override them (that happens in
> > webutil.changelist() entry with "parent" and "child"). So sometimes
> > you're supposed to have a duplicate key.  
> 
> Is it common to override the defaults? If not, we can do it explicitly
> to show that it does change the behavior of common keywords.
> 
>   entry = commonentry(web.repo, ctx)
>   entry['parent'] = ...
>   return entry

Overriding defaults is not common, but happens in about 3 places. But
all of the users of this function add at least one (and up to 10) more
item to the entry, so I decided to have entry.update() in makeentry()
as a shortcut.

OK, seeing how it's not very obvious what happens to the dict passed to
makeentry(), let me do this your way and see if commonentry() looks
better.
Yuya Nishihara - Nov. 20, 2015, 3:32 p.m.
On Fri, 20 Nov 2015 23:11:20 +0800, Anton Shestakov wrote:
> On Fri, 20 Nov 2015 22:40:15 +0900
> Yuya Nishihara <yuya@tcha.org> wrote:
> 
> > On Wed, 18 Nov 2015 23:19:26 +0800, Anton Shestakov wrote:
> > > On Wed, 18 Nov 2015 23:27:18 +0900
> > > Yuya Nishihara <yuya@tcha.org> wrote:  
> > > > On Tue, 17 Nov 2015 21:33:57 +0800, Anton Shestakov wrote:  
> > > > > +    return tmpl("filerevision", **webutil.makeentry(web.repo,
> > > > > fctx, {
> > > > > +        'file': f,
> > > > > +        'path': webutil.up(f),
> > > > > +        'text': lines(),
> > > > > +        'symrev': webutil.symrevorshortnode(req, fctx),
> > > > > +        'rename': webutil.renamelink(fctx),
> > > > > +        'permissions': fctx.manifest().flags(f),
> > > > > +    }))    
> > > > 
> > > > This is minor thing, but I prefer
> > > > 
> > > >     return tmpl("filerevision",
> > > >                 file=f,
> > > >                 ...
> > > >                 **webutil.commonentry(web.repo, fctx))
> > > > 
> > > > because webutil has similar functions named xxxentry(). A good
> > > > thing of this style is that you can get TypeError if
> > > > rev=ctx.rev() is specified twice, for example.  
> > > 
> > > It might be a nice bonus, but makeentry() is supposed to first fill
> > > some defaults and then allow to override them (that happens in
> > > webutil.changelist() entry with "parent" and "child"). So sometimes
> > > you're supposed to have a duplicate key.  
> > 
> > Is it common to override the defaults? If not, we can do it explicitly
> > to show that it does change the behavior of common keywords.
> > 
> >   entry = commonentry(web.repo, ctx)
> >   entry['parent'] = ...
> >   return entry
> 
> Overriding defaults is not common, but happens in about 3 places.

Perhaps some of them can be avoided by passing fctx instead of ctx?
I didn't try it yet. If it's possible, it should be done by a separate patch.

> But
> all of the users of this function add at least one (and up to 10) more
> item to the entry, so I decided to have entry.update() in makeentry()
> as a shortcut.
> 
> OK, seeing how it's not very obvious what happens to the dict passed to
> makeentry(), let me do this your way and see if commonentry() looks
> better.

Thanks, and sorry for late reply. I found the previous email in my gmail's
spam folder.

Patch

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -116,24 +116,14 @@  def _filerevision(web, req, tmpl, fctx):
                    "linenumber": "% 6d" % (lineno + 1),
                    "parity": parity.next()}
 
-    return tmpl("filerevision",
-                file=f,
-                path=webutil.up(f),
-                text=lines(),
-                rev=fctx.rev(),
-                symrev=webutil.symrevorshortnode(req, fctx),
-                node=fctx.hex(),
-                author=fctx.user(),
-                date=fctx.date(),
-                desc=fctx.description(),
-                extra=fctx.extra(),
-                branch=webutil.nodebranchnodefault(fctx),
-                parent=webutil.parents(fctx),
-                child=webutil.children(fctx),
-                rename=webutil.renamelink(fctx),
-                tags=webutil.nodetagsdict(web.repo, fctx.node()),
-                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
-                permissions=fctx.manifest().flags(f))
+    return tmpl("filerevision", **webutil.makeentry(web.repo, fctx, {
+        'file': f,
+        'path': webutil.up(f),
+        'text': lines(),
+        'symrev': webutil.symrevorshortnode(req, fctx),
+        'rename': webutil.renamelink(fctx),
+        'permissions': fctx.manifest().flags(f),
+    }))
 
 @webcommand('file')
 def file(web, req, tmpl):
@@ -261,22 +251,11 @@  def _search(web, req, tmpl):
             showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
             files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
 
-            yield tmpl('searchentry',
-                       parity=parity.next(),
-                       author=ctx.user(),
-                       parent=lambda **x: webutil.parents(ctx),
-                       child=lambda **x: webutil.children(ctx),
-                       changelogtag=showtags,
-                       desc=ctx.description(),
-                       extra=ctx.extra(),
-                       date=ctx.date(),
-                       files=files,
-                       rev=ctx.rev(),
-                       node=hex(n),
-                       tags=webutil.nodetagsdict(web.repo, n),
-                       bookmarks=webutil.nodebookmarksdict(web.repo, n),
-                       inbranch=webutil.nodeinbranch(web.repo, ctx),
-                       branches=webutil.nodebranchdict(web.repo, ctx))
+            yield tmpl('searchentry', **webutil.makeentry(web.repo, ctx, {
+                'parity': parity.next(),
+                'changelogtag': showtags,
+                'files': files,
+            }))
 
             if count >= revcount:
                 break
@@ -545,21 +524,15 @@  def manifest(web, req, tmpl):
                    "emptydirs": "/".join(emptydirs),
                    "basename": d}
 
-    return tmpl("manifest",
-                rev=ctx.rev(),
-                symrev=symrev,
-                node=hex(node),
-                path=abspath,
-                up=webutil.up(abspath),
-                upparity=parity.next(),
-                fentries=filelist,
-                dentries=dirlist,
-                archives=web.archivelist(hex(node)),
-                tags=webutil.nodetagsdict(web.repo, node),
-                bookmarks=webutil.nodebookmarksdict(web.repo, node),
-                branch=webutil.nodebranchnodefault(ctx),
-                inbranch=webutil.nodeinbranch(web.repo, ctx),
-                branches=webutil.nodebranchdict(web.repo, ctx))
+    return tmpl("manifest", **webutil.makeentry(web.repo, ctx, {
+        'symrev': symrev,
+        'path': abspath,
+        'up': webutil.up(abspath),
+        'upparity': parity.next(),
+        'fentries': filelist,
+        'dentries': dirlist,
+        'archives': web.archivelist(hex(node)),
+    }))
 
 @webcommand('tags')
 def tags(web, req, tmpl):
@@ -693,22 +666,10 @@  def summary(web, req, tmpl):
             revs = web.repo.changelog.revs(start, end - 1)
         for i in revs:
             ctx = web.repo[i]
-            n = ctx.node()
-            hn = hex(n)
 
-            l.append(tmpl(
-               'shortlogentry',
-                parity=parity.next(),
-                author=ctx.user(),
-                desc=ctx.description(),
-                extra=ctx.extra(),
-                date=ctx.date(),
-                rev=i,
-                node=hn,
-                tags=webutil.nodetagsdict(web.repo, n),
-                bookmarks=webutil.nodebookmarksdict(web.repo, n),
-                inbranch=webutil.nodeinbranch(web.repo, ctx),
-                branches=webutil.nodebranchdict(web.repo, ctx)))
+            l.append(tmpl('shortlogentry', **webutil.makeentry(web.repo, ctx, {
+                'parity': parity.next(),
+            })))
 
         l.reverse()
         yield l
@@ -753,12 +714,8 @@  def filediff(web, req, tmpl):
             raise
 
     if fctx is not None:
-        n = fctx.node()
         path = fctx.path()
         ctx = fctx.changectx()
-    else:
-        n = ctx.node()
-        # path already defined in except clause
 
     parity = paritygen(web.stripecount)
     style = web.config('web', 'style', 'paper')
@@ -772,22 +729,12 @@  def filediff(web, req, tmpl):
     else:
         rename = []
         ctx = ctx
-    return tmpl("filediff",
-                file=path,
-                node=hex(n),
-                rev=ctx.rev(),
-                symrev=webutil.symrevorshortnode(req, ctx),
-                date=ctx.date(),
-                desc=ctx.description(),
-                extra=ctx.extra(),
-                author=ctx.user(),
-                rename=rename,
-                branch=webutil.nodebranchnodefault(ctx),
-                parent=webutil.parents(ctx),
-                child=webutil.children(ctx),
-                tags=webutil.nodetagsdict(web.repo, n),
-                bookmarks=webutil.nodebookmarksdict(web.repo, n),
-                diff=diffs)
+    return tmpl("filediff", **webutil.makeentry(web.repo, ctx, {
+        'file': path,
+        'symrev': webutil.symrevorshortnode(req, ctx),
+        'rename': rename,
+        'diff': diffs,
+    }))
 
 diff = webcommand('diff')(filediff)
 
@@ -847,26 +794,18 @@  def comparison(web, req, tmpl):
         leftlines = filelines(fctx)
 
     comparison = webutil.compare(tmpl, context, leftlines, rightlines)
-    return tmpl('filecomparison',
-                file=path,
-                node=hex(ctx.node()),
-                rev=ctx.rev(),
-                symrev=webutil.symrevorshortnode(req, ctx),
-                date=ctx.date(),
-                desc=ctx.description(),
-                extra=ctx.extra(),
-                author=ctx.user(),
-                rename=rename,
-                branch=webutil.nodebranchnodefault(ctx),
-                parent=webutil.parents(fctx),
-                child=webutil.children(fctx),
-                tags=webutil.nodetagsdict(web.repo, ctx.node()),
-                bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
-                leftrev=leftrev,
-                leftnode=hex(leftnode),
-                rightrev=rightrev,
-                rightnode=hex(rightnode),
-                comparison=comparison)
+    return tmpl('filecomparison', **webutil.makeentry(web.repo, ctx, {
+        'file': path,
+        'symrev': webutil.symrevorshortnode(req, ctx),
+        'rename': rename,
+        'parent': webutil.parents(fctx),
+        'child': webutil.children(fctx),
+        'leftrev': leftrev,
+        'leftnode': hex(leftnode),
+        'rightrev': rightrev,
+        'rightnode': hex(rightnode),
+        'comparison': comparison,
+    }))
 
 @webcommand('annotate')
 def annotate(web, req, tmpl):
@@ -914,24 +853,14 @@  def annotate(web, req, tmpl):
                    "linenumber": "% 6d" % (lineno + 1),
                    "revdate": f.date()}
 
-    return tmpl("fileannotate",
-                file=f,
-                annotate=annotate,
-                path=webutil.up(f),
-                rev=fctx.rev(),
-                symrev=webutil.symrevorshortnode(req, fctx),
-                node=fctx.hex(),
-                author=fctx.user(),
-                date=fctx.date(),
-                desc=fctx.description(),
-                extra=fctx.extra(),
-                rename=webutil.renamelink(fctx),
-                branch=webutil.nodebranchnodefault(fctx),
-                parent=webutil.parents(fctx),
-                child=webutil.children(fctx),
-                tags=webutil.nodetagsdict(web.repo, fctx.node()),
-                bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
-                permissions=fctx.manifest().flags(f))
+    return tmpl("fileannotate", **webutil.makeentry(web.repo, fctx, {
+        'file': f,
+        'annotate': annotate,
+        'path': webutil.up(f),
+        'symrev': webutil.symrevorshortnode(req, fctx),
+        'rename': webutil.renamelink(fctx),
+        'permissions': fctx.manifest().flags(f),
+    }))
 
 @webcommand('filelog')
 def filelog(web, req, tmpl):
@@ -993,23 +922,12 @@  def filelog(web, req, tmpl):
         for i in revs:
             iterfctx = fctx.filectx(i)
 
-            l.append({"parity": parity.next(),
-                      "filerev": i,
-                      "file": f,
-                      "node": iterfctx.hex(),
-                      "author": iterfctx.user(),
-                      "date": iterfctx.date(),
-                      "rename": webutil.renamelink(iterfctx),
-                      "parent": lambda **x: webutil.parents(iterfctx),
-                      "child": lambda **x: webutil.children(iterfctx),
-                      "desc": iterfctx.description(),
-                      "extra": iterfctx.extra(),
-                      "tags": webutil.nodetagsdict(repo, iterfctx.node()),
-                      "bookmarks": webutil.nodebookmarksdict(
-                          repo, iterfctx.node()),
-                      "branch": webutil.nodebranchnodefault(iterfctx),
-                      "inbranch": webutil.nodeinbranch(repo, iterfctx),
-                      "branches": webutil.nodebranchdict(repo, iterfctx)})
+            l.append(webutil.makeentry(repo, iterfctx, {
+                "parity": parity.next(),
+                "filerev": i,
+                "file": f,
+                "rename": webutil.renamelink(iterfctx),
+            }))
         for e in reversed(l):
             yield e
 
@@ -1018,11 +936,16 @@  def filelog(web, req, tmpl):
 
     revnav = webutil.filerevnav(web.repo, fctx.path())
     nav = revnav.gen(end - 1, revcount, count)
-    return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
-                symrev=webutil.symrevorshortnode(req, fctx),
-                entries=entries,
-                latestentry=latestentry,
-                revcount=revcount, morevars=morevars, lessvars=lessvars)
+    return tmpl("filelog", **webutil.makeentry(web.repo, fctx, {
+        'file': f,
+        'nav': nav,
+        'symrev': webutil.symrevorshortnode(req, fctx),
+        'entries': entries,
+        'latestentry': latestentry,
+        'revcount': revcount,
+        'morevars': morevars,
+        'lessvars': lessvars,
+    }))
 
 @webcommand('archive')
 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
@@ -292,6 +292,30 @@  def filectx(repo, req):
 
     return fctx
 
+def makeentry(repo, ctx, more):
+    node = ctx.node()
+
+    entry = {
+        'rev': ctx.rev(),
+        'node': hex(node),
+        'author': ctx.user(),
+        'desc': ctx.description(),
+        'date': ctx.date(),
+        'extra': ctx.extra(),
+        'phase': ctx.phasestr(),
+        'branch': nodebranchnodefault(ctx),
+        'inbranch': nodeinbranch(repo, ctx),
+        'branches': nodebranchdict(repo, ctx),
+        'tags': nodetagsdict(repo, node),
+        'bookmarks': nodebookmarksdict(repo, node),
+        'parent': lambda **x: parents(ctx),
+        'child': lambda **x: children(ctx),
+    }
+
+    entry.update(more)
+
+    return entry
+
 def changelistentry(web, ctx, tmpl):
     '''Obtain a dictionary to be used for entries in a changelist.
 
@@ -304,22 +328,12 @@  def changelistentry(web, ctx, tmpl):
     showtags = showtag(repo, tmpl, 'changelogtag', n)
     files = listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
 
-    return {
-        "author": ctx.user(),
+    return makeentry(repo, ctx, {
         "parent": lambda **x: parents(ctx, rev - 1),
         "child": lambda **x: children(ctx, rev + 1),
         "changelogtag": showtags,
-        "desc": ctx.description(),
-        "extra": ctx.extra(),
-        "date": ctx.date(),
         "files": files,
-        "rev": rev,
-        "node": hex(n),
-        "tags": nodetagsdict(repo, n),
-        "bookmarks": nodebookmarksdict(repo, n),
-        "inbranch": nodeinbranch(repo, ctx),
-        "branches": nodebranchdict(repo, ctx)
-    }
+    })
 
 def symrevorshortnode(req, ctx):
     if 'node' in req.form:
@@ -358,31 +372,21 @@  def changesetentry(web, req, tmpl, ctx):
     diffstatsgen = diffstatgen(ctx, basectx)
     diffstats = diffstat(tmpl, ctx, diffstatsgen, parity)
 
-    return dict(
-        diff=diff,
-        rev=ctx.rev(),
-        node=ctx.hex(),
-        symrev=symrevorshortnode(req, ctx),
-        parent=parents(ctx),
-        child=children(ctx),
-        basenode=basectx.hex(),
-        changesettag=showtags,
-        changesetbookmark=showbookmarks,
-        changesetbranch=showbranch,
-        author=ctx.user(),
-        desc=ctx.description(),
-        extra=ctx.extra(),
-        date=ctx.date(),
-        phase=ctx.phasestr(),
-        files=files,
-        diffsummary=lambda **x: diffsummary(diffstatsgen),
-        diffstat=diffstats,
-        archives=web.archivelist(ctx.hex()),
-        tags=nodetagsdict(web.repo, ctx.node()),
-        bookmarks=nodebookmarksdict(web.repo, ctx.node()),
-        branch=showbranch,
-        inbranch=nodeinbranch(web.repo, ctx),
-        branches=nodebranchdict(web.repo, ctx))
+    entry = makeentry(web.repo, ctx, {
+        'symrev': symrevorshortnode(req, ctx),
+        'basenode': basectx.hex(),
+        'changesettag': showtags,
+        'changesetbookmark': showbookmarks,
+        'changesetbranch': showbranch,
+        'branch': showbranch,
+        'files': files,
+        'diff': diff,
+        'diffstat': diffstats,
+        'diffsummary': lambda **x: diffsummary(diffstatsgen),
+        'archives': web.archivelist(ctx.hex()),
+    })
+
+    return entry
 
 def listfilediffs(tmpl, files, node, max):
     for f in files[:max]: