Patchwork hgweb: display fate of obsolete changesets

login
register
mail settings
Submitter Anton Shestakov
Date Nov. 21, 2017, 10:14 a.m.
Message ID <f8e398c42760482f02e6.1511259282@neuro>
Download mbox | patch
Permalink /patch/25711/
State Superseded
Headers show

Comments

Anton Shestakov - Nov. 21, 2017, 10:14 a.m.
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1511255021 -28800
#      Tue Nov 21 17:03:41 2017 +0800
# Node ID f8e398c42760482f02e6cfb6b8a1e6a752564c95
# Parent  ff80efc8f3e469c90376603af4fa39012f328918
# EXP-Topic hgweb-more-info
hgweb: display fate of obsolete changesets

Non-hgweb templates have a set of experimental functions that have names
starting with obsfate. Combined, they can be used to show why a particular
changeset is obsolete, e.g.  "pruned" or "rewritten as 5:6e06e39c31df". This
patch reuses some of that code to produce a list of strings that describe what
happened to an obsolete changeset.

In commonentry(), "obsfate" property is made callable so it's only executed on
demand; this saves time when changeset is not obsolete, and also in e.g.
/shortlog view, where there are a lot of changesets, but we don't need to show
each and every one in detail.

In spartan theme, obsfate is used instead of the simple "obsolete: yes", in
other themes a new line is added to /rev page.
Yuya Nishihara - Nov. 26, 2017, 11:10 a.m.
On Tue, 21 Nov 2017 18:14:42 +0800, Anton Shestakov wrote:
> # HG changeset patch
> # User Anton Shestakov <av6@dwimlabs.net>
> # Date 1511255021 -28800
> #      Tue Nov 21 17:03:41 2017 +0800
> # Node ID f8e398c42760482f02e6cfb6b8a1e6a752564c95
> # Parent  ff80efc8f3e469c90376603af4fa39012f328918
> # EXP-Topic hgweb-more-info
> hgweb: display fate of obsolete changesets

> diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
> --- a/mercurial/hgweb/webutil.py
> +++ b/mercurial/hgweb/webutil.py
> @@ -28,10 +28,12 @@ from .. import (
>      error,
>      match,
>      mdiff,
> +    obsutil,
>      patch,
>      pathutil,
>      pycompat,
>      templatefilters,
> +    templatekw,
>      ui as uimod,
>      util,
>  )
> @@ -351,6 +353,10 @@ def linerange(req):
>  def formatlinerange(fromline, toline):
>      return '%d:%d' % (fromline + 1, toline)
>  
> +def obsfate(repo, ctx, ui):
> +    return [obsutil.obsfateprinter(x['successors'], x['markers'], ui)
> +            for x in templatekw.showsuccsandmarkers(repo, ctx)]

Maybe we should first refactor obsfate utility to not depend on templatekw.
Boris, any progress on this?
Augie Fackler - Nov. 30, 2017, 9:08 p.m.
(+boris explicitly to try and get his attention)

On Sun, Nov 26, 2017 at 08:10:14PM +0900, Yuya Nishihara wrote:
> On Tue, 21 Nov 2017 18:14:42 +0800, Anton Shestakov wrote:
> > # HG changeset patch
> > # User Anton Shestakov <av6@dwimlabs.net>
> > # Date 1511255021 -28800
> > #      Tue Nov 21 17:03:41 2017 +0800
> > # Node ID f8e398c42760482f02e6cfb6b8a1e6a752564c95
> > # Parent  ff80efc8f3e469c90376603af4fa39012f328918
> > # EXP-Topic hgweb-more-info
> > hgweb: display fate of obsolete changesets
>
> > diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
> > --- a/mercurial/hgweb/webutil.py
> > +++ b/mercurial/hgweb/webutil.py
> > @@ -28,10 +28,12 @@ from .. import (
> >      error,
> >      match,
> >      mdiff,
> > +    obsutil,
> >      patch,
> >      pathutil,
> >      pycompat,
> >      templatefilters,
> > +    templatekw,
> >      ui as uimod,
> >      util,
> >  )
> > @@ -351,6 +353,10 @@ def linerange(req):
> >  def formatlinerange(fromline, toline):
> >      return '%d:%d' % (fromline + 1, toline)
> >
> > +def obsfate(repo, ctx, ui):
> > +    return [obsutil.obsfateprinter(x['successors'], x['markers'], ui)
> > +            for x in templatekw.showsuccsandmarkers(repo, ctx)]
>
> Maybe we should first refactor obsfate utility to not depend on templatekw.
> Boris, any progress on this?
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Boris Feld - Dec. 3, 2017, 5:49 p.m.
Catching back on my emails.

