Patchwork [8,of,9] templater: factor out function to create mapping dict for nested evaluation

login
register
mail settings
Submitter Yuya Nishihara
Date March 21, 2018, 1:51 p.m.
Message ID <aeb22bf43719ee40562a.1521640316@mimosa>
Download mbox | patch
Permalink /patch/29694/
State Accepted
Headers show

Comments

Yuya Nishihara - March 21, 2018, 1:51 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521116572 -32400
#      Thu Mar 15 21:22:52 2018 +0900
# Node ID aeb22bf43719ee40562a2e235812bb87e65da9b9
# Parent  62f55bdcf09f41d47668a3a5390f09cdcad909cf
templater: factor out function to create mapping dict for nested evaluation

overlaymap() is the hook point to drop mapping items conflicting with the
default keywords which have to be re-evaluated with new 'ctx' resource.

Patch

diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py
--- a/mercurial/templatekw.py
+++ b/mercurial/templatekw.py
@@ -449,8 +449,8 @@  def showlatesttagdistance(context, mappi
 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
 def showchangessincelatesttag(context, mapping):
     """Integer. All ancestors not in the latest tag."""
-    mapping = mapping.copy()
-    mapping['tag'] = getlatesttags(context, mapping)[2][0]
+    tag = getlatesttags(context, mapping)[2][0]
+    mapping = context.overlaymap(mapping, {'tag': tag})
     return _showchangessincetag(context, mapping)
 
 def _showchangessincetag(context, mapping):
@@ -480,8 +480,7 @@  def showmanifest(context, mapping):
         return
     mrev = repo.manifestlog._revlog.rev(mnode)
     mhex = hex(mnode)
-    mapping = mapping.copy()
-    mapping.update({'rev': mrev, 'node': mhex})
+    mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
     f = context.process('manifest', mapping)
     # TODO: perhaps 'ctx' should be dropped from mapping because manifest
     # rev and node are completely different from changeset's.
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -613,6 +613,13 @@  class engine(object):
         self._aliasmap = _aliasrules.buildmap(aliases)
         self._cache = {}  # key: (func, data)
 
+    def overlaymap(self, origmapping, newmapping):
+        """Create combined mapping from the original mapping and partial
+        mapping to override the original"""
+        mapping = origmapping.copy()
+        mapping.update(newmapping)
+        return mapping
+
     def symbol(self, mapping, key):
         """Resolve symbol to value or function; None if nothing found"""
         v = None
diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py
--- a/mercurial/templateutil.py
+++ b/mercurial/templateutil.py
@@ -202,8 +202,8 @@  def _showcompatlist(context, mapping, na
     startname = 'start_' + plural
     if context.preload(startname):
         yield context.process(startname, mapping)
-    vmapping = mapping.copy()
     def one(v, tag=name):
+        vmapping = {}
         try:
             vmapping.update(v)
         # Python 2 raises ValueError if the type of v is wrong. Python
@@ -216,6 +216,7 @@  def _showcompatlist(context, mapping, na
                     vmapping[a] = b
             except (TypeError, ValueError):
                 vmapping[name] = v
+        vmapping = context.overlaymap(mapping, vmapping)
         return context.process(tag, vmapping)
     lastname = 'last_' + name
     if context.preload(lastname):
@@ -399,10 +400,9 @@  def runmap(context, mapping, data):
                 raise error.ParseError(_("%r is not iterable") % d)
 
     for i, v in enumerate(diter):
-        lm = mapping.copy()
-        lm['index'] = i
         if isinstance(v, dict):
-            lm.update(v)
+            lm = context.overlaymap(mapping, v)
+            lm['index'] = i
             lm['originalnode'] = mapping.get('node')
             yield evalrawexp(context, lm, targ)
         else:
@@ -415,8 +415,7 @@  def runmember(context, mapping, data):
     darg, memb = data
     d = evalrawexp(context, mapping, darg)
     if util.safehasattr(d, 'tomap'):
-        lm = mapping.copy()
-        lm.update(d.tomap())
+        lm = context.overlaymap(mapping, d.tomap())
         return runsymbol(context, lm, memb)
     if util.safehasattr(d, 'get'):
         return getdictitem(d, memb)