Patchwork [9,of,9] templater: drop symbols which should be overridden by new 'ctx' (issue5612)

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

Comments

Yuya Nishihara - March 21, 2018, 1:51 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521117537 -32400
#      Thu Mar 15 21:38:57 2018 +0900
# Node ID 148f113af1cd87295de4f773930575613d0e3d5e
# Parent  aeb22bf43719ee40562a2e235812bb87e65da9b9
templater: drop symbols which should be overridden by new 'ctx' (issue5612)

This problem is caused by impedance mismatch between the templater and the
formatter interface, which is that the template keywords are generally
evaluated dynamically, but the formatter puts static values into a template
mapping.

This patch avoids the problem by removing conflicting values from a mapping
dict when a 'ctx' is switched.
Augie Fackler - March 22, 2018, 2:01 a.m.
> On Mar 21, 2018, at 09:51, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1521117537 -32400
> #      Thu Mar 15 21:38:57 2018 +0900
> # Node ID 148f113af1cd87295de4f773930575613d0e3d5e
> # Parent  aeb22bf43719ee40562a2e235812bb87e65da9b9
> templater: drop symbols which should be overridden by new 'ctx' (issue5612)

queued, thanks

Patch

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -504,6 +504,10 @@  class templateresources(templater.resour
             'ui': ui,
         }
 
+    def availablekeys(self, context, mapping):
+        return {k for k, g in self._gettermap.iteritems()
+                if g(self, context, mapping, k) is not None}
+
     def knownkeys(self):
         return self._knownkeys
 
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -563,6 +563,10 @@  class resourcemapper(object):
     __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
+    def availablekeys(self, context, mapping):
+        """Return a set of available resource keys based on the given mapping"""
+
+    @abc.abstractmethod
     def knownkeys(self):
         """Return a set of supported resource keys"""
 
@@ -571,6 +575,9 @@  class resourcemapper(object):
         """Return a resource for the key if available; otherwise None"""
 
 class nullresourcemapper(resourcemapper):
+    def availablekeys(self, context, mapping):
+        return set()
+
     def knownkeys(self):
         return set()
 
@@ -616,10 +623,23 @@  class engine(object):
     def overlaymap(self, origmapping, newmapping):
         """Create combined mapping from the original mapping and partial
         mapping to override the original"""
-        mapping = origmapping.copy()
+        # do not copy symbols which overrides the defaults depending on
+        # new resources, so the defaults will be re-evaluated (issue5612)
+        knownres = self._resources.knownkeys()
+        newres = self._resources.availablekeys(self, newmapping)
+        mapping = {k: v for k, v in origmapping.iteritems()
+                   if (k in knownres  # not a symbol per self.symbol()
+                       or newres.isdisjoint(self._defaultrequires(k)))}
         mapping.update(newmapping)
         return mapping
 
+    def _defaultrequires(self, key):
+        """Resource keys required by the specified default symbol function"""
+        v = self._defaults.get(key)
+        if v is None or not callable(v):
+            return ()
+        return getattr(v, '_requires', ())
+
     def symbol(self, mapping, key):
         """Resolve symbol to value or function; None if nothing found"""
         v = None
diff --git a/tests/test-identify.t b/tests/test-identify.t
--- a/tests/test-identify.t
+++ b/tests/test-identify.t
@@ -63,6 +63,16 @@  test template keywords and functions whi
   $ hg id -T '{parents % "{rev} {node|shortest} {desc}\n"}'
   0 cb9a a
 
+test nested template: '{tags}'/'{node}' constants shouldn't override the
+default keywords, but '{id}' persists because there's no default keyword
+for '{id}' (issue5612)
+
+  $ hg id -T '{tags}\n'
+  tip
+  $ hg id -T '{revset("null:.") % "{rev}:{node|short} {tags} {id}\n"}'
+  -1:000000000000  cb9a9f314b8b
+  0:cb9a9f314b8b tip cb9a9f314b8b
+
 with modifications
 
   $ echo b > a