UGLY workaround is UGLY
[project/luci.git] / libs / uci / luasrc / model / uci.lua
1 --[[
2 LuCI - UCI model
3
4 Description:
5 Generalized UCI model
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24
25 ]]--
26 local os = require "os"
27 local uci = require "uci"
28 local util = require "luci.util"
29 local table = require "table"
30
31
32 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
33 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
34 local require, getmetatable = require, getmetatable
35
36 --- LuCI UCI model library.
37 -- @cstyle instance
38 module "luci.model.uci"
39
40 --- Create a new UCI-Cursor.
41 -- @class function
42 -- @name cursor
43 -- @return UCI-Cursor
44 cursor = uci.cursor
45
46 APIVERSION = uci.APIVERSION
47
48 --- Create a new Cursor initialized to the state directory.
49 -- @return UCI cursor
50 function cursor_state()
51 return cursor(nil, "/var/state")
52 end
53
54
55 local Cursor = getmetatable(cursor())
56
57 --- Applies the new config
58 -- @param config UCI config
59 function Cursor.apply(self, config)
60 local conf = require "luci.config"
61 return conf.uci_oncommit[config] and
62 os.execute(conf.uci_oncommit[config] .. " >/dev/null 2>&1")
63 end
64
65 --- Delete all sections of a given type that match certain criteria.
66 -- @param config UCI config
67 -- @param type UCI section type
68 -- @param comparator Function that will be called for each section and
69 -- returns a boolean whether to delete the current section (optional)
70 function Cursor.delete_all(self, config, type, comparator)
71 local del = {}
72 local function helper (section)
73 if not comparator or comparator(section) then
74 table.insert(del, section[".name"])
75 end
76 end
77
78 self:foreach(config, type, helper)
79
80 for i, j in ipairs(del) do
81 self:delete(config, j)
82 end
83 end
84
85 --- Create a new section and initialize it with data.
86 -- @param config UCI config
87 -- @param type UCI section type
88 -- @param name UCI section name (optional)
89 -- @param values Table of key - value pairs to initialize the section with
90 -- @return Name of created section
91 function Cursor.section(self, config, type, name, values)
92 local stat = true
93 if name then
94 stat = self:set(config, name, type)
95 else
96 name = self:add(config, type)
97 stat = name and true
98 end
99
100 if stat and values then
101 stat = self:tset(config, name, values)
102 end
103
104 return stat and name
105 end
106
107 --- Updated the data of a section using data from a table.
108 -- @param config UCI config
109 -- @param section UCI section name (optional)
110 -- @param values Table of key - value pairs to update the section with
111 function Cursor.tset(self, config, section, values)
112 local stat = true
113 for k, v in pairs(values) do
114 if k:sub(1, 1) ~= "." then
115 stat = stat and self:set(config, section, k, v)
116 end
117 end
118 return stat
119 end
120
121 --- Get an option or list and return values as table.
122 -- @param config UCI config
123 -- @param section UCI section name
124 -- @param option UCI option
125 -- @return UCI value
126 function Cursor.get_list(self, config, section, option)
127 if config and section and option then
128 local val = self:get(config, section, option)
129 return ( type(val) == "table" and val or { val } )
130 end
131 return nil
132 end
133
134 --- Set given values as list.
135 -- @param config UCI config
136 -- @param section UCI section name
137 -- @param option UCI option
138 -- @param value UCI value
139 -- @return Boolean whether operation succeeded
140 function Cursor.set_list(self, config, section, option, value)
141 if config and section and option then
142 return self:set(
143 config, section, option,
144 ( type(value) == "table" and value or { value } )
145 )
146 end
147 return false
148 end
149
150
151 Cursor._changes = Cursor.changes
152 function Cursor.changes(self, config)
153 if config then
154 return Cursor._changes(self, config)
155 else
156 local changes = {}
157 for k,v in pairs(require "luci.fs".dir(self:get_savedir())) do
158 if v ~= "." and v ~= ".." then
159 util.update(changes, Cursor._changes(self, v))
160 end
161 end
162 return changes
163 end
164 end
165
166
167 --- Add an anonymous section.
168 -- @class function
169 -- @name Cursor.add
170 -- @param config UCI config
171 -- @param type UCI section type
172 -- @return Name of created section
173
174 --- Get a table of unsaved changes.
175 -- @class function
176 -- @name Cursor.changes
177 -- @param config UCI config
178 -- @return Table of changes
179
180 --- Commit unsaved changes.
181 -- @class function
182 -- @name Cursor.commit
183 -- @param config UCI config
184 -- @return Boolean whether operation succeeded
185 -- @see Cursor.revert
186
187 --- Deletes a section or an option.
188 -- @class function
189 -- @name Cursor.delete
190 -- @param config UCI config
191 -- @param section UCI section name
192 -- @param option UCI option (optional)
193 -- @return Boolean whether operation succeeded
194
195 --- Call a function for every section of a certain type.
196 -- @class function
197 -- @name Cursor.foreach
198 -- @param config UCI config
199 -- @param type UCI section type
200 -- @param callback Function to be called
201 -- @return Boolean whether operation succeeded
202
203 --- Get a section type or an option
204 -- @class function
205 -- @name Cursor.get
206 -- @param config UCI config
207 -- @param section UCI section name
208 -- @param option UCI option (optional)
209 -- @return UCI value
210
211 --- Get all sections of a config or all values of a section.
212 -- @class function
213 -- @name Cursor.get_all
214 -- @param config UCI config
215 -- @param section UCI section name (optional)
216 -- @return Table of UCI sections or table of UCI values
217
218 --- Manually load a config.
219 -- @class function
220 -- @name Cursor.load
221 -- @param config UCI config
222 -- @return Boolean whether operation succeeded
223 -- @see Cursor.save
224 -- @see Cursor.unload
225
226 --- Revert unsaved changes.
227 -- @class function
228 -- @name Cursor.revert
229 -- @param config UCI config
230 -- @return Boolean whether operation succeeded
231 -- @see Cursor.commit
232
233 --- Saves changes made to a config to make them committable.
234 -- @class function
235 -- @name Cursor.save
236 -- @param config UCI config
237 -- @return Boolean whether operation succeeded
238 -- @see Cursor.load
239 -- @see Cursor.unload
240
241 --- Set a value or create a named section.
242 -- @class function
243 -- @name Cursor.set
244 -- @param config UCI config
245 -- @param section UCI section name
246 -- @param option UCI option or UCI section type
247 -- @param value UCI value or nil if you want to create a section
248 -- @return Boolean whether operation succeeded
249
250 --- Get the configuration directory.
251 -- @class function
252 -- @name Cursor.get_confdir
253 -- @return Configuration directory
254
255 --- Get the directory for uncomitted changes.
256 -- @class function
257 -- @name Cursor.get_savedir
258 -- @return Save directory
259
260 --- Set the configuration directory.
261 -- @class function
262 -- @name Cursor.set_confdir
263 -- @param directory UCI configuration directory
264 -- @return Boolean whether operation succeeded
265
266 --- Set the directory for uncommited changes.
267 -- @class function
268 -- @name Cursor.set_savedir
269 -- @param directory UCI changes directory
270 -- @return Boolean whether operation succeeded
271
272 --- Discard changes made to a config.
273 -- @class function
274 -- @name Cursor.unload
275 -- @param config UCI config
276 -- @return Boolean whether operation succeeded
277 -- @see Cursor.load
278 -- @see Cursor.save