# HG changeset patch # User Yuya Nishihara # Date 1513857805 -32400 # Node ID d6cfa722b04466ebc645e7ccc3a2b5b75873cff0 # Parent 7906354cbc68429109304a96d30c933fb4d87d20 templater: look up mapping table through template engine These functions are stub for symbol/resource separation. This series is intended to address the following problems: a) internal data may be exposed to user (issue5699) b) defaults['repo'] (a repository name) will conflict with mapping['repo'] (a repo object) in hgweb diff -r 7906354cbc68 -r d6cfa722b044 mercurial/templater.py --- a/mercurial/templater.py Mon Dec 18 17:33:43 2017 -0800 +++ b/mercurial/templater.py Thu Dec 21 21:03:25 2017 +0900 @@ -382,9 +382,7 @@ raise error.Abort(_("recursive reference '%s' in template") % key) def runsymbol(context, mapping, key, default=''): - v = mapping.get(key) - if v is None: - v = context._defaults.get(key) + v = context.symbol(mapping, key) if v is None: # put poison to cut recursion. we can't move this to parsing phase # because "x = {x}" is allowed if "x" is a keyword. (issue4758) @@ -626,7 +624,7 @@ return [s] return [] - ctx = mapping['ctx'] + ctx = context.resource(mapping, 'ctx') chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1))) return ''.join(chunks) @@ -639,8 +637,8 @@ raise error.ParseError(_('extdata expects one argument')) source = evalstring(context, mapping, args['source']) - cache = mapping['cache'].setdefault('extdata', {}) - ctx = mapping['ctx'] + cache = context.resource(mapping, 'cache').setdefault('extdata', {}) + ctx = context.resource(mapping, 'ctx') if source in cache: data = cache[source] else: @@ -656,7 +654,7 @@ raise error.ParseError(_("files expects one argument")) raw = evalstring(context, mapping, args[0]) - ctx = mapping['ctx'] + ctx = context.resource(mapping, 'ctx') m = ctx.match([raw]) files = list(ctx.matches(m)) return templatekw.showlist("file", files, mapping) @@ -692,7 +690,7 @@ # i18n: "formatnode" is a keyword raise error.ParseError(_("formatnode expects one argument")) - ui = mapping['ui'] + ui = context.resource(mapping, 'ui') node = evalstring(context, mapping, args[0]) if ui.debugflag: return node @@ -858,7 +856,7 @@ # i18n: "label" is a keyword raise error.ParseError(_("label expects two arguments")) - ui = mapping['ui'] + ui = context.resource(mapping, 'ui') thing = evalstring(context, mapping, args[1]) # preserve unknown symbol as literal so effects like 'red', 'bold', # etc. don't need to be quoted @@ -1030,7 +1028,7 @@ # i18n: "relpath" is a keyword raise error.ParseError(_("relpath expects one argument")) - repo = mapping['ctx'].repo() + repo = context.resource(mapping, 'ctx').repo() path = evalstring(context, mapping, args[0]) return repo.pathto(path) @@ -1043,7 +1041,7 @@ raise error.ParseError(_("revset expects one or more arguments")) raw = evalstring(context, mapping, args[0]) - ctx = mapping['ctx'] + ctx = context.resource(mapping, 'ctx') repo = ctx.repo() def query(expr): @@ -1055,7 +1053,8 @@ revs = query(revsetlang.formatspec(raw, *formatargs)) revs = list(revs) else: - revsetcache = mapping['cache'].setdefault("revsetcache", {}) + cache = context.resource(mapping, 'cache') + revsetcache = cache.setdefault("revsetcache", {}) if raw in revsetcache: revs = revsetcache[raw] else: @@ -1116,7 +1115,7 @@ # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. - cl = mapping['ctx']._repo.unfiltered().changelog + cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog return cl.shortest(node, minlength) @templatefunc('strip(text[, chars])') @@ -1302,6 +1301,18 @@ self._aliasmap = _aliasrules.buildmap(aliases) self._cache = {} # key: (func, data) + def symbol(self, mapping, key): + """Resolve symbol to value or function; None if nothing found""" + v = mapping.get(key) + if v is None: + v = self._defaults.get(key) + return v + + def resource(self, mapping, key): + """Return internal data (e.g. cache) used for keyword/function + evaluation""" + return mapping[key] + def _load(self, t): '''load, parse, and cache a template''' if t not in self._cache: