Mercurial > wow > dependencyloader
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 8:930871e163bc | 9:5362e308c3eb |
|---|---|
| 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 |
