Changeset 5322

Show
Ignore:
Timestamp:
09/10/09 09:05:56 (4 years ago)
Author:
jow
Message:

libs/web: drop the Lua template parser, the C implementation is faster in almost every case, even without caching

Location:
luci/trunk/libs/web
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • luci/trunk/libs/web/luasrc/template.lua

    r5112 r5322  
    3131local string = require "string" 
    3232local config = require "luci.config" 
    33 local coroutine = require "coroutine" 
    3433local nixio = require "nixio", require "nixio.util" 
    3534local tparser = require "luci.template.parser" 
     
    4443 
    4544config.template = config.template or {} 
    46  
    47 viewdir    = config.template.viewdir or util.libpath() .. "/view" 
    48 compiledir = config.template.compiledir or util.libpath() .. "/view" 
    49  
    50  
    51 -- Compile modes: 
    52 -- memory:  Always compile, do not save compiled files, ignore precompiled  
    53 -- file:    Compile on demand, save compiled files, update precompiled 
    54 compiler_mode = config.template.compiler_mode or "memory" 
     45viewdir = config.template.viewdir or util.libpath() .. "/view" 
    5546 
    5647 
    5748-- Define the namespace for template modules 
    5849context = util.threadlocal() 
    59  
    60 --- Manually  compile a given template into an executable Lua function 
    61 -- @param template  LuCI template 
    62 -- @return          Lua template function 
    63 function compile(template)   
    64     local expr = {} 
    65  
    66     -- Search all <% %> expressions 
    67     local function expr_add(ws1, skip1, command, skip2, ws2) 
    68         expr[#expr+1] = command 
    69         return ( #skip1 > 0 and "" or ws1 ) ..  
    70                "<%" .. tostring(#expr) .. "%>" .. 
    71                ( #skip2 > 0 and "" or ws2 ) 
    72     end 
    73      
    74     -- Save all expressiosn to table "expr" 
    75     template = template:gsub("(%s*)<%%(%-?)(.-)(%-?)%%>(%s*)", expr_add) 
    76      
    77     local function sanitize(s) 
    78         s = "%q" % s 
    79         return s:sub(2, #s-1) 
    80     end 
    81      
    82     -- Escape and sanitize all the template (all non-expressions) 
    83     template = sanitize(template) 
    84  
    85     -- Template module header/footer declaration 
    86     local header = 'write("' 
    87     local footer = '")' 
    88      
    89     template = header .. template .. footer 
    90      
    91     -- Replacements 
    92     local r_include = '")\ninclude("%s")\nwrite("' 
    93     local r_i18n    = '")\nwrite(translate("%1","%2"))\nwrite("' 
    94     local r_i18n2   = '")\nwrite(translate("%1", ""))\nwrite("' 
    95     local r_pexec   = '")\nwrite(tostring(%s or ""))\nwrite("' 
    96     local r_exec    = '")\n%s\nwrite("' 
    97      
    98     -- Parse the expressions 
    99     for k,v in pairs(expr) do 
    100         local p = v:sub(1, 1) 
    101         v = v:gsub("%%", "%%%%") 
    102         local re = nil 
    103         if p == "+" then 
    104             re = r_include:format(sanitize(string.sub(v, 2))) 
    105         elseif p == ":" then 
    106             if v:find(" ") then 
    107                 re = sanitize(v):gsub(":(.-) (.*)", r_i18n) 
    108             else 
    109                 re = sanitize(v):gsub(":(.+)", r_i18n2) 
    110             end 
    111         elseif p == "=" then 
    112             re = r_pexec:format(v:sub(2)) 
    113         elseif p == "#" then 
    114             re = "" 
    115         else 
    116             re = r_exec:format(v) 
    117         end 
    118         template = template:gsub("<%%"..tostring(k).."%%>", re) 
    119     end 
    120  
    121     return loadstring(template) 
    122 end 
    12350 
    12451--- Render a certain template. 
     
    13966-- Constructor - Reads and compiles the template on-demand 
    14067function Template.__init__(self, name)   
    141     local function _encode_filename(str) 
    142  
    143         local function __chrenc( chr ) 
    144             return "%%%02x" % string.byte( chr ) 
    145         end 
    146  
    147         if type(str) == "string" then 
    148             str = str:gsub( 
    149                 "([^a-zA-Z0-9$_%-%.%+!*'(),])", 
    150                 __chrenc 
    151             ) 
    152         end 
    153  
    154         return str 
    155     end 
    15668 
    15769    self.template = self.cache[name] 
     
    16274     
    16375    -- If we have a cached template, skip compiling and loading 
    164     if self.template then 
    165         return 
    166     end 
    167      
    168     -- Enforce cache security 
    169     local cdir = compiledir .. "/" .. sys.process.info("uid") 
    170      
    171     -- Compile and build 
    172     local sourcefile   = viewdir    .. "/" .. name 
    173     local compiledfile = cdir .. "/" .. _encode_filename(name) .. ".lua" 
    174     local err    
    175      
    176     if compiler_mode == "file" then 
    177         local tplmt = fs.stat(sourcefile, "mtime") or fs.stat(sourcefile .. ".htm", "mtime") 
    178         local commt = fs.stat(compiledfile, "mtime") 
    179          
    180         if not fs.stat(cdir, "mtime") then 
    181             fs.mkdirr(cdir) 
    182             fs.chmod(fs.dirname(cdir), 777) 
     76    if not self.template then 
     77 
     78        -- Compile template 
     79        local sourcefile = viewdir .. "/" .. name .. ".htm" 
     80        self.template, _, err = tparser.parse(sourcefile) 
     81 
     82        -- If we have no valid template throw error, otherwise cache the template 
     83        if not self.template then 
     84            error(err) 
     85        else 
     86            self.cache[name] = self.template 
    18387        end 
    184          
    185         assert(tplmt or commt, "No such template: " .. name) 
    186                  
    187         -- Build if there is no compiled file or if compiled file is outdated 
    188         if not commt or (commt and tplmt and commt < tplmt) then 
    189             local source 
    190             source, err = fs.readfile(sourcefile) or fs.readfile(sourcefile .. ".htm") 
    191              
    192             if source then 
    193                 local compiled, err = compile(source) 
    194                  
    195                 local f = nixio.open(compiledfile, "w", 600) 
    196                 f:writeall(util.get_bytecode(compiled)) 
    197                 f:close() 
    198                 self.template = compiled 
    199             end 
    200         else 
    201             assert( 
    202                 sys.process.info("uid") == fs.stat(compiledfile, "uid") 
    203                 and fs.stat(compiledfile, "modestr") == "rw-------", 
    204                 "Fatal: Cachefile is not sane!" 
    205             ) 
    206             self.template, err = loadfile(compiledfile) 
    207         end 
    208          
    209     elseif compiler_mode == "memory" then 
    210         self.template, _, err = tparser.parse(sourcefile .. ".htm") 
    211     end 
    212      
    213     -- If we have no valid template throw error, otherwise cache the template 
    214     if not self.template then 
    215         error(err) 
    216     else 
    217         self.cache[name] = self.template 
    21888    end 
    21989end 
  • luci/trunk/libs/web/root/etc/config/luci

    r5138 r5322  
    2121config internal ccache 
    2222    option enable 1 
    23  
    24 config internal template 
    25     option compiler_mode memory 
    26     option compiledir "/tmp/luci-templatecache" 
    2723         
    2824config internal themes