Patchwork templates: limit -Tlist to supported templates (RFC)

login
register
mail settings
Submitter timeless@mozdev.org
Date Dec. 14, 2015, 5:21 a.m.
Message ID <377cf7350fe05e06a5e8.1450070504@waste.org>
Download mbox | patch
Permalink /patch/12029/
State Deferred
Delegated to: Yuya Nishihara
Headers show

Comments

timeless@mozdev.org - Dec. 14, 2015, 5:21 a.m.
# HG changeset patch
# User timeless <timeless@mozdev.org>
# Date 1450065308 0
#      Mon Dec 14 03:55:08 2015 +0000
# Node ID 377cf7350fe05e06a5e8217c0e22c17d647e3cd5
# Parent  944af8e2eb4cddf96ba5b8a96854528b40979715
templates: limit -Tlist to supported templates (RFC)

I'm not sure whether using __contains__/in would be preferred
or using a try-raise-except (this patch does both, which is
wrong....).

The benefit of this is that -T list output is vaguely useful.
Yuya Nishihara - Dec. 15, 2015, 2:24 p.m.
On Sun, 13 Dec 2015 23:21:44 -0600, timeless wrote:
> # HG changeset patch
> # User timeless <timeless@mozdev.org>
> # Date 1450065308 0
> #      Mon Dec 14 03:55:08 2015 +0000
> # Node ID 377cf7350fe05e06a5e8217c0e22c17d647e3cd5
> # Parent  944af8e2eb4cddf96ba5b8a96854528b40979715
> templates: limit -Tlist to supported templates (RFC)
> 
> I'm not sure whether using __contains__/in would be preferred
> or using a try-raise-except (this patch does both, which is
> wrong....).
> 
> The benefit of this is that -T list output is vaguely useful.

> --- a/mercurial/templater.py
> +++ b/mercurial/templater.py
> @@ -828,7 +828,7 @@
>  
>  engines = {'default': engine}
>  
> -def stylelist():
> +def stylelist(topic=None):
>      paths = templatepaths()
>      if not paths:
>          return _('no templates found, try `hg debuginstall` for more info')
> @@ -837,7 +837,12 @@
>      for file in dirlist:
>          split = file.split(".")
>          if split[0] == "map-cmdline":
> -            stylelist.append(split[1])
> +            try:
> +                t = templater(templatepath(file), topic=topic, liststyles=False)
> +                if topic is None or t.__contains__(topic):
> +                    stylelist.append(split[1])
> +            except error.Abort:
> +                pass

"topic in t" should work.

> @@ -846,7 +851,7 @@
>  class templater(object):
>  
>      def __init__(self, mapfile, filters=None, defaults=None, cache=None,
> -                 minchunk=1024, maxchunk=65536):
> +                 minchunk=1024, maxchunk=65536, topic=None, liststyles=True):
>          '''set up template engine.
>          mapfile is name of file to read map definitions from.
>          filters is dict of functions. each transforms a value into another.
> @@ -873,8 +878,11 @@
>          if not mapfile:
>              return
>          if not os.path.exists(mapfile):
> +            hint = None
> +            if liststyles:
> +                hint=_("available styles: %s") % stylelist(topic)
>              raise error.Abort(_("style '%s' not found") % mapfile,
> -                             hint=_("available styles: %s") % stylelist())
> +                             hint=hint)

It seems passing topic to the templater is layering violation. And we can't
list all style-like items here because the formatter has its own built-in
formats (e.g. "json").

Assuming this code path would be only reachable by log --style option, we can
leave it listing all style files.

Patch

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -178,7 +178,7 @@ 
         return tmpl, None
 
     if tmpl == 'list':
-        ui.write(_("available styles: %s\n") % templater.stylelist())
+        ui.write(_("available styles: %s\n") % templater.stylelist(topic))
         raise error.Abort(_("specify a template"))
 
     # perhaps it's a path to a map or a template
@@ -194,7 +194,7 @@ 
 
 def gettemplater(ui, topic, spec):
     tmpl, mapfile = lookuptemplate(ui, topic, spec)
-    t = templater.templater(mapfile, {})
+    t = templater.templater(mapfile, {}, topic=topic)
     if tmpl:
         t.cache[topic] = tmpl
     return t
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -828,7 +828,7 @@ 
 
 engines = {'default': engine}
 
-def stylelist():
+def stylelist(topic=None):
     paths = templatepaths()
     if not paths:
         return _('no templates found, try `hg debuginstall` for more info')
@@ -837,7 +837,12 @@ 
     for file in dirlist:
         split = file.split(".")
         if split[0] == "map-cmdline":
-            stylelist.append(split[1])
+            try:
+                t = templater(templatepath(file), topic=topic, liststyles=False)
+                if topic is None or t.__contains__(topic):
+                    stylelist.append(split[1])
+            except error.Abort:
+                pass
     return ", ".join(sorted(stylelist))
 
 class TemplateNotFound(error.Abort):
@@ -846,7 +851,7 @@ 
 class templater(object):
 
     def __init__(self, mapfile, filters=None, defaults=None, cache=None,
-                 minchunk=1024, maxchunk=65536):
+                 minchunk=1024, maxchunk=65536, topic=None, liststyles=True):
         '''set up template engine.
         mapfile is name of file to read map definitions from.
         filters is dict of functions. each transforms a value into another.
@@ -873,8 +878,11 @@ 
         if not mapfile:
             return
         if not os.path.exists(mapfile):
+            hint = None
+            if liststyles:
+                hint=_("available styles: %s") % stylelist(topic)
             raise error.Abort(_("style '%s' not found") % mapfile,
-                             hint=_("available styles: %s") % stylelist())
+                             hint=hint)
 
         conf = config.config(includepaths=templatepaths())
         conf.read(mapfile)
@@ -893,6 +901,9 @@ 
                 if ':' in val[1]:
                     val = val[1].split(':', 1)
                 self.map[key] = val[0], os.path.join(self.base, val[1])
+        if topic is not None and not self.__contains__(key):
+            raise error.Abort(_("style '%s' does not support '%s'") %
+                      (mapfile, topic))
 
     def __contains__(self, key):
         return key in self.cache or key in self.map
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -997,6 +997,13 @@ 
   abort: specify a template
   [255]
 
+Only supported styles (this test will change with time):
+
+  $ hg manifest -T list
+  available styles: bisect, default, phases, status
+  abort: specify a template
+  [255]
+
 Error if style missing key:
 
   $ echo 'q = q' > t