mercurial/templateutil.py
changeset 37272 7d3bc1d4e871
parent 37231 dc4bb1422f2b
child 37273 83e1bbd48991
equal deleted inserted replaced
37271:0194dac77c93 37272:7d3bc1d4e871
   118     if fmt is None:
   118     if fmt is None:
   119         fmt = '%s'
   119         fmt = '%s'
   120         prefmt = pycompat.bytestr
   120         prefmt = pycompat.bytestr
   121     return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
   121     return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
   122 
   122 
   123 def unwraphybrid(thing):
   123 def unwraphybrid(context, mapping, thing):
   124     """Return an object which can be stringified possibly by using a legacy
   124     """Return an object which can be stringified possibly by using a legacy
   125     template"""
   125     template"""
   126     gen = getattr(thing, 'gen', None)
   126     gen = getattr(thing, 'gen', None)
   127     if gen is None:
   127     if gen is None:
   128         return thing
   128         return thing
   239         yield one(last, tag=lastname)
   239         yield one(last, tag=lastname)
   240     endname = 'end_' + plural
   240     endname = 'end_' + plural
   241     if context.preload(endname):
   241     if context.preload(endname):
   242         yield context.process(endname, mapping)
   242         yield context.process(endname, mapping)
   243 
   243 
   244 def flatten(thing):
   244 def flatten(context, mapping, thing):
   245     """Yield a single stream from a possibly nested set of iterators"""
   245     """Yield a single stream from a possibly nested set of iterators"""
   246     thing = unwraphybrid(thing)
   246     thing = unwraphybrid(context, mapping, thing)
   247     if isinstance(thing, bytes):
   247     if isinstance(thing, bytes):
   248         yield thing
   248         yield thing
   249     elif isinstance(thing, str):
   249     elif isinstance(thing, str):
   250         # We can only hit this on Python 3, and it's here to guard
   250         # We can only hit this on Python 3, and it's here to guard
   251         # against infinite recursion.
   251         # against infinite recursion.
   255         pass
   255         pass
   256     elif not util.safehasattr(thing, '__iter__'):
   256     elif not util.safehasattr(thing, '__iter__'):
   257         yield pycompat.bytestr(thing)
   257         yield pycompat.bytestr(thing)
   258     else:
   258     else:
   259         for i in thing:
   259         for i in thing:
   260             i = unwraphybrid(i)
   260             i = unwraphybrid(context, mapping, i)
   261             if isinstance(i, bytes):
   261             if isinstance(i, bytes):
   262                 yield i
   262                 yield i
   263             elif i is None:
   263             elif i is None:
   264                 pass
   264                 pass
   265             elif not util.safehasattr(i, '__iter__'):
   265             elif not util.safehasattr(i, '__iter__'):
   266                 yield pycompat.bytestr(i)
   266                 yield pycompat.bytestr(i)
   267             else:
   267             else:
   268                 for j in flatten(i):
   268                 for j in flatten(context, mapping, i):
   269                     yield j
   269                     yield j
   270 
   270 
   271 def stringify(thing):
   271 def stringify(context, mapping, thing):
   272     """Turn values into bytes by converting into text and concatenating them"""
   272     """Turn values into bytes by converting into text and concatenating them"""
   273     if isinstance(thing, bytes):
   273     if isinstance(thing, bytes):
   274         return thing  # retain localstr to be round-tripped
   274         return thing  # retain localstr to be round-tripped
   275     return b''.join(flatten(thing))
   275     return b''.join(flatten(context, mapping, thing))
   276 
   276 
   277 def findsymbolicname(arg):
   277 def findsymbolicname(arg):
   278     """Find symbolic name for the given compiled expression; returns None
   278     """Find symbolic name for the given compiled expression; returns None
   279     if nothing found reliably"""
   279     if nothing found reliably"""
   280     while True:
   280     while True:
   292     func, data = arg
   292     func, data = arg
   293     return func(context, mapping, data)
   293     return func(context, mapping, data)
   294 
   294 
   295 def evalfuncarg(context, mapping, arg):
   295 def evalfuncarg(context, mapping, arg):
   296     """Evaluate given argument as value type"""
   296     """Evaluate given argument as value type"""
   297     return _unwrapvalue(evalrawexp(context, mapping, arg))
   297     return _unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
   298 
   298 
   299 # TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
   299 # TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
   300 # is fixed. we can't do that right now because join() has to take a generator
   300 # is fixed. we can't do that right now because join() has to take a generator
   301 # of byte strings as it is, not a lazy byte string.
   301 # of byte strings as it is, not a lazy byte string.
   302 def _unwrapvalue(thing):
   302 def _unwrapvalue(context, mapping, thing):
   303     thing = unwrapvalue(thing)
   303     thing = unwrapvalue(thing)
   304     # evalrawexp() may return string, generator of strings or arbitrary object
   304     # evalrawexp() may return string, generator of strings or arbitrary object
   305     # such as date tuple, but filter does not want generator.
   305     # such as date tuple, but filter does not want generator.
   306     if isinstance(thing, types.GeneratorType):
   306     if isinstance(thing, types.GeneratorType):
   307         thing = stringify(thing)
   307         thing = stringify(context, mapping, thing)
   308     return thing
   308     return thing
   309 
   309 
   310 def evalboolean(context, mapping, arg):
   310 def evalboolean(context, mapping, arg):
   311     """Evaluate given argument as boolean, but also takes boolean literals"""
   311     """Evaluate given argument as boolean, but also takes boolean literals"""
   312     func, data = arg
   312     func, data = arg
   320     thing = unwrapvalue(thing)
   320     thing = unwrapvalue(thing)
   321     if isinstance(thing, bool):
   321     if isinstance(thing, bool):
   322         return thing
   322         return thing
   323     # other objects are evaluated as strings, which means 0 is True, but
   323     # other objects are evaluated as strings, which means 0 is True, but
   324     # empty dict/list should be False as they are expected to be ''
   324     # empty dict/list should be False as they are expected to be ''
   325     return bool(stringify(thing))
   325     return bool(stringify(context, mapping, thing))
   326 
   326 
   327 def evaldate(context, mapping, arg, err=None):
   327 def evaldate(context, mapping, arg, err=None):
   328     """Evaluate given argument as a date tuple or a date string; returns
   328     """Evaluate given argument as a date tuple or a date string; returns
   329     a (unixtime, offset) tuple"""
   329     a (unixtime, offset) tuple"""
   330     return unwrapdate(evalrawexp(context, mapping, arg), err)
   330     thing = evalrawexp(context, mapping, arg)
   331 
   331     return unwrapdate(context, mapping, thing, err)
   332 def unwrapdate(thing, err=None):
   332 
   333     thing = _unwrapvalue(thing)
   333 def unwrapdate(context, mapping, thing, err=None):
       
   334     thing = _unwrapvalue(context, mapping, thing)
   334     try:
   335     try:
   335         return dateutil.parsedate(thing)
   336         return dateutil.parsedate(thing)
   336     except AttributeError:
   337     except AttributeError:
   337         raise error.ParseError(err or _('not a date tuple nor a string'))
   338         raise error.ParseError(err or _('not a date tuple nor a string'))
   338     except error.ParseError:
   339     except error.ParseError:
   339         if not err:
   340         if not err:
   340             raise
   341             raise
   341         raise error.ParseError(err)
   342         raise error.ParseError(err)
   342 
   343 
   343 def evalinteger(context, mapping, arg, err=None):
   344 def evalinteger(context, mapping, arg, err=None):
   344     return unwrapinteger(evalrawexp(context, mapping, arg), err)
   345     thing = evalrawexp(context, mapping, arg)
   345 
   346     return unwrapinteger(context, mapping, thing, err)
   346 def unwrapinteger(thing, err=None):
   347 
   347     thing = _unwrapvalue(thing)
   348 def unwrapinteger(context, mapping, thing, err=None):
       
   349     thing = _unwrapvalue(context, mapping, thing)
   348     try:
   350     try:
   349         return int(thing)
   351         return int(thing)
   350     except (TypeError, ValueError):
   352     except (TypeError, ValueError):
   351         raise error.ParseError(err or _('not an integer'))
   353         raise error.ParseError(err or _('not an integer'))
   352 
   354 
   353 def evalstring(context, mapping, arg):
   355 def evalstring(context, mapping, arg):
   354     return stringify(evalrawexp(context, mapping, arg))
   356     return stringify(context, mapping, evalrawexp(context, mapping, arg))
   355 
   357 
   356 def evalstringliteral(context, mapping, arg):
   358 def evalstringliteral(context, mapping, arg):
   357     """Evaluate given argument as string template, but returns symbol name
   359     """Evaluate given argument as string template, but returns symbol name
   358     if it is unknown"""
   360     if it is unknown"""
   359     func, data = arg
   361     func, data = arg
   360     if func is runsymbol:
   362     if func is runsymbol:
   361         thing = func(context, mapping, data, default=data)
   363         thing = func(context, mapping, data, default=data)
   362     else:
   364     else:
   363         thing = func(context, mapping, data)
   365         thing = func(context, mapping, data)
   364     return stringify(thing)
   366     return stringify(context, mapping, thing)
   365 
   367 
   366 _unwrapfuncbytype = {
   368 _unwrapfuncbytype = {
   367     None: _unwrapvalue,
   369     None: _unwrapvalue,
   368     bytes: stringify,
   370     bytes: stringify,
   369     date: unwrapdate,
   371     date: unwrapdate,
   370     int: unwrapinteger,
   372     int: unwrapinteger,
   371 }
   373 }
   372 
   374 
   373 def unwrapastype(thing, typ):
   375 def unwrapastype(context, mapping, thing, typ):
   374     """Move the inner value object out of the wrapper and coerce its type"""
   376     """Move the inner value object out of the wrapper and coerce its type"""
   375     try:
   377     try:
   376         f = _unwrapfuncbytype[typ]
   378         f = _unwrapfuncbytype[typ]
   377     except KeyError:
   379     except KeyError:
   378         raise error.ProgrammingError('invalid type specified: %r' % typ)
   380         raise error.ProgrammingError('invalid type specified: %r' % typ)
   379     return f(thing)
   381     return f(context, mapping, thing)
   380 
   382 
   381 def runinteger(context, mapping, data):
   383 def runinteger(context, mapping, data):
   382     return int(data)
   384     return int(data)
   383 
   385 
   384 def runstring(context, mapping, data):
   386 def runstring(context, mapping, data):
   423         yield evalrawexp(context, mapping, arg)
   425         yield evalrawexp(context, mapping, arg)
   424 
   426 
   425 def runfilter(context, mapping, data):
   427 def runfilter(context, mapping, data):
   426     arg, filt = data
   428     arg, filt = data
   427     thing = evalrawexp(context, mapping, arg)
   429     thing = evalrawexp(context, mapping, arg)
       
   430     intype = getattr(filt, '_intype', None)
   428     try:
   431     try:
   429         thing = unwrapastype(thing, getattr(filt, '_intype', None))
   432         thing = unwrapastype(context, mapping, thing, intype)
   430         return filt(thing)
   433         return filt(thing)
   431     except error.ParseError as e:
   434     except error.ParseError as e:
   432         raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
   435         raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
   433 
   436 
   434 def _formatfiltererror(arg, filt):
   437 def _formatfiltererror(arg, filt):