mercurial/templater.py
changeset 1905 0c760737b996
parent 1904 a7e416bf3c1d
child 1906 9dec2479622d
equal deleted inserted replaced
1904:a7e416bf3c1d 1905:0c760737b996
    30     if escape: raise SyntaxError(_('unterminated escape'))
    30     if escape: raise SyntaxError(_('unterminated escape'))
    31     return fp.getvalue()
    31     return fp.getvalue()
    32 
    32 
    33 class templater(object):
    33 class templater(object):
    34     def __init__(self, mapfile, filters={}, defaults={}):
    34     def __init__(self, mapfile, filters={}, defaults={}):
       
    35         self.mapfile = mapfile or 'template'
    35         self.cache = {}
    36         self.cache = {}
    36         self.map = {}
    37         self.map = {}
    37         self.base = os.path.dirname(mapfile)
    38         self.base = (mapfile and os.path.dirname(mapfile)) or ''
    38         self.filters = filters
    39         self.filters = filters
    39         self.defaults = defaults
    40         self.defaults = defaults
    40 
    41 
       
    42         if not mapfile:
       
    43             return
    41         i = 0
    44         i = 0
    42         for l in file(mapfile):
    45         for l in file(mapfile):
       
    46             l = l.rstrip('\r\n')
    43             i += 1
    47             i += 1
    44             m = re.match(r'(\S+)\s*=\s*(["\'].*["\'])$', l)
    48             if l.startswith('#') or not l.strip(): continue
       
    49             m = re.match(r'([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$', l)
    45             if m:
    50             if m:
    46                 try:
    51                 key, val = m.groups()
    47                     s = m.group(2)
    52                 if val[0] in "'\"":
    48                     self.cache[m.group(1)] = parsestring(s)
    53                     try:
    49                 except SyntaxError, inst:
    54                         self.cache[key] = parsestring(val)
    50                     raise SyntaxError('%s:%s: %s' % (mapfile, i, inst.args[0]))
    55                     except SyntaxError, inst:
       
    56                         raise SyntaxError('%s:%s: %s' %
       
    57                                           (mapfile, i, inst.args[0]))
       
    58                 else:
       
    59                     self.map[key] = os.path.join(self.base, val)
    51             else:
    60             else:
    52                 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
    61                 raise SyntaxError(_("%s:%s: parse error") % (mapfile, i))
    53                 if m:
       
    54                     self.map[m.group(1)] = os.path.join(self.base, m.group(2))
       
    55                 else:
       
    56                     raise LookupError(_("unknown map entry '%s'") % l)
       
    57 
    62 
    58     def __contains__(self, key):
    63     def __contains__(self, key):
    59         return key in self.cache
    64         return key in self.cache
    60 
    65 
    61     def __call__(self, t, **map):
    66     def __call__(self, t, **map):
    62         m = self.defaults.copy()
    67         m = self.defaults.copy()
    63         m.update(map)
    68         m.update(map)
    64         try:
    69         try:
    65             tmpl = self.cache[t]
    70             tmpl = self.cache[t]
    66         except KeyError:
    71         except KeyError:
    67             tmpl = self.cache[t] = file(self.map[t]).read()
    72             try:
       
    73                 tmpl = self.cache[t] = file(self.map[t]).read()
       
    74             except IOError, inst:
       
    75                 raise IOError(inst.args[0], _('template file %s: %s') %
       
    76                               (self.map[t], inst.args[1]))
    68         return self.template(tmpl, self.filters, **m)
    77         return self.template(tmpl, self.filters, **m)
    69 
    78 
    70     template_re = re.compile(r"[#{]([a-zA-Z_][a-zA-Z0-9_]*)"
    79     template_re = re.compile(r"[#{]([a-zA-Z_][a-zA-Z0-9_]*)"
    71                              r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)"
    80                              r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)"
    72                              r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)[#}]")
    81                              r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)[#}]")
    74     def template(self, tmpl, filters={}, **map):
    83     def template(self, tmpl, filters={}, **map):
    75         lm = map.copy()
    84         lm = map.copy()
    76         while tmpl:
    85         while tmpl:
    77             m = self.template_re.search(tmpl)
    86             m = self.template_re.search(tmpl)
    78             if m:
    87             if m:
    79                 start = m.start(0)
    88                 start, end = m.span(0)
       
    89                 s, e = tmpl[start], tmpl[end - 1]
       
    90                 key = m.group(1)
       
    91                 if ((s == '#' and e != '#') or (s == '{' and e != '}')):
       
    92                     raise SyntaxError(_("'%s'/'%s' mismatch expanding '%s'") %
       
    93                                       (s, e, key))
    80                 if start:
    94                 if start:
    81                     yield tmpl[:start]
    95                     yield tmpl[:start]
    82                 v = map.get(m.group(1), "")
    96                 v = map.get(key, "")
    83                 v = callable(v) and v(**map) or v
    97                 v = callable(v) and v(**map) or v
    84 
    98 
    85                 format = m.group(2)
    99                 format = m.group(2)
    86                 fl = m.group(4)
   100                 fl = m.group(4)
    87 
   101 
    96                 elif fl:
   110                 elif fl:
    97                     for f in fl.split("|")[1:]:
   111                     for f in fl.split("|")[1:]:
    98                         v = filters[f](v)
   112                         v = filters[f](v)
    99 
   113 
   100                 yield v
   114                 yield v
   101                 tmpl = tmpl[m.end(0):]
   115                 tmpl = tmpl[end:]
   102             else:
   116             else:
   103                 yield tmpl
   117                 yield tmpl
   104                 break
   118                 break
   105 
   119 
   106 agescales = [("second", 1),
   120 agescales = [("second", 1),
   151 
   165 
   152 common_filters = {
   166 common_filters = {
   153     "addbreaks": nl2br,
   167     "addbreaks": nl2br,
   154     "age": age,
   168     "age": age,
   155     "date": lambda x: util.datestr(x),
   169     "date": lambda x: util.datestr(x),
       
   170     "domain": domain,
   156     "escape": lambda x: cgi.escape(x, True),
   171     "escape": lambda x: cgi.escape(x, True),
   157     "firstline": (lambda x: x.splitlines(1)[0]),
   172     "firstline": (lambda x: x.splitlines(1)[0]),
   158     "domain": domain,
       
   159     "obfuscate": obfuscate,
   173     "obfuscate": obfuscate,
   160     "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
   174     "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
   161     "person": person,
   175     "person": person,
   162     "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
   176     "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
   163     "short": (lambda x: x[:12]),
   177     "short": (lambda x: x[:12]),