templater: drop extension point of engine classes (API)
authorYuya Nishihara <yuya@tcha.org>
Thu, 03 May 2018 10:58:56 +0900
changeset 38353 48289eafb37d
parent 38352 e9cb13c54d63
child 38354 e637dc0b3b1f
templater: drop extension point of engine classes (API) I don't think this would ever be used by third-party extensions, as we've heavily changed both the templater internals and the syntax since then. The main reason of removing this API is that I want to move the parsing function from the engine to the templater class so that we can peek keywords and functions used in a user template. This change also removes reference cycle between the templater and the engine.
contrib/python3-whitelist
mercurial/templater.py
tests/test-template-engine.t
--- a/contrib/python3-whitelist	Thu May 03 11:09:27 2018 +0900
+++ b/contrib/python3-whitelist	Thu May 03 10:58:56 2018 +0900
@@ -485,7 +485,6 @@
 test-symlinks.t
 test-tag.t
 test-tags.t
-test-template-engine.t
 test-template-filters.t
 test-treemanifest.t
 test-ui-color.py
--- a/mercurial/templater.py	Thu May 03 11:09:27 2018 +0900
+++ b/mercurial/templater.py	Thu May 03 10:58:56 2018 +0900
@@ -718,8 +718,6 @@
             mapping = extramapping
         return templateutil.flatten(self, mapping, func(self, mapping, data))
 
-engines = {'default': engine}
-
 def stylelist():
     paths = templatepaths()
     if not paths:
@@ -777,10 +775,7 @@
                                        conf.source('templates', key))
             cache[key] = unquotestring(val)
         elif key != '__base__':
-            val = 'default', val
-            if ':' in val[1]:
-                val = val[1].split(':', 1)
-            tmap[key] = val[0], os.path.join(base, val[1])
+            tmap[key] = os.path.join(base, val)
     aliases.extend(conf['templatealias'].items())
     return cache, tmap, aliases
 
@@ -815,7 +810,6 @@
         self._resources = resources
         self._aliases = aliases
         self._minchunk, self._maxchunk = minchunk, maxchunk
-        self._ecache = {}
 
     @classmethod
     def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
@@ -835,13 +829,13 @@
         '''Get the template for the given template name. Use a local cache.'''
         if t not in self.cache:
             try:
-                self.cache[t] = util.readfile(self._map[t][1])
+                self.cache[t] = util.readfile(self._map[t])
             except KeyError as inst:
                 raise templateutil.TemplateNotFound(
                     _('"%s" not in template map') % inst.args[0])
             except IOError as inst:
                 reason = (_('template file %s: %s')
-                          % (self._map[t][1],
+                          % (self._map[t],
                              stringutil.forcebytestr(inst.args[1])))
                 raise IOError(inst.args[0], encoding.strfromlocal(reason))
         return self.cache[t]
@@ -857,16 +851,8 @@
     def generate(self, t, mapping):
         """Return a generator that renders the specified named template and
         yields chunks"""
-        ttype = t in self._map and self._map[t][0] or 'default'
-        if ttype not in self._ecache:
-            try:
-                ecls = engines[ttype]
-            except KeyError:
-                raise error.Abort(_('invalid template engine: %s') % ttype)
-            self._ecache[ttype] = ecls(self.load, self._filters, self.defaults,
-                                       self._resources, self._aliases)
-        proc = self._ecache[ttype]
-
+        proc = engine(self.load, self._filters, self.defaults, self._resources,
+                      self._aliases)
         stream = proc.process(t, mapping)
         if self._minchunk:
             stream = util.increasingchunks(stream, min=self._minchunk,
--- a/tests/test-template-engine.t	Thu May 03 11:09:27 2018 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-
-  $ cat > engine.py << EOF
-  > 
-  > from mercurial import (
-  >     pycompat,
-  >     templater,
-  >     templateutil,
-  > )
-  > 
-  > class mytemplater(templater.engine):
-  >     def _load(self, t):
-  >         return self._loader(t)
-  > 
-  >     def process(self, t, map):
-  >         tmpl = self._load(t)
-  >         props = self._defaults.copy()
-  >         props.update(map)
-  >         for k, v in props.items():
-  >             if b'{{%s}}' % k not in tmpl:
-  >                 continue
-  >             if callable(v) and getattr(v, '_requires', None) is None:
-  >                 props = self._resources.copy()
-  >                 props.update(map)
-  >                 v = v(**pycompat.strkwargs(props))
-  >             elif callable(v):
-  >                 v = v(self, props)
-  >             v = templateutil.stringify(self, props, v)
-  >             tmpl = tmpl.replace(b'{{%s}}' % k, v)
-  >         yield tmpl
-  > 
-  > templater.engines[b'my'] = mytemplater
-  > EOF
-  $ hg init test
-  $ echo '[extensions]' > test/.hg/hgrc
-  $ echo "engine = `pwd`/engine.py" >> test/.hg/hgrc
-  $ cd test
-  $ cat > mymap << EOF
-  > changeset = my:changeset.txt
-  > EOF
-  $ cat > changeset.txt << EOF
-  > {{rev}} {{node}} {{author}}
-  > EOF
-  $ hg ci -Ama
-  adding changeset.txt
-  adding mymap
-  $ hg log --style=./mymap
-  0 97e5f848f0936960273bbf75be6388cd0350a32b test
-
-  $ cat > changeset.txt << EOF
-  > {{p1rev}} {{p1node}} {{p2rev}} {{p2node}}
-  > EOF
-  $ hg ci -Ama
-  $ hg log --style=./mymap
-  0 97e5f848f0936960273bbf75be6388cd0350a32b -1 0000000000000000000000000000000000000000
-  -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000
-
-invalid engine type:
-
-  $ echo 'changeset = unknown:changeset.txt' > unknownenginemap
-  $ hg log --style=./unknownenginemap
-  abort: invalid template engine: unknown
-  [255]
-
-  $ cd ..