X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fuvl%2Fluasrc%2Fuvl%2Fdependencies.lua;h=d19149e7ab2a9a0f80a4e18cf0ce444c66f768d4;hp=fc407a985912a1302db967bb0d414e7497681e74;hb=2d409a35862a735327f8fb5de56d891d81ceee94;hpb=23101e71374383bdd1bae09166c2581daaa44b22 diff --git a/libs/uvl/luasrc/uvl/dependencies.lua b/libs/uvl/luasrc/uvl/dependencies.lua index fc407a985..d19149e7a 100644 --- a/libs/uvl/luasrc/uvl/dependencies.lua +++ b/libs/uvl/luasrc/uvl/dependencies.lua @@ -14,103 +14,182 @@ $Id$ ]]-- -module( "luci.uvl.dependencies", package.seeall ) +local uvl = require "luci.uvl" +local ERR = require "luci.uvl.errors" +local util = require "luci.util" +local table = require "table" + +local type, unpack = type, unpack +local ipairs, pairs = ipairs, pairs + +module "luci.uvl.dependencies" + + function _parse_reference( r, c, s, o ) local ref = { } local vars = { - config = ( c or '$config' ), - section = ( s or '$section' ), - option = ( o or '$option' ) + config = c, + section = s, + option = o } - for i, v in ipairs(luci.util.split(r,".")) do - table.insert(ref, (v:gsub( "%$(.+)", function(n) return vars[n] end ))) + for v in r:gmatch("[^.]+") do + ref[#ref+1] = (v:gsub( "%$(.+)", vars )) + end + + if #ref < 2 then + table.insert(ref, 1, s or '$section') + end + if #ref < 3 then + table.insert(ref, 1, c or '$config') end - if c or s then - if #ref == 1 and c and s then - ref = { c, s, ref[1] } - elseif #ref == 2 and c then - ref = { c, unpack(ref) } - elseif #ref ~= 3 then - ref = nil - end - else - if #ref == 1 then - ref = { '$config', '$section', ref[1] } - elseif #ref == 2 then - ref = { '$config', unpack(ref) } - elseif #ref ~= 3 then - ref = nil + return ref +end + +function _serialize_dependency( dep, v ) + local str + + for k, v in util.spairs( dep, + function(a,b) + a = ( type(dep[a]) ~= "boolean" and "_" or "" ) .. a + b = ( type(dep[b]) ~= "boolean" and "_" or "" ) .. b + return a < b end + ) do + str = ( str and str .. " and " or "" ) .. k .. + ( type(v) ~= "boolean" and "=" .. v or "" ) end - return ref + return str end function check( self, object, nodeps ) - if not self.beenthere[object:cid()] then - self.beenthere[object:cid()] = true + local derr = ERR.DEPENDENCY(object) + + if not self.depseen[object:cid()] then + self.depseen[object:cid()] = true else - return false, "Recursive dependency for '" .. object:sid() .. "' found" + return false, derr:child(ERR.DEP_RECURSIVE(object)) end - local item = object.type == luci.uvl.TYPE_SECTION - and object:section() or object:option() + if object:scheme('depends') then + local ok = true + local valid = false + + for _, dep in ipairs(object:scheme('depends')) do + local subcondition = true + for k, v in pairs(dep) do + -- XXX: better error + local ref = _parse_reference( k, unpack(object.cref) ) + + if not ref then + return false, derr:child(ERR.SME_BADDEP(object,k)) + end + + local option = uvl.option( self, object.c, unpack(ref) ) + + valid, err = self:_validate_option( option, true ) + if valid then + if not ( + ( type(v) == "boolean" and option:value() ) or + ( ref[3] and option:value() ) == v + ) then + subcondition = false + + local depstr = _serialize_dependency( dep, v ) + derr:child( + type(v) == "boolean" + and ERR.DEP_NOVALUE(option, depstr) + or ERR.DEP_NOTEQUAL(option, {depstr, v}) + ) + + break + end + else + subcondition = false + + local depstr = _serialize_dependency( dep, v ) + derr:child(ERR.DEP_NOTVALID(option, depstr):child(err)) + + break + end + end + + if subcondition then + ok = true + break + else + ok = false + end + end - if item.depends then - local ok = false - local valid, err = false, - string.format( 'In dependency check for %s "%s":', - ( object.type == luci.uvl.TYPE_SECTION and "section" or "option" ), - object:cid() ) + if not ok then + return false, derr + end + else + return true + end - for _, dep in ipairs(item.depends) do + if object:scheme("type") == "enum" and + object:scheme("enum_depends")[object:value()] + then + local ok = true + local valid = false + local enum = object:enum() + local eerr = ERR.DEP_BADENUM(enum) + + for _, dep in ipairs(enum:scheme('enum_depends')[object:value()]) do local subcondition = true for k, v in pairs(dep) do -- XXX: better error local ref = _parse_reference( k, unpack(object.cref) ) if not ref then - return false, "Ambiguous dependency reference '" .. k .. - "' for object '" .. object:sid() .. "' given" + return false, derr:child(eerr:child(ERR.SME_BADDEP(enum,k))) end - local option = luci.uvl.option( - self, object.config, - object.config[ref[2]] - and object.config[ref[2]]['.type'] - or object.sref[2], - ref[1], ref[2], ref[3] - ) + local option = luci.uvl.option( self, object.c, unpack(ref) ) - valid, err2 = self:_validate_option( option, true ) + valid, err = self:_validate_option( option, true ) if valid then if not ( ( type(v) == "boolean" and object.config[ref[2]][ref[3]] ) or - ( ref[3] and object.config[ref[2]][ref[3]] ) == v + ( ref[3] and object:config() ) == v ) then subcondition = false - err = err .. "\n" .. - self.log.dump_dependency( dep, ref, v ) + + local depstr = _serialize_dependency( dep, v ) + eerr:child( + type(v) == "boolean" + and ERR.DEP_NOVALUE(option, depstr) + or ERR.DEP_NOTEQUAL(option, {depstr, v}) + ) + break end else subcondition = false - err = err .. "\n" .. - self.log.dump_dependency( dep, ref, nil, err2 ) + + local depstr = _serialize_dependency( dep, v ) + eerr:child(ERR.DEP_NOTVALID(option, depstr):child(err)) + break end end if subcondition then return true + else + ok = false end end - return false, err + if not ok then + return false, derr:child(eerr) + end end return true