217f2958899d53071607eee6b0ca8d0c97ad9244
[project/luci.git] / libs / uvl / luasrc / uvl / dependencies.lua
1 --[[
2
3 UCI Validation Layer - Dependency helper
4 (c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
5 (c) 2008 Steven Barth <steven@midlink.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14
15 ]]--
16
17 module( "luci.uvl.dependencies", package.seeall )
18
19 local function _assert( condition, fmt, ... )
20 if not condition then
21 return assert( nil, string.format( fmt, ... ) )
22 else
23 return condition
24 end
25 end
26
27
28 function _parse_reference( r, c, s, o )
29 local ref = { }
30 local vars = {
31 config = c,
32 section = s,
33 option = o
34 }
35
36 for i, v in ipairs(luci.util.split(r,".")) do
37 table.insert( ref, (v:gsub( "%$(.+)", function(n) return vars[n] end )) )
38 end
39
40 if #ref == 1 and c and s then
41 ref = { c, s, ref[1] }
42 elseif #ref == 2 and c then
43 ref = { c, unpack(ref) }
44 elseif #ref ~= 3 then
45 ref = nil
46 end
47
48 return ref
49 end
50
51 function check( self, object, nodeps )
52
53 if not self.beenthere[object:cid()] then
54 self.beenthere[object:cid()] = true
55 else
56 return false, "Recursive dependency for '" .. object:sid() .. "' found"
57 end
58
59 local item = object.type == luci.uvl.TYPE_SECTION
60 and object:section() or object:option()
61
62 if item.depends then
63 local ok = false
64 local valid, err = false,
65 string.format( 'In dependency check for %s "%s":',
66 ( object.type == luci.uvl.TYPE_SECTION and "section" or "option" ),
67 object:cid() )
68
69 for _, dep in ipairs(item.depends) do
70 local subcondition = true
71 for k, v in pairs(dep) do
72 -- XXX: better error
73 local ref = _parse_reference( k, unpack(object.cref) )
74
75 if not ref then
76 return false, "Ambiguous dependency reference '" .. k ..
77 "' for object '" .. object:sid() .. "' given"
78 end
79
80 local option = luci.uvl.option(
81 self, object.config,
82 object.config[ref[2]]
83 and object.config[ref[2]]['.type']
84 or object.sref[2],
85 ref[1], ref[2], ref[3]
86 )
87
88 valid, err2 = self:_validate_option( option, true )
89 if valid then
90 if not (
91 ( type(v) == "boolean" and object.config[ref[2]][ref[3]] ) or
92 ( ref[3] and object.config[ref[2]][ref[3]] ) == v
93 ) then
94 subcondition = false
95 err = err .. "\n" ..
96 self.log.dump_dependency( dep, ref, v )
97 break
98 end
99 else
100 subcondition = false
101 err = err .. "\n" ..
102 self.log.dump_dependency( dep, ref, nil, err2 )
103 break
104 end
105 end
106
107 if subcondition then
108 return true
109 end
110 end
111
112 return false, err
113 end
114
115 return true
116 end