* luci/libs: uvl: implement dependencies for enum values
[project/luci.git] / libs / uvl / luasrc / uvl.lua
index 6f80f97..aaeb875 100644 (file)
@@ -325,7 +325,7 @@ function UVL._validate_section( self, section )
                                section:cid() .. '.' .. k
                        ] then
                                return false, 'Option "%s" not found in scheme'
-                                       % self.log.id( unpack(section:sid()), k )
+                                       % self.log.id( section:sid(), k )
                        end
                end
        end
@@ -347,12 +347,12 @@ function UVL._validate_option( self, option, nodeps )
                                % option:cid()
                end
 
-               if item.type == "enum" and val then
+               if ( item.type == "reference" or item.type == "enum" ) and val then
                        if not item.values or not item.values[val] then
                                return false,
-                                       'Value "%s" of given option "%s" is not defined in enum { %s }'
-                                               %{ val or '<nil>', option:cid(),
-                                                  table.concat( luci.util.keys(item.values), ", " ) }
+                                       'Value "%s" of given option "%s" is not defined in %s { %s }'
+                                               %{ val or '<nil>', option:cid(), item.type,
+                                                  table.concat( luci.util.keys(item.values or {}), ", " ) }
                        end
                elseif item.type == "list" and val then
                        if type(val) ~= "table" and STRICT_LIST_TYPE then
@@ -552,10 +552,20 @@ function UVL._read_scheme_parts( self, scheme, schemes )
                                                                'validator specification in "%s"',
                                                                v.name, scheme, k
                                                        )
+                                               elseif k == "valueof" then
+                                                       local values, err = self:_read_reference( v2 )
+
+                                                       _assert( values,
+                                                               'Variable "%s" in scheme "%s" has invalid ' ..
+                                                               'reference specification:\n%s',
+                                                                       v.name, scheme, err )
+
+                                                       t.type   = "reference"
+                                                       t.values = values
                                                elseif k == "required" then
                                                        t[k] = _bool(v2)
                                                else
-                                                       t[k] = v2
+                                                       t[k] = t[k] or v2
                                                end
                                        end
                                end
@@ -599,6 +609,10 @@ function UVL._read_scheme_parts( self, scheme, schemes )
                                        t.values[v.value] = v.title or v.value
                                end
 
+                               if not t.enum_depends then
+                                       t.enum_depends = { }
+                               end
+
                                if v.default then
                                        _assert( not t.default,
                                                'Enum "%s" in scheme "%s", section "%s" redeclares ' ..
@@ -607,6 +621,16 @@ function UVL._read_scheme_parts( self, scheme, schemes )
 
                                        t.default = v.value
                                end
+
+                               if v.depends then
+                                       t.enum_depends[v.value] = _assert(
+                                               self:_read_dependency(
+                                                       v.depends, t.enum_depends[v.value]
+                                               ),
+                                               'Invalid reference "%s" in "%s.%s.%s.%s"',
+                                               v.depends, scheme, r[2], r[3], v.value
+                                       )
+                               end
                        end
                end
        end
@@ -675,6 +699,44 @@ function UVL._read_validator( self, values, validators )
        end
 end
 
+-- Read a reference specification (XXX: We should validate external configs too...)
+function UVL._read_reference( self, values )
+       local val = { }
+       values = ( type(values) == "table" and values or { values } )
+
+       for _, value in ipairs(values) do
+               local ref = luci.util.split(value, ".")
+
+               if #ref == 2 or #ref == 3 then
+                       self.uci.load_config(ref[1])
+                       local co = self.uci.get_all(ref[1])
+
+                       if not co then
+                               return nil, 'Can not load config "%s" for reference "%s"'
+                                       %{ ref[1], value }
+                       end
+
+                       for k, v in pairs(co) do
+                               if v['.type'] == ref[2] then
+                                       if #ref == 2 then
+                                               if v['.anonymous'] == true then
+                                                       return nil, 'Illegal reference "%s" to an anonymous section'
+                                                               % value
+                                               end
+                                               val[k] = k      -- XXX: title/description would be nice
+                                       elseif v[ref[3]] then
+                                               val[v[ref[3]]] = v[ref[3]]  -- XXX: dito
+                                       end
+                               end
+                       end
+               else
+                       return nil, 'Malformed reference "%s"' % value
+               end
+       end
+
+       return val, nil
+end
+
 -- Resolve given path
 function UVL._resolve_function( self, value )
        local path = luci.util.split(value, ".")