annotate DependencyLoader/Tree.lua @ 18:e7995d599184 tip

updated pkgmeta fix the inversion in addon:Enable added support for late-loading
author mckenziemc
date Tue, 21 Dec 2010 00:23:57 -0800
parents a46bf694050c
children
rev   line source
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@18 15 local debug = addonTable.debug
mckenziemc@15 16 local classes = addonTable.classes
mckenziemc@15 17
mckenziemc@15 18
mckenziemc@8 19 Tree.trees = {}
mckenziemc@8 20
mckenziemc@10 21
mckenziemc@15 22 --- (private) Creates a new tree object.
mckenziemc@15 23 -- Assumptions: root addon exists and is not a Blizzard addon.
mckenziemc@8 24 -- @param root Name, index, or Addon object of the root addon.
mckenziemc@8 25 function Tree:New(root)
mckenziemc@8 26 if type(root) ~= "table" then
mckenziemc@15 27 root = classes.Addon:Get(root)
mckenziemc@8 28 end
mckenziemc@8 29
mckenziemc@8 30 local instance = {}
mckenziemc@8 31 setmetatable(instance, self.instanceMetatable)
mckenziemc@8 32
mckenziemc@8 33 instance.root = root
mckenziemc@8 34
mckenziemc@8 35 return instance
mckenziemc@8 36 end
mckenziemc@8 37
mckenziemc@8 38
mckenziemc@8 39 --- Retrieves the tree rooted at the specified addon
mckenziemc@15 40 -- Assumptions: root addon exists and is not a Blizzard addon
mckenziemc@8 41 -- @param root Name, index, or Addon object of the root.
mckenziemc@8 42 function Tree:Get(root)
mckenziemc@8 43 if type(root) ~= "table" then
mckenziemc@15 44 root = classes.Addon:Get(root)
mckenziemc@8 45 end
mckenziemc@8 46
mckenziemc@8 47 local tree = self.trees[root]
mckenziemc@8 48
mckenziemc@8 49 if tree then
mckenziemc@8 50 return tree
mckenziemc@8 51 else
mckenziemc@8 52 tree = self:New(root)
mckenziemc@8 53 self.trees[root] = tree
mckenziemc@8 54 return tree
mckenziemc@8 55 end
mckenziemc@8 56 end
mckenziemc@8 57
mckenziemc@8 58
mckenziemc@15 59 -- NOTE: All tree:Can functions should check the root too.
mckenziemc@15 60 -- That way, the hooks don't have to do "if addon:Can_ and tree:Can_",
mckenziemc@15 61 -- plus the tree can cache info that includes the capabilities of the
mckenziemc@15 62 -- root addon.
mckenziemc@15 63
mckenziemc@15 64
mckenziemc@15 65 --- Checks if the tree rooted at the specified addon
mckenziemc@12 66 -- can be loaded if all dependencies are enabled
mckenziemc@12 67 -- and the UI is reloaded.
mckenziemc@12 68 -- Basically makes sure all dependencies are installed.
mckenziemc@12 69 function tree:CanLoad()
mckenziemc@15 70 local root = self.root
mckenziemc@15 71
mckenziemc@18 72 --debug("Checking if the tree rooted at", root:GetName(), "can be loaded.")
mckenziemc@18 73
mckenziemc@15 74 if root:IsLoaded() then
mckenziemc@15 75 return true
mckenziemc@15 76 end
mckenziemc@15 77
mckenziemc@15 78 if not root:CanLoad() then
mckenziemc@12 79 return false
mckenziemc@12 80 end
mckenziemc@12 81
mckenziemc@12 82 -- check all the dependencies
mckenziemc@15 83 local dependencies = {root:GetDependencies()}
mckenziemc@15 84
mckenziemc@8 85 for i, depName in pairs(dependencies) do
mckenziemc@15 86 if not classes.Addon:Exists(depName) then
mckenziemc@12 87 return false
mckenziemc@12 88 end
mckenziemc@12 89
mckenziemc@15 90 local dep = classes.Addon:Get(depName)
mckenziemc@15 91 local depTree = Tree:Get(dep)
mckenziemc@8 92
mckenziemc@12 93 if not depTree:CanLoad() then
mckenziemc@15 94 return false
mckenziemc@10 95 end
mckenziemc@10 96 end
mckenziemc@10 97
mckenziemc@18 98 --debug("The tree rooted at", root:GetName(), "can be loaded")
mckenziemc@12 99 return true
mckenziemc@8 100 end
mckenziemc@8 101
mckenziemc@8 102
mckenziemc@12 103 --- Checks if the tree can be loaded on demand.
mckenziemc@15 104 -- Does not allow for force-loading; dependencies must
mckenziemc@15 105 -- already be loaded, or enabled and LoD.
mckenziemc@10 106 function tree:CanLoD()
mckenziemc@15 107 local root = self.root
mckenziemc@15 108
mckenziemc@15 109 if root:IsLoaded() then
mckenziemc@8 110 return true
mckenziemc@8 111 end
mckenziemc@8 112
mckenziemc@15 113 if not root:CanLoD() then
mckenziemc@8 114 return false
mckenziemc@8 115 end
mckenziemc@8 116
mckenziemc@8 117 -- now check dependencies recursively
mckenziemc@15 118 local dependencies = {root:GetDependencies()}
mckenziemc@15 119
mckenziemc@8 120 for i, depName in pairs(dependencies) do
mckenziemc@15 121 if not classes.Addon:Exists(depName) then
mckenziemc@15 122 return false
mckenziemc@15 123 end
mckenziemc@15 124
mckenziemc@15 125 local dep = classes.Addon:Get(depName)
mckenziemc@15 126 local depTree = Tree:Get(dep)
mckenziemc@8 127
mckenziemc@10 128 if not depTree:CanLoD() then
mckenziemc@10 129 return false
mckenziemc@8 130 end
mckenziemc@8 131 end
mckenziemc@8 132
mckenziemc@8 133 return true
mckenziemc@8 134 end
mckenziemc@8 135
mckenziemc@8 136
mckenziemc@18 137 -- Checks if this tree can load late (LoadAddOn with non-LoD)
mckenziemc@18 138 function tree:CanLoadLate()
mckenziemc@18 139 local root = self.root
mckenziemc@18 140
mckenziemc@18 141 if not root:CanLoadLate() then
mckenziemc@18 142 return false
mckenziemc@18 143 end
mckenziemc@18 144
mckenziemc@18 145 local dependencies = {root:GetDependencies()}
mckenziemc@18 146
mckenziemc@18 147 for i, depName in pairs(dependencies) do
mckenziemc@18 148 if not classes.Addon:Exists(depName) then
mckenziemc@18 149 return false
mckenziemc@18 150 end
mckenziemc@18 151
mckenziemc@18 152 local dep = classes.Addon:Get(depName)
mckenziemc@18 153 local depTree = Tree:Get(dep)
mckenziemc@18 154
mckenziemc@18 155 if not depTree:CanLoadLate() then
mckenziemc@18 156 return false
mckenziemc@18 157 end
mckenziemc@18 158 end
mckenziemc@18 159
mckenziemc@18 160 return true
mckenziemc@18 161 end
mckenziemc@18 162
mckenziemc@18 163
mckenziemc@15 164 --- Checks if this tree can be force-loaded.
mckenziemc@15 165 -- Does not check user settings nor if force-loading is actually available.
mckenziemc@15 166 -- @return canForceLoad True if this tree can be force loaded, false otherwise
mckenziemc@15 167 function tree:CanForceLoad()
mckenziemc@15 168 local root = self.root
mckenziemc@15 169 -- TODO: remove redundencies (for now they're here for design flexibility)
mckenziemc@15 170
mckenziemc@15 171 -- this addon must be loaded, able to load-on-demand, or able to force-load
mckenziemc@15 172 if root:IsLoaded() then
mckenziemc@15 173 return true
mckenziemc@15 174 end
mckenziemc@15 175
mckenziemc@15 176 if not root:CanForceLoad() then
mckenziemc@12 177 return false
mckenziemc@8 178 end
mckenziemc@8 179
mckenziemc@8 180 -- now check dependencies recursively
mckenziemc@15 181 local dependencies = {root:GetDependencies()}
mckenziemc@15 182
mckenziemc@8 183 for i, depName in pairs(dependencies) do
mckenziemc@15 184 if not classes.Addon:Exists(depName) then
mckenziemc@12 185 return false
mckenziemc@8 186 end
mckenziemc@12 187
mckenziemc@15 188 local dep = classes.Addon:Get(depName)
mckenziemc@15 189 local depTree = Tree:Get(dep)
mckenziemc@15 190
mckenziemc@15 191 if not depTree:CanForceLoad() then
mckenziemc@15 192 return false
mckenziemc@12 193 end
mckenziemc@8 194 end
mckenziemc@8 195
mckenziemc@8 196 return true
mckenziemc@8 197 end
mckenziemc@8 198
mckenziemc@12 199
mckenziemc@15 200 --- Prepares this tree to be loaded, whether through
mckenziemc@15 201 -- a ui reload or by loading on demand.
mckenziemc@15 202 -- Assumptions: CanLoad is true for this tree
mckenziemc@15 203 function tree:PrepareForLoad()
mckenziemc@15 204 local root = self.root
mckenziemc@15 205
mckenziemc@18 206 --debug("Preparing the tree rooted at", root:GetName(), "for loading")
mckenziemc@18 207
mckenziemc@15 208 -- The Addon class will take care of delaying enables
mckenziemc@15 209 -- till after PLAYER_LOGIN if necessary.
mckenziemc@15 210
mckenziemc@15 211 root:Enable()
mckenziemc@15 212
mckenziemc@15 213 -- enable dependencies
mckenziemc@15 214 local dependencies = {root:GetDependencies()}
mckenziemc@15 215
mckenziemc@15 216 for i, depName in pairs(dependencies) do
mckenziemc@15 217 Tree:Get(depName):PrepareForLoad()
mckenziemc@15 218 end
mckenziemc@12 219
mckenziemc@15 220 -- prepare embeds, if they are available separately
mckenziemc@15 221 local embeds = {root:GetEmbeds(addon)}
mckenziemc@12 222
mckenziemc@15 223 for i, embedName in pairs(embeds) do
mckenziemc@15 224 if classes.Addon:Exists(embedName) then
mckenziemc@15 225 Tree:Get(embedName):PrepareForLoad()
mckenziemc@12 226 end
mckenziemc@12 227 end
mckenziemc@12 228 end
mckenziemc@12 229
mckenziemc@12 230
mckenziemc@12 231 -- I think the problem this solves is a major issue with
mckenziemc@12 232 -- migrating to separate libs. think about it more and document
mckenziemc@12 233 -- here and in project description
mckenziemc@15 234
mckenziemc@15 235 --- Force-loads this addon tree. If a subtree can be loaded on
mckenziemc@15 236 -- demand, this function will enable but not load the subtree.
mckenziemc@15 237 -- Assumptions: the root addon should be force-loaded, not just enabled.
mckenziemc@15 238 --function tree:ForceLoad()
mckenziemc@15 239
mckenziemc@15 240 -- Assumptions: the root is loadable-on demand, and force-load is available.
mckenziemc@15 241 -- and tree can be force-loaded
mckenziemc@12 242 function tree:PrepareForLoD()
mckenziemc@15 243 local root = self.root
mckenziemc@12 244
mckenziemc@15 245 -- prepare dependencies first (for consistency)
mckenziemc@15 246 local dependencies = {root:GetDependencies()}
mckenziemc@15 247
mckenziemc@12 248 for i, depName in pairs(dependencies) do
mckenziemc@15 249 local dep = classes.Addon:Get(depName)
mckenziemc@12 250
mckenziemc@15 251 if not dep:IsLoaded() then
mckenziemc@15 252 if dep:CanLoD() then
mckenziemc@15 253 -- don't load it now but make sure its dependencies are prepared
mckenziemc@15 254 Tree:Get(dep):PrepareForLoD()
mckenziemc@15 255 else
mckenziemc@15 256 -- Based on our assumption about the tree, this addon
mckenziemc@15 257 -- should be able to force-load.
mckenziemc@15 258 -- force-load it now so we can load the parent on demand
mckenziemc@15 259 Tree:Get(dep):ForceLoad()
mckenziemc@15 260 end
mckenziemc@12 261 end
mckenziemc@12 262 end
mckenziemc@12 263
mckenziemc@12 264 -- prepare embeds, if they are available separately
mckenziemc@15 265 local embeds = {root:GetEmbeds()}
mckenziemc@15 266
mckenziemc@12 267 for i, embedName in pairs(embeds) do
mckenziemc@15 268 if classes.Addon:Exists(embedName) then
mckenziemc@15 269 local embed = classes.Addon:Get(embedName)
mckenziemc@15 270
mckenziemc@15 271 if not embed:IsLoaded() then
mckenziemc@15 272 if embed:CanLoD() then
mckenziemc@15 273 Tree:Get(embed):PrepareForLoD()
mckenziemc@15 274 else
mckenziemc@15 275 Tree:Get(embed):ForceLoad()
mckenziemc@15 276 end
mckenziemc@12 277 end
mckenziemc@12 278 end
mckenziemc@12 279 end
mckenziemc@15 280
mckenziemc@15 281 root:Enable()
mckenziemc@12 282 end
mckenziemc@12 283
mckenziemc@12 284
mckenziemc@18 285 function tree:LoadLate()
mckenziemc@18 286 local root = self.root
mckenziemc@18 287
mckenziemc@18 288 -- load dependencies
mckenziemc@18 289 local dependencies = {root:GetDependencies()}
mckenziemc@18 290
mckenziemc@18 291 for i, depName in pairs(dependencies) do
mckenziemc@18 292 Tree:Get(depName):LoadLate()
mckenziemc@18 293 end
mckenziemc@18 294
mckenziemc@18 295 -- load embeds, if they are available separately
mckenziemc@18 296 local embeds = {root:GetEmbeds()}
mckenziemc@18 297
mckenziemc@18 298 for i, embedName in pairs(embeds) do
mckenziemc@18 299 if classes.Addon:Exists(embedName) then
mckenziemc@18 300 Tree:Get(embedName):LoadLate()
mckenziemc@18 301 end
mckenziemc@18 302 end
mckenziemc@18 303
mckenziemc@18 304 root:LoadLate()
mckenziemc@18 305 end
mckenziemc@18 306
mckenziemc@18 307
mckenziemc@18 308
mckenziemc@15 309 --- Force-loads this tree.
mckenziemc@15 310 -- This will also load any LoD addons in the tree
mckenziemc@10 311 function tree:ForceLoad()
mckenziemc@15 312 local root = self.root
mckenziemc@15 313
mckenziemc@15 314 -- FIXME: if already loaded
mckenziemc@15 315
mckenziemc@8 316 -- load dependencies
mckenziemc@15 317 local dependencies = {root:GetDependencies()}
mckenziemc@15 318
mckenziemc@8 319 for i, depName in pairs(dependencies) do
mckenziemc@15 320 Tree:Get(depName):ForceLoad()
mckenziemc@8 321 end
mckenziemc@8 322
mckenziemc@8 323 -- load embeds, if they are available separately
mckenziemc@15 324 local embeds = {root:GetEmbeds()}
mckenziemc@15 325
mckenziemc@8 326 for i, embedName in pairs(embeds) do
mckenziemc@15 327 if classes.Addon:Exists(embedName) then
mckenziemc@15 328 Tree:Get(embedName):ForceLoad()
mckenziemc@15 329 end
mckenziemc@8 330 end
mckenziemc@8 331
mckenziemc@18 332 if root:CanLoD() then
mckenziemc@18 333 root:Load()
mckenziemc@18 334 else
mckenziemc@18 335 root:ForceLoad()
mckenziemc@18 336 end
mckenziemc@8 337 end