* luci/libs: more UVL hacking, needs to be rewritten later
[project/luci.git] / libs / uvl / luasrc / uvl / dependencies.lua
diff --git a/libs/uvl/luasrc/uvl/dependencies.lua b/libs/uvl/luasrc/uvl/dependencies.lua
new file mode 100644 (file)
index 0000000..b8d7286
--- /dev/null
@@ -0,0 +1,130 @@
+--[[
+
+UCI Validation Layer - Main Library
+(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.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 = {
+               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 )) )
+       end
+
+       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
+               print("INVALID REFERENCE: "..#ref, c, s, o)
+               ref = nil
+       end
+
+       return ref
+end
+
+function check_dependency( self, uci, conf, sect, optn, nodeps, section2 )
+
+--     print( "Depency check:    ", conf .. '.' .. sect .. ( optn and '.' .. optn or '' ) )
+
+       local key = conf .. '.' .. sect .. ( optn and '.' .. optn or '' )
+       if not self.beenthere[key] then
+               self.beenthere[key] = true
+       else
+               print("CIRCULAR DEPENDENCY!")
+               return false, "Recursive depency detected"
+       end
+
+       -- check for config
+       if not self.packages[conf] then self:read_scheme(conf) end
+       local item = self.packages[conf]
+
+       -- check for section
+       if sect then
+               item = _assert( self:_scheme_section( uci, conf, sect ) or self:_scheme_section( uci, conf, section2 ),
+                       "Unknown section '%s' in scheme '%s' requested",
+                       sect or '<nil>', conf or '<nil>' )
+
+               -- check for option
+               if optn then
+                       item = _assert( self:_scheme_option( uci, conf, sect, optn ) or
+                                                       self:_scheme_option( uci, conf, section2, optn ),
+                               "Unknown variable '%s' in scheme '%s', section '%s' requested",
+                               optn or '<nil>', conf or '<nil>', sect or '<nil>' )
+               end
+       end
+
+       if item.depends then
+               local ok = false
+               local valid, err
+
+               for _, dep in ipairs(item.depends) do
+                       --print("DEP:",luci.util.serialize_data(dep))
+
+                       local subcondition = true
+
+                       for k, v in pairs(dep) do
+                               -- XXX: better error
+                               local ref = _assert( _parse_reference(k,conf,sect,optn),
+                                       "Ambiguous dependency reference '" .. k .. "' given" )
+
+                               -- XXX: true -> nodeps
+                               valid, err = self:validate_option(ref[1], ref[2], ref[3], uci, true, section2)
+                               if valid then
+                                       --print("CHK:",uci[ref[2]][ref[3]],v,unpack(ref))
+                                       if not (
+                                               ( type(v) == "boolean" and uci[ref[2]][ref[3]] ) or
+                                               ( ref[3] and uci[ref[2]][ref[3]] ) == v
+                                       ) then
+                                               subcondition = false
+                                               err = type(v) ~= "boolean"
+                                                       and "Option '" .. table.concat( ref, "." ) .. "' doesn't match requested type '" .. v .. '"'
+                                                       or  "Option '" .. table.concat( ref, "." ) .. "' has no value"
+
+                                               break
+                                       end
+                               else
+                                       subcondition = false
+                                       break
+                               end
+                       end
+
+                       if subcondition then
+--                             print( " -> Success (condition matched)\n" )
+                               return true
+                       end
+               end
+
+--             print( " -> Failed\n" )
+               return false, err
+       end
+
+--     print( " -> Success (no depends)\n" )
+       return true
+end