Mercurial > wow > dependencyloader
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Core/Tree.lua Sat Dec 04 23:05:34 2010 -0800 @@ -0,0 +1,287 @@ +-- Tree +-- Represents a recursive "tree" of addon +-- dependencies rooted at a specific addon. + + +local addonName, addonTable = ... + + +-- TODO: prevent infinite loops in the recursive functions + + +local Tree, tree = addonTable:NewClass("Tree") + + +Tree.trees = {} + +-- internal +-- Creates a new tree object +-- @param root Name, index, or Addon object of the root addon. +function Tree:New(root) + if type(root) ~= "table" then + root = addonTable.classes.Addon:Get(root) + end + + local instance = {} + setmetatable(instance, self.instanceMetatable) + + instance.root = root + + return instance +end + + +--- Retrieves the tree rooted at the specified addon +-- @param root Name, index, or Addon object of the root. +function Tree:Get(root) + if type(root) ~= "table" then + root = addonTable.classes.Addon:Get(root) + end + + local tree = self.trees[root] + + if tree then + return tree + else + tree = self:New(root) + self.trees[root] = tree + return tree + end +end + + +function tree:GetLoadBitfield() + local bitfield = self.root:GetLoadBitfield() + + local dependencies = {self.root:GetDependencies()} + for i, depName in pairs(dependencies) do + local depTree = Tree:Get(depName) + + if depTree == nil then + return 0 + end + + bitfield = bit.band(bitfield, depTree:GetLoadBitfield()) + end + + return bitfield +end + + +-- Checks if the tree rooted at the specified addon can be force-loaded. +-- @param root The name or index of the root addon. +function core:CanForceLoadTree(root) + -- TODO: if some addons have already loaded, we have to check + -- forceafter for those and forcebefore for the others + return false +end + + +-- NOTE: any tree that can be loaded on demand is also eligible for force-loading +-- Checks if the tree rooted at the specified addon can be loaded on demand. +-- @param root The name or index of the root addon. +function core:CanLoDTree(root) + local bitfield = self:GetLoadBitfield() + root = self:GetAddon(root) + assert(root) + + -- since this will be used recursively, return true if + -- this is already loaded. + if root:IsLoaded() then + return true + end + + -- true if all dependencies are loaded or LoD + + if not root:CanLoD() then + return false + end + + -- now check dependencies recursively + local dependencies = {root:GetDependencies()} + for i, depName in pairs(dependencies) do + local dep = self:GetAddon(depName) + + if not dep then + return false -- missing + end + + if not dep:IsLoaded() then + if not self:CanLoDTree(depName) then + return false + end + end + end + + return true +end + + +-- Checks if the tree rooted at the specified addon +-- can be loaded if all dependencies are enabled +-- the UI is reloaded. +-- Basically makes sure all dependencies are installed. +function core:CanReloadTree(root) + -- convert root to an Addon object + root = self:GetAddon(root) + assert(root) + + if root:IsLoaded() then + return true + -- FIXME: deps may have been disabled + end + + -- TODO: make sure the root isn't incompatible + + -- now check dependencies recursively + -- FIXME: prevent infinite recursion + + local dependencies = {root:GetDependencies()} + for i, depName in pairs(dependencies) do + local dep = self:GetAddon(depName) + + if dep == nil then + return false -- missing dependency + end + + -- TODO: make sure it's compatible + end + + return true +end + +-- Loads the tree rooted at the specified addon. +-- FIXME: load the root too or not? +-- Supports both LoD addons and those that require force-loading. +function core:LoadTree(addon) + -- don't check if the tree can actually be loaded. + -- external code should do that itself to check if it + -- should even call this at all. + + if self:ForceLoadAvailable() then + -- LoD trees can also be force-loaded + self:ForceLoadTree(addon) + else + self:LoadLoDTree(addon) + end +end + + +-- load the root too, since it may actually be a leaf +function core:ForceLoadTree(root) + root = self:GetAddon(root) + assert(root) + + -- load dependencies + local dependencies = {root:GetDependencies(addon)} + for i, depName in pairs(dependencies) do + self:ForceLoadTree(depName) + end + + -- load embeds, if they are available separately + local embeds = {root:GetEmbeds(addon)} + for i, embedName in pairs(embeds) do + if Addon:Exists(embedName) then + self:ForceLoadTree(embedName) + end + end + + root:ForceLoad() +end + + +function core:LoadLoDTree(root) + root = self:GetAddon(root) + assert(root) + + -- load dependencies + local dependencies = {root:GetDependencies(addon)} + for i, depName in pairs(dependencies) do + self:LoadLoDTree(depName) + end + + -- load embeds, if they are available separately + local embeds = {root:GetEmbeds(addon)} + for i, embedName in pairs(embeds) do + if Addon:Exists(embedName) then + self:LoadLoDTree(embedName) + end + end + + root:LoD() +end + + +-- I think the problem this solves is a major issue with +-- migrating to separate libs. think about it more and document +-- here and in project description +function core:PrepareLoDTree(root) + root = self:GetAddon(root) + assert(root) + + -- assume root is LoD + + -- check dependencies + local dependencies = {root:GetDependencies(addon)} + for i, depName in pairs(dependencies) do + local dep = self:GetAddon(depName) + + -- assume external code made sure it exists + + if dep:CanLoD() then + -- don't load it now but make sure its dependencies are prepared + self:PrepareLoDTree(depName) + else + -- FIXME: if it's already loaded + -- force-load it now so we can load the parent on demand + self:ForceLoadTree(depName) + end + end + + -- prepare embeds, if they are available separately + local embeds = {root:GetEmbeds(addon)} -- FIXME: addon? + for i, embedName in pairs(embeds) do + local embed = self:GetAddon(embedName) + + if embed then + if embed:CanLoD() then + -- don't load it now but make sure its dependencies are prepared + self:PrepareLoDTree(embedName) + else + -- FIXME: if it's already loaded + -- force-load it now so we can load the parent on demand + self:ForceLoadTree(depName) + end + end + end +end + + +function Core:PrepareReloadTree(addon) + root = self:GetAddon(root) + assert(root) + + root:Enable() + + -- check dependencies + local dependencies = {root:GetDependencies()} + for i, depName in pairs(dependencies) do + self:PrepareReloadTree(depName) + end + + -- prepare embeds, if they are available separately + local embeds = {root:GetEmbeds(addon)} + for i, embedName in pairs(embeds) do + local embed = self:GetAddon(embedName) + + if embed then + self:PrepareReloadTree(embedName) + end + end +end + + +function Core:ForceLoadAvailable() + return true + -- FIXME: use field and a frame registered for PLAYER_LOGIN +end