ced275e6b38d94d364e6051a3b6e70799a8005ae
[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 function _parse_reference( r, c, s, o )
20         local ref  = { }
21         local vars = {
22                 config  = c,
23                 section = s,
24                 option  = o
25         }
26
27         for i, v in ipairs(luci.util.split(r,".")) do
28                 table.insert( ref, (v:gsub( "%$(.+)", function(n) return vars[n] end )) )
29         end
30
31         if #ref == 1 and c and s then
32                 ref = { c, s, ref[1] }
33         elseif #ref == 2 and c then
34                 ref = { c, unpack(ref) }
35         elseif #ref ~= 3 then
36                 ref = nil
37         end
38
39         return ref
40 end
41
42 function check( self, object, nodeps )
43
44         if not self.beenthere[object:cid()] then
45                 self.beenthere[object:cid()] = true
46         else
47                 return false, "Recursive dependency for '" .. object:sid() .. "' found"
48         end
49
50         local item = object.type == luci.uvl.TYPE_SECTION
51                 and object:section() or object:option()
52
53         if item.depends then
54                 local ok = false
55                 local valid, err = false,
56                         string.format( 'In dependency check for %s "%s":',
57                                 ( object.type == luci.uvl.TYPE_SECTION and "section" or "option" ),
58                                 object:cid() )
59
60                 for _, dep in ipairs(item.depends) do
61                         local subcondition = true
62                         for k, v in pairs(dep) do
63                                 -- XXX: better error
64                                 local ref = _parse_reference( k, unpack(object.cref) )
65
66                                 if not ref then
67                                         return false, "Ambiguous dependency reference '" .. k ..
68                                                 "' for object '" .. object:sid() .. "' given"
69                                 end
70
71                                 local option = luci.uvl.option(
72                                         self, object.config,
73                                         object.config[ref[2]]
74                                                 and object.config[ref[2]]['.type']
75                                                 or  object.sref[2],
76                                         ref[1], ref[2], ref[3]
77                                 )
78
79                                 valid, err2 = self:_validate_option( option, true )
80                                 if valid then
81                                         if not (
82                                                 ( type(v) == "boolean" and object.config[ref[2]][ref[3]] ) or
83                                                 ( ref[3] and object.config[ref[2]][ref[3]] ) == v
84                                         ) then
85                                                 subcondition = false
86                                                 err = err .. "\n" ..
87                                                         self.log.dump_dependency( dep, ref, v )
88                                                 break
89                                         end
90                                 else
91                                         subcondition = false
92                                         err = err .. "\n" ..
93                                                 self.log.dump_dependency( dep, ref, nil, err2 )
94                                         break
95                                 end
96                         end
97
98                         if subcondition then
99                                 return true
100                         end
101                 end
102
103                 return false, err
104         end
105
106         return true
107 end