* luci/libs: uvl: add support for external validation commands, various cleanups
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 17 Aug 2008 17:40:57 +0000 (17:40 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 17 Aug 2008 17:40:57 +0000 (17:40 +0000)
libs/uvl/luasrc/uvl.lua
libs/uvl/luasrc/uvl/dependencies.lua
libs/uvl/luasrc/uvl/loghelper.lua
libs/uvl/luasrc/uvl/validation.lua [new file with mode: 0644]

index d778cfc3af301e149ce065dafaa5cd9ce64319cd..aa3aeb361d170ee41aec29136365c277156c19fe 100644 (file)
@@ -21,15 +21,16 @@ require("luci.util")
 require("luci.model.uci")
 require("luci.uvl.loghelper")
 require("luci.uvl.datatypes")
---require("luci.uvl.validation")
+require("luci.uvl.validation")
 require("luci.uvl.dependencies")
 
 TYPE_SECTION  = 0x01
 TYPE_VARIABLE = 0x02
 TYPE_ENUM     = 0x03
 
-STRICT_UNKNOWN_SECTIONS = true
-STRICT_UNKNOWN_OPTIONS  = true
+STRICT_UNKNOWN_SECTIONS    = true
+STRICT_UNKNOWN_OPTIONS     = true
+STRICT_EXTERNAL_VALIDATORS = true
 
 
 local default_schemedir = "/etc/scheme"
@@ -242,6 +243,11 @@ function UVL._validate_option( self, option, nodeps )
                if not nodeps then
                        return luci.uvl.dependencies.check( self, option )
                end
+
+               local ok, err = luci.uvl.validation.check( self, option )
+               if not ok and STRICT_EXTERNAL_VALIDATORS then
+                       return false, self.log.validator_error( option, err )
+               end
        end
 
        return true, nil
@@ -353,6 +359,10 @@ function UVL._read_scheme_parts( self, scheme, schemes )
                                                end
                                        end
                                end
+
+                               s.dynamic  = s.dynamic  or false
+                               s.unique   = s.unique   or false
+                               s.required = s.required or false
                        end
                end
        end
@@ -402,6 +412,7 @@ function UVL._read_scheme_parts( self, scheme, schemes )
                                end
 
                                t.type     = t.type     or "variable"
+                               t.datatype = t.datatype or "string"
                                t.required = t.required or false
                        end
                end
@@ -485,22 +496,24 @@ end
 
 -- Read a validator specification
 function UVL._read_validator( self, value, validators )
-       local validator
-
-       if value and value:match("/") and self.datatypes.file(value) then
-               validator = value
-       else
-               validator = self:_resolve_function( value )
-       end
+       if value then
+               local validator
 
-       if validator then
-               if not validators then
-                       validators = { validator }
-               else
-                       table.insert( validators, validator )
+               if value:match("^exec:") then
+                       validator = value:gsub("^exec:","")
+               elseif value:match("^lua:") then
+                       validator = self:_resolve_function( (value:gsub("^lua:","") ) )
                end
 
-               return validators
+               if validator then
+                       if not validators then
+                               validators = { validator }
+                       else
+                               table.insert( validators, validator )
+                       end
+
+                       return validators
+               end
        end
 end
 
index 217f2958899d53071607eee6b0ca8d0c97ad9244..ced275e6b38d94d364e6051a3b6e70799a8005ae 100644 (file)
@@ -16,15 +16,6 @@ $Id$
 
 module( "luci.uvl.dependencies", package.seeall )
 
-local function _assert( condition, fmt, ... )
-       if not condition then
-               return assert( nil, string.format( fmt, ... ) )
-       else
-               return condition
-       end
-end
-
-
 function _parse_reference( r, c, s, o )
        local ref  = { }
        local vars = {
index 9ec57f1320a8a6f6b05881d5cdaf13a36e973911..001664e13630f76fb080f81cb5c8cd15935dc34e 100644 (file)
@@ -30,6 +30,13 @@ function section_error( section, message )
        )
 end
 
+function validator_error( option, message )
+       return string.format(
+               'External validator in option "%s" failed:\n%s',
+                       option:cid(), message or "Unknown error"
+       )
+end
+
 function dump_dependency( dep, ref, v, e )
        local str = nil
 
@@ -46,7 +53,7 @@ function dump_dependency( dep, ref, v, e )
 
        str = string.format(
                '%s) failed:\n\t%s',
-               str, e or string.format(
+               str, e and e:gsub("\n","\n\t") or string.format(
                        'Option "%s" %s',
                        table.concat( ref, "." ), (
                                type(v) == "boolean"
diff --git a/libs/uvl/luasrc/uvl/validation.lua b/libs/uvl/luasrc/uvl/validation.lua
new file mode 100644 (file)
index 0000000..39f1527
--- /dev/null
@@ -0,0 +1,65 @@
+--[[
+
+UCI Validation Layer - Validation helper
+(c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+(c) 2008 Steven Barth <steven@midlink.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+]]--
+
+module( "luci.uvl.validation", package.seeall )
+
+require("luci.fs")
+require("luci.sys")
+
+
+function _exec( bin, args )
+       local cmd, output = "", nil
+
+       for _, v in ipairs({ bin, unpack(args) }) do
+               cmd = cmd .. string.format("%q ",v):gsub("([%$`])","\\%1")
+       end
+
+       local tmpfile = "/tmp/uvl" .. luci.sys.uniqueid(8)
+       local retval  = os.execute( cmd .. " 1>" .. tmpfile .. " 2>" .. tmpfile )
+
+       if luci.fs.access(tmpfile) then
+               output = luci.fs.readfile(tmpfile)
+               luci.fs.unlink(tmpfile)
+       end
+
+       return retval, output
+end
+
+function check( self, object )
+       local item = object:option()
+
+       if item.validators then
+               for _, val in ipairs(item.validators) do
+                       local ok, err = false, nil
+                       local args = {
+                               item.type, unpack(object.cref), item.datatype, object:value()
+                       }
+
+                       if type(val) == "function" then
+                               ok, err = val(unpack(args))
+                       else
+                               ok, err = _exec( val, args )
+                               ok = ( ok == 0 )
+                       end
+
+                       if not ok then
+                               return false, err
+                       end
+               end
+       end
+
+       return true, nil
+end