I thought obsfateprinter was not dependent on the template system but I
was wrong. It doesn't seems too hard to make obsfate printer
independent of the templating system.

Just checking that we are all on the same page, should we update the
current obsfateprinter to manually format and render an obsfate line?
Or do we create another utility that is not template-dependent that
could also be called by changeset_printer?

Also, do we agree on the general format of obsfate as is it today?

    Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-
01-01 00:00 +0000)
    Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-
01-01 00:00 +0000)

On Thu, 2017-11-30 at 16:08 -0500, Augie Fackler wrote:
> (+boris explicitly to try and get his attention)
> 
> On Sun, Nov 26, 2017 at 08:10:14PM +0900, Yuya Nishihara wrote:
> > On Tue, 21 Nov 2017 18:14:42 +0800, Anton Shestakov wrote:
> > > # HG changeset patch
> > > # User Anton Shestakov <av6@dwimlabs.net>
> > > # Date 1511255021 -28800
> > > #      Tue Nov 21 17:03:41 2017 +0800
> > > # Node ID f8e398c42760482f02e6cfb6b8a1e6a752564c95
> > > # Parent  ff80efc8f3e469c90376603af4fa39012f328918
> > > # EXP-Topic hgweb-more-info
> > > hgweb: display fate of obsolete changesets
> > > diff --git a/mercurial/hgweb/webutil.py
> > > b/mercurial/hgweb/webutil.py
> > > --- a/mercurial/hgweb/webutil.py
> > > +++ b/mercurial/hgweb/webutil.py
> > > @@ -28,10 +28,12 @@ from .. import (
> > >      error,
> > >      match,
> > >      mdiff,
> > > +    obsutil,
> > >      patch,
> > >      pathutil,
> > >      pycompat,
> > >      templatefilters,
> > > +    templatekw,
> > >      ui as uimod,
> > >      util,
> > >  )
> > > @@ -351,6 +353,10 @@ def linerange(req):
> > >  def formatlinerange(fromline, toline):
> > >      return '%d:%d' % (fromline + 1, toline)
> > > 
> > > +def obsfate(repo, ctx, ui):
> > > +    return [obsutil.obsfateprinter(x['successors'],
> > > x['markers'], ui)
> > > +            for x in templatekw.showsuccsandmarkers(repo, ctx)]
> > 
> > Maybe we should first refactor obsfate utility to not depend on
> > templatekw.
> > Boris, any progress on this?
> > _______________________________________________
> > Mercurial-devel mailing list
> > Mercurial-devel@mercurial-scm.org
> > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Yuya Nishihara - Dec. 4, 2017, 3:05 p.m.
On Sun, 03 Dec 2017 18:49:55 +0100, Boris Feld wrote:
> I thought obsfateprinter was not dependent on the template system but I
> was wrong. It doesn't seems too hard to make obsfate printer
> independent of the templating system.
> 
> Just checking that we are all on the same page, should we update the
> current obsfateprinter to manually format and render an obsfate line?

Perhaps. Non-template version of obsfateprinter() will need to support
translation, which isn't possible in templater. Also "obsfate" template
will be replaced by a real template.

> Or do we create another utility that is not template-dependent that
> could also be called by changeset_printer?

One utility function for both changeset_printer and hgweb if feasible.

That said, hgweb might need a real template to embed hyperlinks.

> Also, do we agree on the general format of obsfate as is it today?
> 
>     Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-
> 01-01 00:00 +0000)
>     Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-
> 01-01 00:00 +0000)

I have no preference on this.
Anton Shestakov - Dec. 4, 2017, 3:08 p.m.
On Sun, 03 Dec 2017 18:49:55 +0100
Boris Feld <boris.feld@octobus.net> wrote:

> Catching back on my emails.
> 
> I thought obsfateprinter was not dependent on the template system but I
> was wrong. It doesn't seems too hard to make obsfate printer
> independent of the templating system.

It's not exactly dependent, it's just that everywhere it's used (just
one place at the moment) it takes output of showsuccsandmarkers(),
which lives in templatekw. That function is not short, so it made sense
to reuse it.

> Just checking that we are all on the same page, should we update the
> current obsfateprinter to manually format and render an obsfate line?
> Or do we create another utility that is not template-dependent that
> could also be called by changeset_printer?

