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