[patch][preliminary] hgweb: arbitrary diff support

Csaba Henk csaba-ml at creo.hu
Fri May 19 09:17:02 CDT 2006


Hi folks,

The attached patch lets you view the diff of arbitrary two revisions via
the web interface.

TODO: cleanup template handling (in particular that of those parts which
appear optionally), add support for gitweb style interface.

However, I think the main question is if the UI is useable/acceptable,
or can be easily tuned to be so.

Regrads,
Csaba

# HG changeset patch
# User csaba.henk at creo.hu
# Node ID 3c2da2df1685dcce7c2936548806cfd75fdafadd
# Parent  4be9a79b49b177f5c44c4f32b22999ff5583880a
Add basic support for diffing arbitrary revisions via the web interface
 - Add "diffnodes" cgi command for diffing arbitrary two revisions.
 - Introduce the so-called "reference changeset". This can be set and
   preserved in a changelog/changset context. When it's set, each
   changelog entry will have a link to the diff taken against the ref cset.
 - Changeset pages got a button which returns to the changelog with
   setting the current changeset node as the ref cset; changelog page
   got a button which clears the ref cset value.

diff -r 4be9a79b49b1 -r 3c2da2df1685 mercurial/hgweb.py
--- a/mercurial/hgweb.py	Wed May 17 13:21:36 2006 -0500
+++ b/mercurial/hgweb.py	Fri May 19 07:24:10 2006 +0200
@@ -222,7 +222,7 @@ class hgweb(object):
             yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
                             showfunc=showfunc, ignorews=ignorews), f, tn)
 
-    def changelog(self, pos):
+    def changelog(self, pos, ref=None):
         def changenav(**map):
             def seq(factor, maxchanges=None):
                 if maxchanges:
@@ -265,19 +265,28 @@ class hgweb(object):
                 changes = cl.read(n)
                 hn = hex(n)
 
-                l.insert(0, {"parity": parity,
-                             "author": changes[1],
-                             "parent": self.siblings(cl.parents(n), cl.rev,
-                                                     cl.rev(n) - 1),
-                             "child": self.siblings(cl.children(n), cl.rev,
-                                                    cl.rev(n) + 1),
-                             "changelogtag": self.showtag("changelogtag",n),
-                             "manifest": hex(changes[0]),
-                             "desc": changes[4],
-                             "date": changes[2],
-                             "files": self.listfilediffs(changes[3], n),
-                             "rev": i,
-                             "node": hn})
+                dic = {"parity": parity,
+                       "author": changes[1],
+                       "parent": self.siblings(cl.parents(n), cl.rev,
+                                               cl.rev(n) - 1),
+                       "child": self.siblings(cl.children(n), cl.rev,
+                                              cl.rev(n) + 1),
+                       "changelogtag": self.showtag("changelogtag",n),
+                       "manifest": hex(changes[0]),
+                       "desc": changes[4],
+                       "date": changes[2],
+                       "files": self.listfilediffs(changes[3], n),
+                       "rev": i,
+                       "node": hn,
+                       "nodesave": hn}
+
+                if ref and refrev != i:
+                    dic["ref"] = ref
+                    dic["refrev"] = [[[str(refrev), ""], ["", ""]]]
+                else:
+                    dic["refrev"] = []
+
+                l.insert(0, dic)
                 parity = 1 - parity
 
             for e in l:
@@ -290,10 +299,17 @@ class hgweb(object):
         end = min(count, start + self.maxchanges)
         pos = end - 1
 
+        if ref:
+             refrev = cl.rev(self.repo.lookup(ref))
+             refhack = [[["",""],["",""]]]
+        else:
+             refhack = []
+
         yield self.t('changelog',
                      changenav=changenav,
                      manifest=hex(mf),
                      rev=pos, changesets=count, entries=changelist,
+                     ref=ref or "", refhack=refhack,
                      archives=self.archivelist("tip"))
 
     def search(self, query):
