comparison DependencyLoader_Core/Tree.lua @ 8:930871e163bc

created a new Tree class and started rearranging code
author mckenziemc
date Sat, 04 Dec 2010 23:05:34 -0800
parents
children
comparison
equal deleted inserted replaced
7:f4ab9d7b97b0 8:930871e163bc
1 -- Tree
2 -- Represents a recursive "tree" of addon
3 -- dependencies rooted at a specific addon.
4
5
6 local addonName, addonTable = ...
7
8
9 -- TODO: prevent infinite loops in the recursive functions
10
11
12 local Tree, tree = addonTable:NewClass("Tree")
13
14
15 Tree.trees = {}
16
17 -- internal
18 -- Creates a new tree object
19 -- @param root Name, index, or Addon object of the root addon.
20 function Tree:New(root)
21 if type(root) ~= "table" then
22 root = addonTable.classes.Addon:Get(root)
23 end
24
25 local instance = {}
26 setmetatable(instance, self.instanceMetatable)
27
28 instance.root = root
29
30 return instance
31 end
32
33
34 --- Retrieves the tree rooted at the specified addon
35 -- @param root Name, index, or Addon object of the root.
36 function Tree:Get(root)
37 if type(root) ~= "table" then
38 root = addonTable.classes.Addon:Get(root)
39 end
40
41 local tree = self.trees[root]
42
43 if tree then
44 return tree
45 else
46 tree = self:New(root)
47 self.trees[root] = tree
48 return tree
49 end
50 end
51
52
53 function tree:GetLoadBitfield()
54 local bitfield = self.root:GetLoadBitfield()
55
56 local dependencies = {self.root:GetDependencies()}
57 for i, depName in pairs(dependencies) do
58 local depTree = Tree:Get(depName)
59
60 if depTree == nil then
61 return 0
62 end
63
64 bitfield = bit.band(bitfield, depTree:GetLoadBitfield())
65 end
66
67 return bitfield
68 end
69
70
71 -- Checks if the tree rooted at the specified addon can be force-loaded.
72 -- @param root The name or index of the root addon.
73 function core:CanForceLoadTree(root)
74 -- TODO: if some addons have already loaded, we have to check
75 -- forceafter for those and forcebefore for the others
76 return false
77 end
78
79
80 -- NOTE: any tree that can be loaded on demand is also eligible for force-loading
81 -- Checks if the tree rooted at the specified addon can be loaded on demand.
82 -- @param root The name or index of the root addon.
83 function core:CanLoDTree(root)
84 local bitfield = self:GetLoadBitfield()
85 root = self:GetAddon(root)
86 assert(root)
87
88 -- since this will be used recursively, return true if
89 -- this is already loaded.
90 if root:IsLoaded() then
91 return true
92 end
93
94 -- true if all dependencies are loaded or LoD
95
96 if not root:CanLoD() then
97 return false
98 end
99
100 -- now check dependencies recursively
101 local dependencies = {root:GetDependencies()}
102 for i, depName in pairs(dependencies) do
103 local dep = self:GetAddon(depName)
104
105 if not dep then
106 return false -- missing
107 end
108
109 if not dep:IsLoaded() then
110 if not self:CanLoDTree(depName) then
111 return false
112 end
113 end
114 end
115
116 return true
117 end
118
119
120 -- Checks if the tree rooted at the specified addon
121 -- can be loaded if all dependencies are enabled
122 -- the UI is reloaded.
123 -- Basically makes sure all dependencies are installed.
124 function core:CanReloadTree(root)
125 -- convert root to an Addon object
126 root = self:GetAddon(root)
127 assert(root)
128
129 if root:IsLoaded() then
130 return true
131 -- FIXME: deps may have been disabled
132 end
133
134 -- TODO: make sure the root isn't incompatible
135
136 -- now check dependencies recursively
137 -- FIXME: prevent infinite recursion
138
139 local dependencies = {root:GetDependencies()}
140 for i, depName in pairs(dependencies) do
141 local dep = self:GetAddon(depName)
142
143 if dep == nil then
144 return false -- missing dependency
145 end
146
147 -- TODO: make sure it's compatible
148 end
149
150 return true
151 end
152
153 -- Loads the tree rooted at the specified addon.
154 -- FIXME: load the root too or not?
155 -- Supports both LoD addons and those that require force-loading.
156 function core:LoadTree(addon)
157 -- don't check if the tree can actually be loaded.
158 -- external code should do that itself to check if it
159 -- should even call this at all.
160
161 if self:ForceLoadAvailable() then
162 -- LoD trees can also be force-loaded
163 self:ForceLoadTree(addon)
164 else
165 self:LoadLoDTree(addon)
166 end
167 end
168
169
170 -- load the root too, since it may actually be a leaf
171 function core:ForceLoadTree(root)
172 root = self:GetAddon(root)
173 assert(root)
174
175 -- load dependencies
176 local dependencies = {root:GetDependencies(addon)}
177 for i, depName in pairs(dependencies) do
178 self:ForceLoadTree(depName)
179 end
180
181 -- load embeds, if they are available separately
182 local embeds = {root:GetEmbeds(addon)}
183 for i, embedName in pairs(embeds) do
184 if Addon:Exists(embedName) then
185 self:ForceLoadTree(embedName)
186 end
187 end
188
189 root:ForceLoad()
190 end
191
192
193 function core:LoadLoDTree(root)
194 root = self:GetAddon(root)
195 assert(root)
196
197 -- load dependencies
198 local dependencies = {root:GetDependencies(addon)}
199 for i, depName in pairs(dependencies) do
200 self:LoadLoDTree(depName)
201 end
202
203 -- load embeds, if they are available separately
204 local embeds = {root:GetEmbeds(addon)}
205 for i, embedName in pairs(embeds) do
206 if Addon:Exists(embedName) then
207 self:LoadLoDTree(embedName)
208 end
209 end
210
211 root:LoD()
212 end
213
214
215 -- I think the problem this solves is a major issue with
216 -- migrating to separate libs. think about it more and document
217 -- here and in project description
218 function core:PrepareLoDTree(root)
219 root = self:GetAddon(root)
220 assert(root)
221
222 -- assume root is LoD
223
224 -- check dependencies
225 local dependencies = {root:GetDependencies(addon)}
226 for i, depName in pairs(dependencies) do
227 local dep = self:GetAddon(depName)
228
229 -- assume external code made sure it exists
230
231 if dep:CanLoD() then
232 -- don't load it now but make sure its dependencies are prepared
233 self:PrepareLoDTree(depName)
234 else
235 -- FIXME: if it's already loaded
236 -- force-load it now so we can load the parent on demand
237 self:ForceLoadTree(depName)
238 end
239 end
240
241 -- prepare embeds, if they are available separately
242 local embeds = {root:GetEmbeds(addon)} -- FIXME: addon?
243 for i, embedName in pairs(embeds) do
244 local embed = self:GetAddon(embedName)
245
246 if embed then
247 if embed:CanLoD() then
248 -- don't load it now but make sure its dependencies are prepared
249 self:PrepareLoDTree(embedName)
250 else
251 -- FIXME: if it's already loaded
252 -- force-load it now so we can load the parent on demand
253 self:ForceLoadTree(depName)
254 end
255 end
256 end
257 end
258
259
260 function Core:PrepareReloadTree(addon)
261 root = self:GetAddon(root)
262 assert(root)
263
264 root:Enable()
265
266 -- check dependencies
267 local dependencies = {root:GetDependencies()}
268 for i, depName in pairs(dependencies) do
269 self:PrepareReloadTree(depName)
270 end
271
272 -- prepare embeds, if they are available separately
273 local embeds = {root:GetEmbeds(addon)}
274 for i, embedName in pairs(embeds) do
275 local embed = self:GetAddon(embedName)
276
277 if embed then
278 self:PrepareReloadTree(embedName)
279 end
280 end
281 end
282
283
284 function Core:ForceLoadAvailable()
285 return true
286 -- FIXME: use field and a frame registered for PLAYER_LOGIN
287 end