2ba5bfd2509cefa74cbc05110e66b46888356c98
[project/luci.git] / libs / lpk / luasrc / lpk / core.lua
1 module("luci.lpk.core", package.seeall)
2 require("luci.util")
3
4 Task = luci.util.class()
5
6 function Task.__init__(self, machine, register, start)
7         self.machine = machine
8
9         -- The queue that has to be processed
10         self.work = {start}
11         
12         -- The queue that has to be processed in case of rollback
13         self.done = {}
14         
15         -- The Task register
16         self.register = register
17 end
18
19 function Task.rollback(self)
20         if #self.done < 1 then
21                 return false
22         end
23         
24         local state = table.remove(self.done)
25         local ret, err = pcall(state.rollback, state, self.register)
26         
27         if ret then
28                 return true
29         else
30                 return false, err
31         end
32 end
33
34 function Task.step(self)
35         local state = table.remove(self.work)
36         local ret, next = pcall(state.process, state, self.register)
37         
38         if ret then
39                 if next then
40                         local nstate = self.machine:state(next)
41                         if nstate then
42                                 table.insert(self.work, state)
43                                 table.insert(self.work, nstate)
44                         else
45                                 self.register.error = "Unknown state: " .. next
46                                 return false
47                         end
48                 else
49                         table.insert(self.done, state)
50                 end
51                 
52                 return #self.work > 0 
53         else
54                 self.register.error = next
55                 return false
56         end
57 end
58
59 function Task.perform(self)
60         while self:step() do
61         end
62         
63         if not self.register.error then
64                 return true
65         else
66                 local stat, err
67                 repeat
68                         stat, err = self:rollback()
69                 until not stat
70                 
71                 assert(not err, "Machine broken!")
72                 
73                 return false, self.register.error
74         end     
75 end
76
77
78 Machine = luci.util.class()
79
80 function Machine.__init__(self, namespace)
81         self.namespace = namespace or _NAME
82 end
83
84 function Machine.state(self, name)
85         local ret, state = pcall(require, self.namespace .. "." .. name)
86         return ret and state
87 end
88
89 function Machine.task(self, name, ...)
90         local start = self:state(name)
91         
92         if not start or not start.entry then
93                 error("No such command: " .. name)
94         end
95         
96         local register = {}
97         
98         if start:entry(register) then
99                 return Task(self, register, start)
100         else
101                 return nil, register.error
102         end
103 end