import io import re import sys import os from hserver.api.WebCallable import WebCallable import html import builtins from simplelog import log def text2html(text): lines = text.splitlines() html = "" for l in lines: html = "{0}

{1}

".format(html,l) return html class SandboxPrinter: def __init__(self,stream): self.stream = stream def __call__(self,te = ""): self.stream.write(str(te)) class SandboxInclude: def __init__(self,template): self.__template = template def __call__(self,template,selfref = None): if (selfref is None): self.__template.include( template ) else: self.__template.include( [template, selfref] ) class TemplateSegment: def __init__(self,template,parent = None): self.__template = template self.__parent = parent def setParent(self,parent): self.__parent = parent def getParent(self): return self.__parent def getTemplate(self): return self.__template def run(self,env,priv = {}): """Run this Segement of the Template""" pass def __repr__(self): return "" class TemplateGroupSegment(TemplateSegment): def __init__(self,template,parent = None): TemplateSegment.__init__(self,template,parent) self.__children = [] def appendChild(self,segment): self.__children.append(segment) def getChildren(self): return self.__children def run(self,env,priv={}): for child in self.__children: child.run(env,priv) def __repr__(self): return "" % (str(self.getChildren()),) class TemplateTextSegment(TemplateSegment): def __init__(self,template,parent = None,text = ""): TemplateSegment.__init__(self,template,parent) self.__text = text def run(self,env,priv={}): self.getTemplate().getContentFile().write(self.__text) def __repr__(self): return "" class TemplateCodeSegment(TemplateSegment): def __init__(self,template,parent = None,code = ""): TemplateSegment.__init__(self,template,parent) self.__code = code def run(self,env,priv={}): exec( self.__code, env ) def __repr__(self): return "" %(self.__code,) class TemplateValueSegment(TemplateSegment): def __init__(self,template,parent = None,code = ""): TemplateSegment.__init__(self,template,parent) self.__code = code def run(self,env,priv={}): code = self.__code v = eval( code, env ) self.getTemplate().getContentFile().write(str(v)) class TemplateIterateSegment(TemplateGroupSegment): def __init__(self,template,parent = None,code = ""): TemplateGroupSegment.__init__(self,template,parent) (self.__iterator, self.__iteration) = code.split(" ",1) def run(self,env,priv={}): iter = eval( self.__iteration, env ) for v in iter: env[self.__iterator] = v TemplateGroupSegment.run(self,env,priv) def __repr__(self): return "" % (self.__iterator,self.__iteration,self.getChildren(),) class TemplateUseSegment(TemplateSegment): def __init__(self,template,parent = None,code = ""): TemplateSegment.__init__(self,template,parent) print("USE: {0}".format(code)) (self._name,self._arguments) = code.split(" ",1) def name(self): return self._name def run(self,env,priv={}): args = eval(self._arguments, env) tmpl = self.getTemplate().getDefine( self._name ) e = dict( env ) if isinstance( args, dict ): e.update( args ) else: e["args"] = args tmpl.use(e,priv) def __repr__(self): return "" % (self.__iterator,self.__iteration,self.getChildren(),) class TemplateDefineSegment(TemplateGroupSegment): def __init__(self,template,parent = None,code = ""): TemplateGroupSegment.__init__(self,template,parent) self._name = code template.addDefine( self ) def name(self): return self._name def run(self,env,priv={}): pass def use(self,env,priv={}): TemplateGroupSegment.run(self,env,priv) def __repr__(self): return "" % (self.__iterator,self.__iteration,self.getChildren(),) class TemplateIfSegment(TemplateGroupSegment): def __init__(self,template,parent = None,code = ""): TemplateGroupSegment.__init__(self,template,parent) self.__code = code def run(self,env,priv={}): v = eval( self.__code, env ) if (v): TemplateGroupSegment.run(self,env,priv) def __repr__(self): return "" % (str(self.__children),) class TemplateIncludeSegment(TemplateSegment): def __init__(self,template,parent = None,code = ""): TemplateSegment.__init__(self,template,parent) self.__code = code def run(self,env,priv={}): v = eval( self.__code, env ) self.getTemplate().include(v,priv={}) def __repr__(self): return "" % (str(self.__code),) class TemplateContentSegment(TemplateSegment): def __init__(self,template,parent = None): TemplateSegment.__init__(self,template,parent) def run(self,env,priv={}): if (not priv is None) and ("framed" in priv) and (not priv["framed"] is None): priv["framed"].framed(env,priv) def __repr__(self): return "" % (str(self.__code),) class Template(WebCallable): def __init__(self,template=None,base = ".",source = None,disable_sandbox=False,frame=None,provider=None): self.template = template self.base = base self.__content = None self.__frame = frame self.__source = source self.__root = None self.__current = self.__root self.__disable_sandbox = disable_sandbox self.__timestamp = None self.__provider = provider self.__defines = {} def getContent(self): return self.__content.getvalue() def getContentFile(self): return self.__content def setFrame(self,frame): self.__frame = frame def provider(self): return self.__provider def addDefine(self,define): self.__defines[ define.name() ] = define def getDefine(self,name): return self.__defines[ name ] def __appendSegment(self,segment): self.__current.appendChild(segment) def __appendGroup(self,segment): self.__appendSegment(segment) self.__current = segment def __leaveGroup(self): if (self.__current != self.__root) and (self.__current.getParent() is not None): self.__current = self.__current.getParent() def indexWS(self,te): p = 0 while (p < len(te)): if (ord(te[p]) <= 0x20): return p p = p + 1 return p def __splittag(self,tag): "Split to a list of [ , ]" if (ord(tag[0]) <= 0x20): return ["",tag[1:]] elif (tag[0]=="="): return ["=",tag[1:]] else: i = self.indexWS(tag) if (i == len(tag)): return [ tag , "" ] else: return [ tag[:i], tag[ i+1: ] ] def __parsetag(self,tag): (action,expr) = self.__splittag(tag) if (action == ""): self.__appendSegment( TemplateCodeSegment(self,self.__current,expr) ) elif (action == "="): self.__appendSegment( TemplateValueSegment(self,self.__current,expr) ) elif (action == "include"): self.__appendSegment( TemplateIncludeSegment(self,self.__current,expr) ) elif (action == "iterate"): s = TemplateIterateSegment(self,self.__current,expr) self.__appendGroup( s ) elif (action == "if"): s = TemplateIfSegment(self,self.__current,expr) self.__appendGroup( s ) elif (action == "define"): s = TemplateDefineSegment(self,self.__current,expr) self.__appendGroup( s ) elif (action == "end"): self.__leaveGroup() elif (action == "content"): self.__appendSegment( TemplateContentSegment( self, self.__current )) elif (action == "use"): self.__appendSegment( TemplateUseSegment( self, self.__current, expr )) elif (action == "frame"): self.__frame = expr print("FRAME = {0} : {1}".format(expr, self.__frame)) # self.__frame = self.__provider.provide( expr ) else: pass def __parse(self,source): if self.__root is None: self.__root = TemplateGroupSegment(self) self.__current = self.__root pos = 0; while (len(source) > pos): iopen = None iclose = None try: iopen = source.index( "<%", pos ) iclose = source.index( "%>", iopen ) except ValueError as ve: self.debugException(ve) if (iopen is None): iopen = len(source) iclose = len(source) else: raise ve if (iopen > pos): self.__appendSegment( TemplateTextSegment(self, self.__current, source[pos : iopen]) ) if (iopen < len(source)): self.__parsetag( source[ iopen + 2 : iclose ] ) pos = iclose + 2 def debugException(self,ex): pass def __load_source(self): if not self.template is None: tfilename = "%s/%s" % (self.base,self.template) st = os.stat( tfilename ) print("Template.__load_source(): Check %s > %s" % (st.st_mtime, self.__timestamp)) if (self.__timestamp is None) or (st.st_mtime > self.__timestamp): self.__timestamp = st.st_mtime tfile = open(tfilename,"r") self.__source = tfile.read() tfile.close() self.__root = None __allowed_builtins = ["getattr","setattr","hasattr","range","abs","dict","hex","int","float","bytes","bool","chr","ord","pow","str","map","round","len"] def run(self,o = None,env = {},outfile=None,framed=None): save_content = self.__content if (not outfile is None): self.__content = outfile else: self.__content = io.StringIO() priv = {} priv["framed"] = framed self.__load_source() self.__parse(self.__source) if o is not None: env['self'] = o if not self.__disable_sandbox: env['__builtins__'] = { getattr: getattr } env['print'] = SandboxPrinter(self.__content) env['include'] = SandboxInclude(self) env['escape'] = html.escape env['text2html'] = text2html for an in self.__allowed_builtins: if hasattr(globals(),an): env[an] = getattr(globals(),an) if hasattr(builtins,an): env[an] = getattr(builtins,an) print("Template.run(): my frame is: %s" % (self.__frame,)) self.env = env if self.__frame is not None: self.frame(env) else: self.__root.run(env,priv) if (isinstance( self.__content, io.StringIO) ): c = self.__content.getvalue() else: c = None self.__content = save_content return c def frame(self,env): fv = eval( self.__frame, env ) f = self.findTemplate( fv ) print("Template: Framing with %s" % (f,)) f.run(env=env,outfile=self.__content,framed=self) def framed(self,env,priv): print("Frame %s called %s" % (self.__frame,self)) self.__root.run(env,priv) def include(self,expr,priv): log("