No idea, I'll probably just try and render obsfate in hgweb without
depending on the obsfateprinter, since this didn't turn out to be a
trivial patch.

> Also, do we agree on the general format of obsfate as is it today?
> 
>     Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-
> 01-01 00:00 +0000)
>     Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-
> 01-01 00:00 +0000)

FWIW, this does look fine, but also shows how obsfateprinter can't fit
every need: hgweb would need the hashes to be links.

So yes, this patch can be dropped.

> On Thu, 2017-11-30 at 16:08 -0500, Augie Fackler wrote:
> > (+boris explicitly to try and get his attention)
> > 
> > On Sun, Nov 26, 2017 at 08:10:14PM +0900, Yuya Nishihara wrote:  
> > > On Tue, 21 Nov 2017 18:14:42 +0800, Anton Shestakov wrote:  
> > > > # HG changeset patch
> > > > # User Anton Shestakov <av6@dwimlabs.net>
> > > > # Date 1511255021 -28800
> > > > #      Tue Nov 21 17:03:41 2017 +0800
> > > > # Node ID f8e398c42760482f02e6cfb6b8a1e6a752564c95
> > > > # Parent  ff80efc8f3e469c90376603af4fa39012f328918
> > > > # EXP-Topic hgweb-more-info
> > > > hgweb: display fate of obsolete changesets
> > > > diff --git a/mercurial/hgweb/webutil.py
> > > > b/mercurial/hgweb/webutil.py
> > > > --- a/mercurial/hgweb/webutil.py
> > > > +++ b/mercurial/hgweb/webutil.py
> > > > @@ -28,10 +28,12 @@ from .. import (
> > > >      error,
> > > >      match,
> > > >      mdiff,
> > > > +    obsutil,
> > > >      patch,
> > > >      pathutil,
> > > >      pycompat,
> > > >      templatefilters,
> > > > +    templatekw,
> > > >      ui as uimod,
> > > >      util,
> > > >  )
> > > > @@ -351,6 +353,10 @@ def linerange(req):
> > > >  def formatlinerange(fromline, toline):
> > > >      return '%d:%d' % (fromline + 1, toline)
> > > > 
> > > > +def obsfate(repo, ctx, ui):
> > > > +    return [obsutil.obsfateprinter(x['successors'],
> > > > x['markers'], ui)
> > > > +            for x in templatekw.showsuccsandmarkers(repo, ctx)]  
> > > 
> > > Maybe we should first refactor obsfate utility to not depend on
> > > templatekw.
> > > Boris, any progress on this?
> > > _______________________________________________
> > > Mercurial-devel mailing list
> > > Mercurial-devel@mercurial-scm.org
> > > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Boris Feld - Jan. 3, 2018, 4 p.m.
I have thought about it lately,

What about introducing a intermediary function obsfatedata that would
returns a dictionary with all the raw values.

Something like:

{'markers': [..., ...],
 'max_date': (0.0, 0),
 'min_date': (0.0, 0),
 'successors': ['7a230b46bf61e50b30308c6cfd7bd1269ef54702'],
 'users': ['test'],
 'verb': 'reworded'}

This dictionnary could then be used by various functions in different
context to render for hgweb, a non-template translation version and a
template version.

This way we separate computing the data from displaying it, avoiding
copy-pasting some logic around.

What do you think?

On Tue, 2017-12-05 at 00:05 +0900, Yuya Nishihara wrote:
> On Sun, 03 Dec 2017 18:49:55 +0100, Boris Feld wrote:
> > I thought obsfateprinter was not dependent on the template system
> > but I
> > was wrong. It doesn't seems too hard to make obsfate printer
> > independent of the templating system.
> > 
> > Just checking that we are all on the same page, should we update
> > the
> > current obsfateprinter to manually format and render an obsfate
> > line?
> 
> Perhaps. Non-template version of obsfateprinter() will need to
> support
> translation, which isn't possible in templater. Also "obsfate"
> template
> will be replaced by a real template.
> 
> > Or do we create another utility that is not template-dependent that
> > could also be called by changeset_printer?
> 
> One utility function for both changeset_printer and hgweb if
> feasible.
> 
> That said, hgweb might need a real template to embed hyperlinks.
> 
> > Also, do we agree on the general format of obsfate as is it today?
> > 
> >     Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at
> > 1970-
> > 01-01 00:00 +0000)
> >     Obsfate: rewritten using amend as 3:65b757b745b9 by test (at
> > 1970-
> > 01-01 00:00 +0000)
> 
> I have no preference on this.
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Yuya Nishihara - Jan. 4, 2018, 7:50 a.m.
On Wed, 03 Jan 2018 17:00:35 +0100, Boris Feld wrote:
> What about introducing a intermediary function obsfatedata that would
> returns a dictionary with all the raw values.
> 
> Something like:
> 
> {'markers': [..., ...],
>  'max_date': (0.0, 0),
>  'min_date': (0.0, 0),
>  'successors': ['7a230b46bf61e50b30308c6cfd7bd1269ef54702'],
>  'users': ['test'],
>  'verb': 'reworded'}

