diff mercurial/templater.py @ 34581:ee0d74083a22

templater: store revisions as ints so min/max won't compare them as strings Because a template value has no explicit type (like ancient PHP), ifcontains() has to coerce the type of the needle. Before, it was always converted to a string, which meant any container type should be a list/dict of strings. This no longer works since we've introduced min/max functions. In order to work around the untyped nature of templater, this patch adds a type specifier to hybrid dict/list. It isn't named as "valuetype" since the _hybrid class can also wrap a dict.
author Yuya Nishihara <yuya@tcha.org>
date Tue, 19 Sep 2017 23:13:46 +0900
parents 4c1cfe54c08d
children 3edfd472f3cb
line wrap: on
line diff
--- a/mercurial/templater.py	Mon Oct 09 12:47:22 2017 -0700
+++ b/mercurial/templater.py	Tue Sep 19 23:13:46 2017 +0900
@@ -333,12 +333,12 @@
     # empty dict/list should be False as they are expected to be ''
     return bool(stringify(thing))
 
-def evalinteger(context, mapping, arg, err):
+def evalinteger(context, mapping, arg, err=None):
     v = evalfuncarg(context, mapping, arg)
     try:
         return int(v)
     except (TypeError, ValueError):
-        raise error.ParseError(err)
+        raise error.ParseError(err or _('not an integer'))
 
 def evalstring(context, mapping, arg):
     return stringify(evalrawexp(context, mapping, arg))
@@ -353,6 +353,20 @@
         thing = func(context, mapping, data)
     return stringify(thing)
 
+_evalfuncbytype = {
+    bool: evalboolean,
+    bytes: evalstring,
+    int: evalinteger,
+}
+
+def evalastype(context, mapping, arg, typ):
+    """Evaluate given argument and coerce its type"""
+    try:
+        f = _evalfuncbytype[typ]
+    except KeyError:
+        raise error.ProgrammingError('invalid type specified: %r' % typ)
+    return f(context, mapping, arg)
+
 def runinteger(context, mapping, data):
     return int(data)
 
@@ -782,8 +796,9 @@
         # i18n: "ifcontains" is a keyword
         raise error.ParseError(_("ifcontains expects three or four arguments"))
 
-    needle = evalstring(context, mapping, args[0])
     haystack = evalfuncarg(context, mapping, args[1])
+    needle = evalastype(context, mapping, args[0],
+                        getattr(haystack, 'keytype', None) or bytes)
 
     if needle in haystack:
         yield evalrawexp(context, mapping, args[2])