annotate DependencyLoader/Tree.lua @ 9:5362e308c3eb

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