@@ -352,7 +368,7 @@ class hgweb(object):
                      manifest=hex(mf),
                      entries=changelist)
 
-    def changeset(self, nodeid):
+    def changeset(self, nodeid, ref=None):
         cl = self.repo.changelog
         n = self.repo.lookup(nodeid)
         nodeid = hex(n)
@@ -380,7 +396,31 @@ class hgweb(object):
                      desc=changes[4],
                      date=changes[2],
                      files=files,
+                     ref = ref or "",
                      archives=self.archivelist(nodeid))
+
+    def diffnodes(self, nodeid0, nodeid1, files):
+        cl = self.repo.changelog
+        ns = [ self.repo.lookup(nodeid) for nodeid in [nodeid0, nodeid1] ]
+        nodeids = [ hex(n) for n in ns ]
+        revs = [ cl.rev(n) for n in ns ]
+        if revs[0] > revs[1]:
+            for x in ns, nodeids, revs:
+                x.reverse()
+ 
+        def diff(**map):
+            yield self.diff(ns[0], ns[1], files)
+
+        if files:
+            files = " ".join(files)
+
+        yield self.t('diffnodes',
+                     diff=diff,
+                     rev0=revs[0],
+                     node0=nodeids[0], 
+                     rev1=revs[1],
+                     node1=nodeids[1], 
+                     files=files)
 
     def filelog(self, f, filenode):
         cl = self.repo.changelog
@@ -802,10 +842,32 @@ class hgweb(object):
                     req.write(self.search(hi)) # XXX redirect to 404 page?
                     return
 
-            req.write(self.changelog(hi))
+            if req.form.has_key('ref'):
+                ref = req.form['ref'][0]
+            else:
+                ref = None 
+
+            req.write(self.changelog(hi, ref))
 
         elif cmd == 'changeset':