IIUC, we already have utility functions at that level, such as
obsutil.obsfateverb(). What's an advantage of packing them into a dict?

> This dictionnary could then be used by various functions in different
> context to render for hgweb, a non-template translation version and a
> template version.

hgweb thing was implemented using templatekw.
Boris Feld - Jan. 4, 2018, 8:44 a.m.
On Thu, 2018-01-04 at 16:50 +0900, Yuya Nishihara wrote:
> On Wed, 03 Jan 2018 17:00:35 +0100, Boris Feld wrote:
> > What about introducing a intermediary function obsfatedata that
> > would
> > returns a dictionary with all the raw values.
> > 
> > Something like:
> > 
> > {'markers': [..., ...],
> >  'max_date': (0.0, 0),
> >  'min_date': (0.0, 0),
> >  'successors': ['7a230b46bf61e50b30308c6cfd7bd1269ef54702'],
> >  'users': ['test'],
> >  'verb': 'reworded'}
> 
> IIUC, we already have utility functions at that level, such as
> obsutil.obsfateverb(). What's an advantage of packing them into a
> dict?

As Anton said, the obsfateprinter function is not short.

This function has 3 responsibilities:

- Gather all obsfate-related information, verb, operation, users, dates
using functions in obsutil.
- Apply some logic, like filtering the current user or computing the
date range.
- Format a string and returns it.

The advantage I can see about spitting the formatting in another
function is that all users could use the same function for the first
and second responsibility. Also, we won't need to update several
functions when adding a new obsfate-related field.

> 
> > This dictionnary could then be used by various functions in
> > different
> > context to render for hgweb, a non-template translation version and
> > a
> > template version.
> 
> hgweb thing was implemented using templatekw.

Right, but we want an implementation not dependent on templatekw to
clean the following piece of code, right?

+def obsfate(repo, ctx, ui):
+    return [obsutil.obsfateprinter(x['successors'], x['markers'], ui)
+            for x in templatekw.showsuccsandmarkers(repo, ctx)]
Yuya Nishihara - Jan. 4, 2018, 9:36 a.m.
On Thu, 04 Jan 2018 09:44:17 +0100, Boris Feld wrote:
> On Thu, 2018-01-04 at 16:50 +0900, Yuya Nishihara wrote:
> > On Wed, 03 Jan 2018 17:00:35 +0100, Boris Feld wrote:
> > > What about introducing a intermediary function obsfatedata that
> > > would
> > > returns a dictionary with all the raw values.
> > > 
> > > Something like:
> > > 
> > > {'markers': [..., ...],
> > >  'max_date': (0.0, 0),
> > >  'min_date': (0.0, 0),
> > >  'successors': ['7a230b46bf61e50b30308c6cfd7bd1269ef54702'],
> > >  'users': ['test'],
> > >  'verb': 'reworded'}
> > 
> > IIUC, we already have utility functions at that level, such as
> > obsutil.obsfateverb(). What's an advantage of packing them into a
> > dict?
> 
> As Anton said, the obsfateprinter function is not short.
> 
> This function has 3 responsibilities:
> 
> - Gather all obsfate-related information, verb, operation, users, dates
> using functions in obsutil.
> - Apply some logic, like filtering the current user or computing the
> date range.
> - Format a string and returns it.
> 
> The advantage I can see about spitting the formatting in another
> function is that all users could use the same function for the first
> and second responsibility. Also, we won't need to update several
> functions when adding a new obsfate-related field.

The first two are served by template keywords/functions, and the last one
is only needed for changeset_printer.

> > > This dictionnary could then be used by various functions in
> > > different
> > > context to render for hgweb, a non-template translation version and
> > > a
> > > template version.
> > 
> > hgweb thing was implemented using templatekw.
> 
> Right, but we want an implementation not dependent on templatekw to
> clean the following piece of code, right?
> 
> +def obsfate(repo, ctx, ui):
> +    return [obsutil.obsfateprinter(x['successors'], x['markers'], ui)
> +            for x in templatekw.showsuccsandmarkers(repo, ctx)]

