Mercurial > wow > dependencyloader
changeset 12:b230b94d4487
fixed Addon.lua to use the unhooked EnableAddOn (still needs to be changed to grab from the interface)
improved the error message when creating an Addon object on a Blizzard addon (will add direct support later)
implemented the hooks on EnableAddOn and LoadAddOn
rearranged functions inside Tree.lua, with some edits
copied OptDeps from main module to the bootstrap module, to delegate loading to the client when possible
author | mckenziemc |
---|---|
date | Fri, 10 Dec 2010 00:21:17 -0800 |
parents | 47d15fc9208e |
children | 110baf84e7a8 |
files | DependencyLoader/Addon.lua DependencyLoader/DependencyLoader.lua DependencyLoader/Tree.lua DependencyLoader_Bootstrap/DependencyLoader_Bootstrap.toc DependencyLoader_Bootstrap/bootstrap.lua |
diffstat | 5 files changed, 272 insertions(+), 136 deletions(-) [+] |
line wrap: on
line diff
--- a/DependencyLoader/Addon.lua Sun Dec 05 03:39:26 2010 -0800 +++ b/DependencyLoader/Addon.lua Fri Dec 10 00:21:17 2010 -0800 @@ -10,6 +10,7 @@ local Addon, addon = addonTable:NewClass("Addon") +Addon.enableAddon = EnableAddOn -- TODO: use raw hook from main module? Addon.addons = {} Addon.nameToIndex = {} @@ -41,7 +42,8 @@ instance.name = GetAddOnInfo(id) instance.index = index else - error("Addon not found") + local message = "Addon not found: "..(id or "nil") + error(message) end end @@ -166,7 +168,7 @@ function addon:Enable() -- FIXME: delay this till after PLAYER_LOGIN or it'll get force-loaded - EnableAddOn(self.name) + Addon.enableAddon(self.name) end
--- a/DependencyLoader/DependencyLoader.lua Sun Dec 05 03:39:26 2010 -0800 +++ b/DependencyLoader/DependencyLoader.lua Fri Dec 10 00:21:17 2010 -0800 @@ -1,6 +1,7 @@ -- DependencyLoader -- + local addonName, addonTable = ... @@ -10,11 +11,11 @@ addonTable.interface = DependencyLoader -local libPrint = LibStub("LibPrint-1.0") +local LibPrint = LibStub("LibPrint-1.0") local LibScriptLink = LibStub("LibScriptLink-1.0") -DependencyLoader.printStream = libPrint:NewStream("DependencyLoader", "DpLdr", print) -DependencyLoader.debugStream = libPrint:NewStream("DependencyLoader", "DpLdr", "mcm") +DependencyLoader.printStream = LibPrint:NewStream("DependencyLoader", "DpLdr", print) +DependencyLoader.debugStream = LibPrint:NewStream("DependencyLoader", "DpLdr", "mcm") function DependencyLoader:Print(...) @@ -34,11 +35,12 @@ function DependencyLoader:OnEnable() + self:RawHook("LoadAddOn", true) + self:RawHook("EnableAddOn", true) + + self:PrepareAllAddons() + self:Print("Enabled", addonName) - - self:Hook("EnableAddOn", true) - - self:FixCurrentAddons() end @@ -66,7 +68,7 @@ -- Enables any dependencies needed by the addons -- that have already been enabled -function DependencyLoader:FixCurrentAddons() +function DependencyLoader:PrepareAllAddons() local requestReload = false for i=1, GetNumAddOns() do @@ -74,26 +76,105 @@ -- TODO: what if an addon was loaded but its deps were then disabled? if addon:IsEnabled() and not addon:IsLoaded() then - local tree = addonTable.classes.Tree:Get(addon) - - if self:CanForceLoad() and tree:CanForceLoad() then - tree:ForceLoad() - elseif tree:CanLoD() then - tree:PrepareForLoD() - elseif tree:CanLoad() then - tree:PrepareForReload() - requestReload = true - end + self:EnableAddOn(addon:GetName()) end end + --[[ if requestReload then local message = LibScriptLink:NewLink(ReloadUI) .. " to reload your UI." self:Print(message) end + ]] end function DependencyLoader:EnableAddOn(...) - print("DependencyLoader:EnableAddOn", ...) + local id = ... + local addon = addonTable.classes.Addon:Get(id) + local tree = addonTable.classes.Tree:Get(addon) + + local requestReload = false + + if self:CanForceLoad() then + -- NOTE: if we can force-load, then will enabling LoD addons cause them to load too? + -- A: no, they will still wait for LoadAddOn + + -- Can the addon be loaded on demand if force-loading is + -- allowed for its dependencies + -- if so, enable all deps and force-load if nec. + -- deps will get enabled if all parents are lod, force-loaded + -- if any parent can't be loaded on demand + -- else + -- if the addon is not loadable on demand but the tree can be + -- force-loaded, then force-load it all + -- deps will all get loaded since req. for root to load + -- else + -- if it can be loaded with a reloadui then prepare after login + -- else + -- it can't be loaded, maybe tell the user + + if tree:CanLoDWithForce() then + tree:PrepareForLoD() + elseif tree:CanForceLoad() then + tree:ForceLoad() + elseif tree:CanLoad() then + tree:PrepareForReload() + requestReload = true + else + -- TODO: tell user + end + else + -- if it can be loaded on demand (deps are loaded or LoD) then + -- prepare it (enable all deps) + -- else + -- if it can be loaded (and isn't already) then + -- if force loading is available, we have to wait, then enable everything + -- else + -- prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT) + -- else + -- can't be loaded, maybe tell the user + + if tree:CanLoD() then + tree:PrepareForReload() + -- don't actually intend to reload, just enable everything + elseif tree:CanLoad() then + tree:PrepareForReload() + requestReload = true + else + -- TODO: tell user + end + end + + -- TODO: requestReload + + return self.hooks.EnableAddOn(...) end + + + +--- Prepares the addon tree rooted at the specified addon +function DependencyLoader:LoadAddOn(...) + local id = ... + + local isBlizzardAddon = false + + if type(id) == "string" and string.match(id, "Blizzard_") then + self:Debug("Asked to load Blizzard addon", id, ", skipping") + isBlizzardAddon = true + end + + if not isBlizzardAddon then + local addon = addonTable.classes.Addon:Get(id) + local tree = addonTable.classes.Tree:Get(addon) + + if tree:CanLoD() then + tree:PrepareForLoD() + elseif tree:CanLoad() then + tree:PrepareForReload() + end + end + + -- call even if it can't be loaded so regular returns appear + return self.hooks.LoadAddOn(...) +end
--- a/DependencyLoader/Tree.lua Sun Dec 05 03:39:26 2010 -0800 +++ b/DependencyLoader/Tree.lua Fri Dec 10 00:21:17 2010 -0800 @@ -51,52 +51,38 @@ end -function tree:GetLoadBitfield() - local bitfield = self.root:GetLoadBitfield() - +-- Checks if the tree rooted at the specified addon +-- can be loaded if all dependencies are enabled +-- and the UI is reloaded. +-- Basically makes sure all dependencies are installed. +function tree:CanLoad() + if not self.root:CanLoad() then + return false + end + + -- check all the dependencies local dependencies = {self.root:GetDependencies()} for i, depName in pairs(dependencies) do + local dep = addonTable.classes.Addon:Get(depName) + + if not dep:CanLoad() then + return false + end + local depTree = Tree:Get(depName) - if depTree == nil then - return 0 - end - - bitfield = bit.band(bitfield, depTree:GetLoadBitfield()) - end - - return bitfield -end - - ---- Checks if this tree can be force-loaded. --- Does not check user settings nor if force-loading is actually available. --- @return canForceLoad True if this tree can be force loaded, false otherwise -function tree:CanForceLoad() - if self.root:IsLoaded() then - return true - end - - if not self.root:CanForceLoad() then - return false - end - - -- now check dependencies recursively - local dependencies = {self.root:GetDependencies()} - for i, depName in pairs(dependencies) do - local depTree = Tree:Get(depName) - - if not depTree:CanForceLoad() then - return false + if not depTree:CanLoad() then + return false -- missing dependency end end - return + return true end --- NOTE: any tree that can be loaded on demand is also eligible for force-loading --- Checks if the tree can be loaded on demand. +--- Checks if the tree can be loaded on demand. +-- Does not consider force-loading; dependencies must +-- be enabled and LoD, or loaded function tree:CanLoD() -- since this will be used recursively, return true if -- this is already loaded. @@ -111,7 +97,7 @@ end -- now check dependencies recursively - local dependencies = {root:GetDependencies()} + local dependencies = {self.root:GetDependencies()} for i, depName in pairs(dependencies) do local depTree = Tree:Get(depName) @@ -124,35 +110,82 @@ 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 tree:CanLoad() - if self.root:IsLoaded() then - return true - -- FIXME: deps may have been disabled +--- Checks if this tree can be loaded on demand as long as +-- force-loading is allowed for preparing dependencies. +function tree:CanLoDWithForce() + if not self.root:CanLoD() then + return false end - -- TODO: make sure the root isn't incompatible - -- now check dependencies recursively - -- FIXME: prevent infinite recursion - local dependencies = {self.root:GetDependencies()} for i, depName in pairs(dependencies) do + local dep = addonTable.classes.Addon:Get(depName) local depTree = Tree:Get(depName) - if not depTree:CanLoad() then - return false -- missing dependency + if not dep:CanLoad() then + return false end - - -- TODO: make sure it's compatible + + if dep:CanLoD() then + if not depTree:CanLoDWithForce() then + return false + end + elseif dep:CanForceLoad() then + if not depTree:CanForceLoad() then + return + end + end end return true end + + +--- Checks if this tree can be force-loaded. +-- Does not check user settings nor if force-loading is actually available. +-- @return canForceLoad True if this tree can be force loaded, false otherwise +function tree:CanForceLoad() + -- TODO: remove redundencies (for now they're here for design flexibility) + + -- this addon must be loaded, able to load-on-demand, or able to force-load + if self.root:IsLoaded() then + return true + end + + if not self.root:CanLoad() then + return false + end + + if not self.root:CanForceLoad() then + return false + end + + -- now check dependencies recursively + local dependencies = {self.root:GetDependencies()} + for i, depName in pairs(dependencies) do + local dep = addonTable.classes.Addon:Get(depName) + local depTree = Tree:Get(depName) + + if not dep:CanLoad() then + return false + end + + if not dep:CanLoD() and not dep:CanForceLoad() then + return false + end + + if not depTree:CanForceLoad() then + return false + end + end + + return +end + + + --[[ -- Loads the tree rooted at the specified addon. -- FIXME: load the root too or not? @@ -172,6 +205,81 @@ ]] +function tree:PrepareForReload() + -- if force-loading is enabled then we have to queue this if the addon isn't lod + local function callback() + self.root:Enable() + + -- check dependencies + local dependencies = {self.root:GetDependencies()} + for i, depName in pairs(dependencies) do + Tree:Get(depName):PrepareForReload() + end + + -- prepare embeds, if they are available separately + local embeds = {self.root:GetEmbeds(addon)} + for i, embedName in pairs(embeds) do + Tree:Get(embedName):PrepareForReload() + end + end + + if IsLoggedIn() then + callback() + else + -- TODO: replace with cleaner alternative? + local frame = CreateFrame("Frame") + frame:SetScript("OnEvent", callback) + frame:RegisterEvent("PLAYER_LOGIN") + end +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 tree:PrepareForLoD() + -- assume root is LoD + + -- check dependencies + local dependencies = {self.root:GetDependencies(addon)} + for i, depName in pairs(dependencies) do + local depTree = Tree:Get(depName) + depTree:PrepareForLoD() + + --[[ + 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 = {self.root:GetEmbeds(addon)} -- FIXME: addon? + for i, embedName in pairs(embeds) do + local embedTree = Tree:Get(embedName) + embedTree:PrepareForLoD() + + --[[ + 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 + + -- load the root too, since it may actually be a leaf function tree:ForceLoad() -- load dependencies @@ -215,65 +323,3 @@ 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 tree:PrepareForLoD() - -- assume root is LoD - - -- check dependencies - local dependencies = {root:GetDependencies(addon)} - for i, depName in pairs(dependencies) do - local depTree = Tree:Get(depName) - depTree:PrepareForLoD() - - --[[ - 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 embedTree = Tree:Get(embedName) - embedTree:PrepareForLoD() - - --[[ - 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 tree:PrepareForReload() - self.root:Enable() - - -- check dependencies - local dependencies = {self.root:GetDependencies()} - for i, depName in pairs(dependencies) do - Tree:Get(depName):PrepareForReload() - end - - -- prepare embeds, if they are available separately - local embeds = {self.root:GetEmbeds(addon)} - for i, embedName in pairs(embeds) do - Tree:Get(embedName):PrepareForReload() - end -end
--- a/DependencyLoader_Bootstrap/DependencyLoader_Bootstrap.toc Sun Dec 05 03:39:26 2010 -0800 +++ b/DependencyLoader_Bootstrap/DependencyLoader_Bootstrap.toc Fri Dec 10 00:21:17 2010 -0800 @@ -5,6 +5,10 @@ ## Author: mckenziemc +# Ask the client to load the dependencies of the core module if +# they're already enabled, to lessen the chance of something breaking. +## OptDeps: LibStub, Ace3, LibPrint-1.0, LibScriptLink-1.0 + ## LoadManagers: !!!LoadFirst, AddonLoader ## X-LoadFirst: true ## X-LoadOn-Always: true
--- a/DependencyLoader_Bootstrap/bootstrap.lua Sun Dec 05 03:39:26 2010 -0800 +++ b/DependencyLoader_Bootstrap/bootstrap.lua Fri Dec 10 00:21:17 2010 -0800 @@ -7,6 +7,9 @@ local addonName, addonTable = ... +-- FIXME: don't force-load if we're already logged in + + print("loading DependencyLoader_Bootstrap") -- TODO: move and use dependency parsing function here?