Patchwork [8,of,9] templater: find keyword name more thoroughly on filtering error

login
register
mail settings
Submitter Yuya Nishihara
Date April 12, 2017, 3:53 p.m.
Message ID <81f613324b3f1e4c8b02.1492012404@mimosa>
Download mbox | patch
Permalink /patch/20139/
State Accepted
Headers show

Comments

Yuya Nishihara - April 12, 2017, 3:53 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1491662012 -32400
#      Sat Apr 08 23:33:32 2017 +0900
# Node ID 81f613324b3f1e4c8b02eb989f68f6b59d28a8bf
# Parent  9477eee4e9d3ebb387691d9626c0616387c1959a
templater: find keyword name more thoroughly on filtering error

Before, it could spill an internal representation of compiled template such
as [(<function runsymbol at 0x....>, 'extras'), ...]. Show less cryptic
message if no symbol found.

New findsymbolicname() function will be also used by dict() constructor.

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -284,6 +284,18 @@  def gettemplate(exp, context):
         return context._load(exp[1])
     raise error.ParseError(_("expected template specifier"))
 
+def findsymbolicname(arg):
+    """Find symbolic name for the given compiled expression; returns None
+    if nothing found reliably"""
+    while True:
+        func, data = arg
+        if func is runsymbol:
+            return data
+        elif func is runfilter:
+            arg = data[0]
+        else:
+            return None
+
 def evalfuncarg(context, mapping, arg):
     func, data = arg
     # func() may return string, generator of strings or arbitrary object such
@@ -387,12 +399,13 @@  def runfilter(context, mapping, data):
     try:
         return filt(thing)
     except (ValueError, AttributeError, TypeError):
-        if isinstance(arg[1], tuple):
-            dt = arg[1][1]
+        sym = findsymbolicname(arg)
+        if sym:
+            msg = (_("template filter '%s' is not compatible with keyword '%s'")
+                   % (filt.func_name, sym))
         else:
-            dt = arg[1]
-        raise error.Abort(_("template filter '%s' is not compatible with "
-                           "keyword '%s'") % (filt.func_name, dt))
+            msg = _("incompatible use of template filter '%s'") % filt.func_name
+        raise error.Abort(msg)
 
 def buildmap(exp, context):
     func, data = compileexp(exp[1], context, methods)
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
@@ -2684,6 +2684,14 @@  Behind the scenes, this will throw Value
   hg: parse error: date expects a date information
   [255]
 
+  $ hg tip -T '{author|email|shortdate}\n'
+  abort: template filter 'shortdate' is not compatible with keyword 'author'
+  [255]
+
+  $ hg tip -T '{get(extras, "branch")|shortdate}\n'
+  abort: incompatible use of template filter 'shortdate'
+  [255]
+
 Error in nested template:
 
   $ hg log -T '{"date'