No. We decided to export {succsandmarkers} to web templates. We could make
template fragments shared across styles, but that's another story.
Boris Feld - Jan. 4, 2018, 9:55 a.m.
On Thu, 2018-01-04 at 18:36 +0900, Yuya Nishihara wrote:
> On Thu, 04 Jan 2018 09:44:17 +0100, Boris Feld wrote:
> > On Thu, 2018-01-04 at 16:50 +0900, Yuya Nishihara wrote:
> > > On Wed, 03 Jan 2018 17:00:35 +0100, Boris Feld wrote:
> > > > What about introducing a intermediary function obsfatedata that
> > > > would
> > > > returns a dictionary with all the raw values.
> > > > 
> > > > Something like:
> > > > 
> > > > {'markers': [..., ...],
> > > >  'max_date': (0.0, 0),
> > > >  'min_date': (0.0, 0),
> > > >  'successors': ['7a230b46bf61e50b30308c6cfd7bd1269ef54702'],
> > > >  'users': ['test'],
> > > >  'verb': 'reworded'}
> > > 
> > > IIUC, we already have utility functions at that level, such as
> > > obsutil.obsfateverb(). What's an advantage of packing them into a
> > > dict?
> > 
> > As Anton said, the obsfateprinter function is not short.
> > 
> > This function has 3 responsibilities:
> > 
> > - Gather all obsfate-related information, verb, operation, users,
> > dates
> > using functions in obsutil.
> > - Apply some logic, like filtering the current user or computing
> > the
> > date range.
> > - Format a string and returns it.
> > 
> > The advantage I can see about spitting the formatting in another
> > function is that all users could use the same function for the
> > first
> > and second responsibility. Also, we won't need to update several
> > functions when adding a new obsfate-related field.
> 
> The first two are served by template keywords/functions, and the last
> one
> is only needed for changeset_printer.
> 
> > > > This dictionnary could then be used by various functions in
> > > > different
> > > > context to render for hgweb, a non-template translation version
> > > > and
> > > > a
> > > > template version.
> > > 
> > > hgweb thing was implemented using templatekw.
> > 
> > Right, but we want an implementation not dependent on templatekw to
> > clean the following piece of code, right?
> > 
> > +def obsfate(repo, ctx, ui):
> > +    return [obsutil.obsfateprinter(x['successors'], x['markers'],
> > ui)
> > +            for x in templatekw.showsuccsandmarkers(repo, ctx)]
> 
> No. We decided to export {succsandmarkers} to web templates. We could
> make
> template fragments shared across styles, but that's another story.

I should have missed a mail or an IRC discussion, sorry for the noise
then.

Patch

diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
--- a/mercurial/hgweb/webutil.py
+++ b/mercurial/hgweb/webutil.py
@@ -28,10 +28,12 @@  from .. import (
     error,
     match,
     mdiff,
+    obsutil,
     patch,
     pathutil,
     pycompat,
     templatefilters,
+    templatekw,
     ui as uimod,
     util,
 )
@@ -351,6 +353,10 @@  def linerange(req):
 def formatlinerange(fromline, toline):
     return '%d:%d' % (fromline + 1, toline)
 