-            req.write(self.changeset(req.form['node'][0]))
+            if req.form.has_key('ref'):
+                ref = req.form['ref'][0]
+            else:
+                ref = None 
+
+            req.write(self.changeset(req.form['node'][0], ref))
+
+        elif cmd == 'diffnodes':
+            if req.form.has_key('files'):
+                if req.form.has_key('filesep'):
+                    filesep = req.form['filesep'][0]
+                else:
+                    filesep = ' '
+                files = req.form['files'][0].split(filesep)
+            else:
+                files = None
+            req.write(self.diffnodes(req.form['node0'][0],
+                                     req.form['node1'][0], files))
 
         elif cmd == 'manifest':
             req.write(self.manifest(req.form['manifest'][0],
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/changelog.tmpl
--- a/templates/changelog.tmpl	Wed May 17 13:21:36 2006 -0500
+++ b/templates/changelog.tmpl	Fri May 19 07:24:10 2006 +0200
@@ -10,6 +10,7 @@
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 #archives%archiveentry#
 <a type="application/rss+xml" href="?style=rss">rss</a>
+#refhack%resetref#
 </div>
 
 <h2>changelog for #repo|escape#</h2>
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/changelogentry.tmpl
--- a/templates/changelogentry.tmpl	Wed May 17 13:21:36 2006 -0500
+++ b/templates/changelogentry.tmpl	Fri May 19 07:24:10 2006 +0200
@@ -5,7 +5,7 @@
  </tr>
  <tr>
   <th class="revision">changeset #rev#:</th>
-  <td class="node"><a href="?cs=#node|short#">#node|short#</a></td>
+  <td class="node"><a href="?cs=#node|short#;ref=#ref#">#node|short#</a></td>
  </tr>
  #parent%changelogparent#
  #child%changelogchild#
@@ -22,4 +22,5 @@
   <th class="files"><a href="?mf=#manifest|short#;path=/">files</a>:</th>
   <td class="files">#files#</td>
  </tr>
+ #refrev%diffvs#
 </table>
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/changeset.tmpl
--- a/templates/changeset.tmpl	Wed May 17 13:21:36 2006 -0500
+++ b/templates/changeset.tmpl	Fri May 19 07:24:10 2006 +0200
@@ -4,7 +4,8 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
+<a href="?cl=#rev#;ref=#ref#">changelog</a>
+<a href="?cl=#rev#;ref=#node|short#">chlog + set ref cset</a>
 <a href="?cmd=tags">tags</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 <a href="?cs=#node|short#;style=raw">raw</a>
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/map
--- a/templates/map	Wed May 17 13:21:36 2006 -0500
+++ b/templates/map	Fri May 19 07:24:10 2006 +0200
@@ -3,13 +3,15 @@ footer = footer.tmpl
 footer = footer.tmpl
 search = search.tmpl
 changelog = changelog.tmpl
-naventry = '<a href="?cl=#rev#">#label|escape#</a> '
+naventry = '<a href="?cl=#rev#;ref=#ref#">#label|escape#</a> '
 filedifflink = '<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> '
 filenodelink = '<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> '
 fileellipses = '...'
 changelogentry = changelogentry.tmpl
 searchentry = changelogentry.tmpl
 changeset = changeset.tmpl
+diffnodes = diffnodes.tmpl
+resetref = '<a href="?cl=#rev#">reset ref cset</a>'
 manifest = manifest.tmpl
 manifestdirentry = '<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#">#basename|escape#/</a>'
 manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?f=#filenode|short#;file=#file|urlescape#">#basename|escape#</a>'
@@ -26,6 +28,7 @@ diffline = '#line|escape#'
 diffline = '#line|escape#'
 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>'
 changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>'
+diffvs = '<tr><th class="refrev">diff to #refrev#:</th><td class="refrev"><a href="?cmd=diffnodes;node0=#nodesave|short#;node1=#ref#">#ref#</a></td></tr>'
 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>'
 filerename = '<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#">#file|escape#@#node|short#</a></td></tr>'
 filelogrename = '<tr><th>base:</th><td><a href="?f=#node|short#;file=#file|urlescape#">#file|escape#@#node|short#</a></td></tr>'
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/map-raw
--- a/templates/map-raw	Wed May 17 13:21:36 2006 -0500
+++ b/templates/map-raw	Fri May 19 07:24:10 2006 +0200
@@ -14,3 +14,4 @@ filediff = filediff-raw.tmpl
 filediff = filediff-raw.tmpl
 fileannotate = fileannotate-raw.tmpl
 annotateline = '#author#@#rev#: #line#'
+diffnodes = diffnodes-raw.tmpl
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/diffnodes-raw.tmpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/diffnodes-raw.tmpl	Fri May 19 07:24:10 2006 +0200
@@ -0,0 +1,7 @@
+#header#
+# HG diff 
+# changeset0 #rev0#: #node0|short# 
+# changeset1 #rev1#: #node1|short# 
+# files: #files#
+
+#diff#
diff -r 4be9a79b49b1 -r 3c2da2df1685 templates/diffnodes.tmpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/diffnodes.tmpl	Fri May 19 07:24:10 2006 +0200
@@ -0,0 +1,30 @@
+#header#
+<title>#repo|escape#: diff #rev0# =&gt; #rev1#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="?cmd=diffnodes;node0=#node0|short#;node1=#node1|short#;style=raw">raw</a>
+</div>
+
+<h2>diff: #rev0# =&gt; #rev1#</h2>
+
+<table id="changesetEntry">
+<tr>
+ <th class="changeset">changeset0 #rev0#:</th>
+ <td class="changeset"><a href="?cs=#node0|short#">#node0|short#</a></td>
+</tr>
+<tr>
+ <th class="changeset">changeset1 #rev1#:</th>
+ <td class="changeset"><a href="?cs=#node1|short#">#node1|short#</a></td>
+</tr>
+<tr>
+ <th class="files">files:</th>
+ <td class="files">#files#</td></tr>
+</table>
+
+<div id="changesetDiff">
+#diff#
+</div>
+
+#footer#



More information about the Mercurial mailing list