diff options
Diffstat (limited to 'sys/src/cmd/hg/mercurial/templater.py')
-rw-r--r-- | sys/src/cmd/hg/mercurial/templater.py | 245 |
1 files changed, 0 insertions, 245 deletions
diff --git a/sys/src/cmd/hg/mercurial/templater.py b/sys/src/cmd/hg/mercurial/templater.py deleted file mode 100644 index 86a674fbb..000000000 --- a/sys/src/cmd/hg/mercurial/templater.py +++ /dev/null @@ -1,245 +0,0 @@ -# templater.py - template expansion for output -# -# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2, incorporated herein by reference. - -from i18n import _ -import re, sys, os -import util, config, templatefilters - -path = ['templates', '../templates'] -stringify = templatefilters.stringify - -def parsestring(s, quoted=True): - '''parse a string using simple c-like syntax. - string must be in quotes if quoted is True.''' - if quoted: - if len(s) < 2 or s[0] != s[-1]: - raise SyntaxError(_('unmatched quotes')) - return s[1:-1].decode('string_escape') - - return s.decode('string_escape') - -class engine(object): - '''template expansion engine. - - template expansion works like this. a map file contains key=value - pairs. if value is quoted, it is treated as string. otherwise, it - is treated as name of template file. - - templater is asked to expand a key in map. it looks up key, and - looks for strings like this: {foo}. it expands {foo} by looking up - foo in map, and substituting it. expansion is recursive: it stops - when there is no more {foo} to replace. - - expansion also allows formatting and filtering. - - format uses key to expand each item in list. syntax is - {key%format}. - - filter uses function to transform value. syntax is - {key|filter1|filter2|...}.''' - - template_re = re.compile(r'{([\w\|%]+)}|#([\w\|%]+)#') - - def __init__(self, loader, filters={}, defaults={}): - self.loader = loader - self.filters = filters - self.defaults = defaults - self.cache = {} - - def process(self, t, map): - '''Perform expansion. t is name of map element to expand. map contains - added elements for use during expansion. Is a generator.''' - tmpl = self.loader(t) - iters = [self._process(tmpl, map)] - while iters: - try: - item = iters[0].next() - except StopIteration: - iters.pop(0) - continue - if isinstance(item, str): - yield item - elif item is None: - yield '' - elif hasattr(item, '__iter__'): - iters.insert(0, iter(item)) - else: - yield str(item) - - def _format(self, expr, get, map): - key, format = expr.split('%') - v = get(key) - if not hasattr(v, '__iter__'): - raise SyntaxError(_("error expanding '%s%%%s'") % (key, format)) - lm = map.copy() - for i in v: - lm.update(i) - yield self.process(format, lm) - - def _filter(self, expr, get, map): - if expr not in self.cache: - parts = expr.split('|') - val = parts[0] - try: - filters = [self.filters[f] for f in parts[1:]] - except KeyError, i: - raise SyntaxError(_("unknown filter '%s'") % i[0]) - def apply(get): - x = get(val) - for f in filters: - x = f(x) - return x - self.cache[expr] = apply - return self.cache[expr](get) - - def _process(self, tmpl, map): - '''Render a template. Returns a generator.''' - - def get(key): - v = map.get(key) - if v is None: - v = self.defaults.get(key, '') - if hasattr(v, '__call__'): - v = v(**map) - return v - - while tmpl: - m = self.template_re.search(tmpl) - if not m: - yield tmpl - break - - start, end = m.span(0) - variants = m.groups() - expr = variants[0] or variants[1] - - if start: - yield tmpl[:start] - tmpl = tmpl[end:] - - if '%' in expr: - yield self._format(expr, get, map) - elif '|' in expr: - yield self._filter(expr, get, map) - else: - yield get(expr) - -engines = {'default': engine} - -class templater(object): - - def __init__(self, mapfile, filters={}, defaults={}, cache={}, - minchunk=1024, maxchunk=65536): - '''set up template engine. - mapfile is name of file to read map definitions from. - filters is dict of functions. each transforms a value into another. - defaults is dict of default map definitions.''' - self.mapfile = mapfile or 'template' - self.cache = cache.copy() - self.map = {} - self.base = (mapfile and os.path.dirname(mapfile)) or '' - self.filters = templatefilters.filters.copy() - self.filters.update(filters) - self.defaults = defaults - self.minchunk, self.maxchunk = minchunk, maxchunk - self.engines = {} - - if not mapfile: - return - if not os.path.exists(mapfile): - raise util.Abort(_('style not found: %s') % mapfile) - - conf = config.config() - conf.read(mapfile) - - for key, val in conf[''].items(): - if val[0] in "'\"": - try: - self.cache[key] = parsestring(val) - except SyntaxError, inst: - raise SyntaxError('%s: %s' % - (conf.source('', key), inst.args[0])) - else: - val = 'default', val - if ':' in val[1]: - val = val[1].split(':', 1) - self.map[key] = val[0], os.path.join(self.base, val[1]) - - def __contains__(self, key): - return key in self.cache or key in self.map - - def load(self, t): - '''Get the template for the given template name. Use a local cache.''' - if not t in self.cache: - try: - self.cache[t] = open(self.map[t][1]).read() - except IOError, inst: - raise IOError(inst.args[0], _('template file %s: %s') % - (self.map[t][1], inst.args[1])) - return self.cache[t] - - def __call__(self, t, **map): - ttype = t in self.map and self.map[t][0] or 'default' - proc = self.engines.get(ttype) - if proc is None: - proc = engines[ttype](self.load, self.filters, self.defaults) - self.engines[ttype] = proc - - stream = proc.process(t, map) - if self.minchunk: - stream = util.increasingchunks(stream, min=self.minchunk, - max=self.maxchunk) - return stream - -def templatepath(name=None): - '''return location of template file or directory (if no name). - returns None if not found.''' - normpaths = [] - - # executable version (py2exe) doesn't support __file__ - if hasattr(sys, 'frozen'): - module = sys.executable - else: - module = __file__ - for f in path: - if f.startswith('/'): - p = f - else: - fl = f.split('/') - p = os.path.join(os.path.dirname(module), *fl) - if name: - p = os.path.join(p, name) - if name and os.path.exists(p): - return os.path.normpath(p) - elif os.path.isdir(p): - normpaths.append(os.path.normpath(p)) - - return normpaths - -def stylemap(style, paths=None): - """Return path to mapfile for a given style. - - Searches mapfile in the following locations: - 1. templatepath/style/map - 2. templatepath/map-style - 3. templatepath/map - """ - - if paths is None: - paths = templatepath() - elif isinstance(paths, str): - paths = [paths] - - locations = style and [os.path.join(style, "map"), "map-" + style] or [] - locations.append("map") - for path in paths: - for location in locations: - mapfile = os.path.join(path, location) - if os.path.isfile(mapfile): - return mapfile - - raise RuntimeError("No hgweb templates found in %r" % paths) |