+def obsfate(repo, ctx, ui):
+    return [obsutil.obsfateprinter(x['successors'], x['markers'], ui)
+            for x in templatekw.showsuccsandmarkers(repo, ctx)]
+
 def commonentry(repo, ctx):
     node = ctx.node()
     return {
@@ -362,6 +368,7 @@  def commonentry(repo, ctx):
         'extra': ctx.extra(),
         'phase': ctx.phasestr(),
         'obsolete': ctx.obsolete(),
+        'obsfate': lambda **x: obsfate(repo, ctx, repo.ui),
         'instabilities': [{"name": i} for i in ctx.instabilities()],
         'branch': nodebranchnodefault(ctx),
         'inbranch': nodeinbranch(repo, ctx),
diff --git a/mercurial/templates/gitweb/changeset.tmpl b/mercurial/templates/gitweb/changeset.tmpl
--- a/mercurial/templates/gitweb/changeset.tmpl
+++ b/mercurial/templates/gitweb/changeset.tmpl
@@ -44,6 +44,7 @@  changeset |
  <td>changeset {rev}</td>
  <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
 </tr>
+{if(obsolete, '<tr><td>obsolete</td><td>{join(obsfate, '; ')|escape}</td></tr>')}
 {ifeq(count(parent), '2', parent%changesetparentdiff, parent%changesetparent)}
 {child%changesetchild}
 </table></div>
diff --git a/mercurial/templates/monoblue/changeset.tmpl b/mercurial/templates/monoblue/changeset.tmpl
--- a/mercurial/templates/monoblue/changeset.tmpl
+++ b/mercurial/templates/monoblue/changeset.tmpl
@@ -48,6 +48,7 @@ 
         {branch%changesetbranch}
         <dt>changeset {rev}</dt>
         <dd><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>
+        {if(obsolete, '<dt>obsolete</dt><dd>{join(obsfate, '; ')|escape}</dd>')}
         {ifeq(count(parent), '2', parent%changesetparentdiff, parent%changesetparent)}
         {child%changesetchild}
     </dl>
diff --git a/mercurial/templates/paper/changeset.tmpl b/mercurial/templates/paper/changeset.tmpl
--- a/mercurial/templates/paper/changeset.tmpl
+++ b/mercurial/templates/paper/changeset.tmpl
@@ -49,6 +49,10 @@ 
  <th class="date">date</th>
  <td class="date age">{date|rfc822date}</td>
 </tr>
+{if(obsolete, '<tr>
+ <th>obsolete</th>
+ <td>{join(obsfate, '; ')|escape}</td>
+</tr>')}
 <tr>
  <th class="author">parents</th>
  <td class="author">{ifeq(count(parent), '2', parent%changesetparentdiff, parent%changesetparent)}</td>
diff --git a/mercurial/templates/spartan/changelogentry.tmpl b/mercurial/templates/spartan/changelogentry.tmpl
--- a/mercurial/templates/spartan/changelogentry.tmpl
+++ b/mercurial/templates/spartan/changelogentry.tmpl
@@ -24,7 +24,7 @@ 
  </tr>')}
  {if(obsolete, '<tr>
   <th class="obsolete">obsolete:</th>
-  <td class="obsolete">yes</td>
+  <td class="obsolete">{join(obsfate, '; ')|escape}</td>
  </tr>')}
  {ifeq(count(instabilities), '0', '', '<tr>
   <th class="instabilities">instabilities:</th>
diff --git a/mercurial/templates/spartan/changeset.tmpl b/mercurial/templates/spartan/changeset.tmpl
--- a/mercurial/templates/spartan/changeset.tmpl
+++ b/mercurial/templates/spartan/changeset.tmpl
@@ -39,7 +39,7 @@ 
 </tr>')}
 {if(obsolete, '<tr>
  <th class="obsolete">obsolete:</th>
- <td class="obsolete">yes</td>
+ <td class="obsolete">{join(obsfate, '; ')|escape}</td>
 </tr>')}
 {ifeq(count(instabilities), '0', '', '<tr>
  <th class="instabilities">instabilities:</th>
diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t
--- a/tests/test-hgweb-commands.t
+++ b/tests/test-hgweb-commands.t
@@ -902,6 +902,7 @@  Logs and changes
    <th class="date">date</th>
    <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
   </tr>
+  
   <tr>
    <th class="author">parents</th>
    <td class="author"></td>
diff --git a/tests/test-hgweb-diffs.t b/tests/test-hgweb-diffs.t
--- a/tests/test-hgweb-diffs.t
+++ b/tests/test-hgweb-diffs.t
@@ -103,6 +103,7 @@  revision
    <th class="date">date</th>
    <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
   </tr>
+  
   <tr>
    <th class="author">parents</th>
    <td class="author"></td>
@@ -381,6 +382,7 @@  revision
    <th class="date">date</th>
    <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
   </tr>
+  
   <tr>
    <th class="author">parents</th>
    <td class="author"></td>
diff --git a/tests/test-hgweb-removed.t b/tests/test-hgweb-removed.t
--- a/tests/test-hgweb-removed.t
+++ b/tests/test-hgweb-removed.t
@@ -84,6 +84,7 @@  revision
    <th class="date">date</th>
    <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
   </tr>
+  
   <tr>
    <th class="author">parents</th>
    <td class="author"><a href="/rev/cb9a9f314b8b">cb9a9f314b8b</a> </td>
diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -1032,7 +1032,7 @@  check obsolete changeset
           <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
   $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
     <th class="obsolete">obsolete:</th>
-    <td class="obsolete">yes</td>
+    <td class="obsolete">pruned</td>
 
 check changeset with instabilities