Mercurial > wow > dependencyloader
changeset 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 | 930871e163bc |
children | e0a4a8b5b389 |
files | DependencyLoader/Ace3.xml DependencyLoader/Addon.lua DependencyLoader/Core.lua DependencyLoader/DependencyLoader.toc DependencyLoader/DependencyLoader_Core.toc DependencyLoader/Tree.lua DependencyLoader/bootstrap.lua DependencyLoader/class.lua DependencyLoader/embeds.xml DependencyLoader/frontend.lua DependencyLoader/load.xml DependencyLoader/start.lua DependencyLoader_Bootstrap/Ace3.xml DependencyLoader_Bootstrap/DependencyLoader.toc DependencyLoader_Bootstrap/bootstrap.lua DependencyLoader_Bootstrap/embeds.xml DependencyLoader_Bootstrap/load.xml DependencyLoader_Core/Addon.lua DependencyLoader_Core/Core.lua DependencyLoader_Core/DependencyLoader_Core.toc DependencyLoader_Core/Tree.lua DependencyLoader_Core/class.lua DependencyLoader_Core/frontend.lua DependencyLoader_Core/load.xml DependencyLoader_Core/start.lua |
diffstat | 25 files changed, 1044 insertions(+), 1044 deletions(-) [+] |
line wrap: on
line diff
--- a/DependencyLoader/Ace3.xml Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> - <Script file="libs\Ace3\LibStub\LibStub.lua"/> - - <Include file="libs\Ace3\CallbackHandler-1.0\CallbackHandler-1.0.xml"/> - <Include file="libs\Ace3\AceAddon-3.0\AceAddon-3.0.xml"/> - <Include file="libs\Ace3\AceEvent-3.0\AceEvent-3.0.xml"/> - <Include file="libs\Ace3\AceTimer-3.0\AceTimer-3.0.xml"/> - <Include file="libs\Ace3\AceBucket-3.0\AceBucket-3.0.xml"/> - <Include file="libs\Ace3\AceHook-3.0\AceHook-3.0.xml"/> - <Include file="libs\Ace3\AceDB-3.0\AceDB-3.0.xml"/> - <Include file="libs\Ace3\AceDBOptions-3.0\AceDBOptions-3.0.xml"/> - <Include file="libs\Ace3\AceLocale-3.0\AceLocale-3.0.xml"/> - <Include file="libs\Ace3\AceConsole-3.0\AceConsole-3.0.xml"/> - <Include file="libs\Ace3\AceGUI-3.0\AceGUI-3.0.xml"/> - <Include file="libs\Ace3\AceConfig-3.0\AceConfig-3.0.xml"/> - <Include file="libs\Ace3\AceComm-3.0\AceComm-3.0.xml"/> - <Include file="libs\Ace3\AceTab-3.0\AceTab-3.0.xml"/> - <Include file="libs\Ace3\AceSerializer-3.0\AceSerializer-3.0.xml"/> -</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/Addon.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,248 @@ +-- Addon +-- Represents individual addon modules + + +local addonName, addonTable = ... + + +-- NOTE: I assume that the API addon functions are +-- slightly quicker with an index than with a number. + +-- TODO: modify the dependency stuff to use the Errata module if available + +local Addon, addon = addonTable:NewClass("Addon") + + +-- load ability masks +Addon.loadMasks = { + reload = bit.lshift(1, 0), -- can load after reloadui + ondemand = bit.lshift(1, 1), -- can load on demand + forceafter = bit.lshift(1, 2), -- force load after it would normally be loaded + forcebefore = bit.lshift(1, 3), -- force load before it would normally be loaded +} + + +Addon.addons = {} +Addon.nameToIndex = {} + + +-- Internal function +-- Creates a new Addon object +-- @param id Name or index of the addon. +function Addon:New(id) + local instance = {} + setmetatable(instance, self.instanceMetatable) + + if type(id) == "number" then + -- TODO: make sure it's in range + instance.index = id + instance.name = GetAddOnInfo(id) + else + -- FIXME: allow blizzard addons? + local index + + for i=1,GetNumAddOns() do + if GetAddOnInfo(i) == id then + index = i + break + end + end + + if index then + instance.name = GetAddOnInfo(id) + instance.index = index + else + error("Addon not found") + end + end + + return instance +end + + +--- Retrieves an Addon object. +-- @param id Name or index of the addon to retrieve. +-- @return The Addon object, or nil if not found. +function Addon:Get(id) + if not self:Exists(id) then + return nil + end + + if type(id) == "number" then + if self.addons[id] ~= nil then + return self.addons[id] + end + + local new = self:New(id) + self.addons[new:GetIndex()] = new + self.nameToIndex[new:GetName()] = id + + return new + elseif type(id) == "string" then + if self.nameToIndex[id] then + return self.addons[self.nameToIndex[id] ] + end + + local new = self:New(id) + self.addons[new:GetIndex()] = new + self.nameToIndex[id] = new:GetIndex() + + return new + end +end + +-- Checks if an addon exists with the specified name. +-- @param addon Name of the addon. +-- @return True if the addon is present, false otherwise. +function Addon:Exists(addon) + if type(addon) == "number" then + if addon >= 1 and addon <= GetNumAddOns() then + return true + else + return false + end + elseif type(addon) == "string" then + local status = select(6, GetAddOnInfo(addon)) + + if status == "MISSING" then + return false + else + return true + end + else + error() + end +end + + +function Addon:GetLoadMasks() + return self.masks +end + + +function addon:GetName() + return self.name +end + + +function addon:GetIndex() + return self.index +end + + +function addon:IsEnabled() + -- FIXME: written while tired; review later + local status = select(6, GetAddOnInfo(self.index)) + + if status == "DISABLED" then + return false + else + return true + end +end + + +function addon:GetLoadBitfield() + local bitfield = 0 + + if self:CanLoad() then + bitfield = bitfield + self.masks.reload + end + + if self:CanLoD() then + bitfield = bitfield + self.masks.ondemand + end + + if self:CanForceLoadAfter() then + bitfield = bitfield + self.masks.forceafter + end + + if self:CanForceLoadBefore() then + bitfield = bitfield + self.masks.forcebefore + end + + return bitfield +end + + +--- Checks if the addon is loadable. +-- Considers interface issues, missing, etc. (NYI) +-- Does not check dependencies. +function addon:CanLoad() + -- FIXME: an addon may be present but unloadable if loading out of date addons is disabled. + return true +end + + +function addon:CanLoD() + -- FIXME: what will the client say about addons using LoadManagers if the LM was force-loaded? + if IsAddOnLoadOnDemand(self.name) then + return true + else + return false + end +end + + +function addon:CanForceLoadAfter() + -- TODO: check Errata module + return false +end + + +function addon:CanForceLoadBefore() + -- TODO: check Errata module + return false -- TODO: check if there's any reason addons can't be forceloaded +end + + +function addon:Enable() + -- FIXME: delay this till after PLAYER_LOGIN or it'll get force-loaded + EnableAddOn(self.name) +end + + +-- NOTE: only call for LoD, not force-loading +function addon:Load() + assert(self:CanLoD()) + + EnableAddOn(self.name) + LoadAddOn(self.name) +end + + +function addon:ForceLoad() + assert(self:CanForceLoad()) + -- TODO: make sure force-loading is available at this time + + EnableAddOn(self.name) -- This should cause the game to also load this addon +end + + +function addon:GetDependencies() + -- TODO: consider no-lib embeds as deps? + return GetAddOnDependencies(self.index) +end + + +function addon:GetEmbeds() + local embeds = {} + + local embedString = GetAddOnMetadata(self.name, "X-Embeds") + + if embedString then + for match in string.gmatch(embedString, "[^,%s]+") do + table.insert(embeds, match) + end + end + + return unpack(embeds) +end + +function addon:IsLoaded() + if IsAddOnLoaded(self.index) then + return true + else + return false + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/Core.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,293 @@ + + + +local addonName, addonTable = ... + + +local Core, core = addonTable:NewClass("Core") + + +function Core:New() + local instance = {} + setmetatable(instance, self.instanceMetatable) + + instance.addons = {} + instance.nameToIndex = {} + + for i=1,GetNumAddOns() do + local newAddon = Addon:New(i) + + instance.addons[i] = newAddon + instance.nameToIndex[newAddon:GetName()] = i + end + + -- TODO: enable dependencies for any addons that have already loaded + + return instance +end + + +-- @param addon Name or index of the addon to retrieve. +-- @return The addon object, or nil if not found +function core:GetAddon(addon) + if not Addon:Exists(addon) then + return nil + end + + local index + + if type(addon) == "string" then + index = self.nameToIndex[addon] + elseif type(addon) == "number" then + index = addon + end + + return self.addons[index] +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) + -- convert root to an Addon object + root = self:GetAddon(root) + assert(root) + + if root:IsLoaded() then + return true + end + + -- check if the root itself can be force-loaded + if not root:CanForceLoad() then + return false + end + + -- 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 + + -- if it's already loaded then skip to next one + if not dep:IsLoaded() then + if not self:CanForceLoadTree(depName) then + return false + end + end + end + + return true +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) + 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
--- a/DependencyLoader/DependencyLoader.toc Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -## Interface: 40000 - -## Notes: Bootstrap for DependencyLoader_Core -## Author: mckenziemc - -## LoadManagers: !!!LoadFirst, AddonLoader -## X-LoadFirst: true -## X-LoadOn-Always: true - - -load.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/DependencyLoader_Core.toc Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,14 @@ +## Interface: 40000 + +# TODO: actually explain what DependencyLoader does. +## Notes: Core module of DependencyLoader +## Author: mckenziemc + +# TODO: figure out some way to allow AddonLoader +# to work with DependencyLoader +## Dependencies: DependencyLoader, LibStub, LibPrint-1.0, Ace3 + +## LoadOnDemand: 1 + + +load.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/Tree.lua Sun Dec 05 00:12:57 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
--- a/DependencyLoader/bootstrap.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ --- bootstrap.lua --- Bootstrap code for DependencyLoader, allowing --- the user to successfully load it without --- explicitly enabling its own dependencies. - - -local addonName, addonTable = ... - --- TODO: move and use dependency parsing function here? -local dependencies = {"LibStub", "LibPrint-1.0", "Ace3"} - -local canLoad = true -for _, addon in pairs(dependencies) do - local reason = select(6, GetAddOnInfo(addon)) - - if reason ~= nil and reason ~= "DISABLED" then - canLoad = false - break - end -end - -if not canLoad then - print("Can't load DependencyLoader") - return -end - - -print("Loading DependencyLoader") - -for _, addon in pairs(dependencies) do - EnableAddOn(addon) -end - -EnableAddOn("DependencyLoader_Core") -LoadAddOn("DependencyLoader_Core") -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/class.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,24 @@ +-- class.lua +-- Implements a generic class builder. + + +local addonName, addonTable = ... + +-- FIXME: prevent duplicate class definitions + +print( string.format([[running %s\class.lua]], addonName) ) + +addonTable.classes = {} + +function addonTable:NewClass(name) + local class, prototype, metatable = {}, {}, {} + + class.prototype = prototype + + metatable.__index = prototype + class.instanceMetatable = metatable + + self.classes[name] = class + + return class, prototype +end
--- a/DependencyLoader/embeds.xml Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> - <script file="libs\LibStub\LibStub.lua"/> - <include file="Ace3.xml"/> - <include file="libs\LibBuilder-1.0\load.xml"/> - <include file="libs\LibPrint-1.0\load.xml"/> -</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/frontend.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,83 @@ +-- main.lua +-- + +local addonName, addonTable = ... + + +local DependencyLoader = LibStub("AceAddon-3.0"):NewAddon(addonName) +_G[addonName] = DependencyLoader + +local libPrint = LibStub("LibPrint-1.0") +DependencyLoader.printStream = libPrint:NewStream("DependencyLoader", "DpLdr", print) +DependencyLoader.debugStream = libPrint:NewStream("DependencyLoader", "DpLdr", "mcm") + +-- temp +DependencyLoader.classes = addonTable.classes + +function DependencyLoader:Print(...) + self.printStream:Print(...) +end + + +function DependencyLoader:Debug(...) + self.debugStream:Print(...) +end + + +function DependencyLoader:OnInitialize() + self:Debug("Initializing and enabling", addonName) + self:Enable() +end + + +function DependencyLoader:OnEnable() + self.core = addonTable.classes.Core:New() + + self:Print("Enabled", addonName) + + self:FixCurrentAddons() +end + +function DependencyLoader:OnDisable() + self:Print("Disabled", addonName) +end + + +-- TODO: move this into core? + +-- Enables any dependencies needed by the addons +-- that have already been enabled +function DependencyLoader:FixCurrentAddons() + local core = self.core + + for i=1, GetNumAddOns() do + local addon = self.core:GetAddon(i) + + if addon:IsEnabled() then + if addon:IsLoaded() then + -- TODO: it might still help to enable its embeds + else + self:Debug("Checking", addon:GetName()) + + if addonTable.classes.Core:ForceLoadAvailable() then + if core:CanForceLoadTree(addon:GetName()) then + core:ForceLoadTree(addon:GetName()) + else + print("Can't force load", addon:GetName()) + end + else + if core:CanLoDTree(addon:GetName()) then + core:PrepareLoDTree(addon:GetName()) + else + print("Couldn't load", addon:GetName(), "on demand.") + end + end + end + end + end +end + + + + + \ No newline at end of file
--- a/DependencyLoader/load.xml Sat Dec 04 23:05:34 2010 -0800 +++ b/DependencyLoader/load.xml Sun Dec 05 00:12:57 2010 -0800 @@ -1,1 +1,1 @@ -<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> <include file="embeds.xml"/> <Script file="bootstrap.lua"/> </Ui> \ No newline at end of file +<ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> <script file="start.lua"/> <script file="class.lua"/> <script file="Addon.lua"/> <script file="Core.lua"/> <script file="frontend.lua"/> </ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader/start.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,21 @@ +-- start.lua +-- Initializes components of DependencyLoader + + +local addonName, addonTable = ... + + +print( string.format([[running %s\start.lua]], addonName) ) + +-- NOTE: We don't have to check if this module's dependencies +-- are available: it lists them normally in its .toc file and +-- the bootstrap module will take care of enabling them first. + +-- prepare output functions +local lp = LibStub("LibPrint-1.0") +local printStream = lp:NewStream("DependencyLoader", "DepLoader", "DepLdr", print) +local debugStream = lp:NewStream("DependencyLoader", "DepLoader", "DepLdr", "mcm") + +addonTable.print = function(...) printStream:Print(...) end +addonTable.debug = function(...) debugStream:Print(...) end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Bootstrap/Ace3.xml Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,19 @@ +<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> + <Script file="libs\Ace3\LibStub\LibStub.lua"/> + + <Include file="libs\Ace3\CallbackHandler-1.0\CallbackHandler-1.0.xml"/> + <Include file="libs\Ace3\AceAddon-3.0\AceAddon-3.0.xml"/> + <Include file="libs\Ace3\AceEvent-3.0\AceEvent-3.0.xml"/> + <Include file="libs\Ace3\AceTimer-3.0\AceTimer-3.0.xml"/> + <Include file="libs\Ace3\AceBucket-3.0\AceBucket-3.0.xml"/> + <Include file="libs\Ace3\AceHook-3.0\AceHook-3.0.xml"/> + <Include file="libs\Ace3\AceDB-3.0\AceDB-3.0.xml"/> + <Include file="libs\Ace3\AceDBOptions-3.0\AceDBOptions-3.0.xml"/> + <Include file="libs\Ace3\AceLocale-3.0\AceLocale-3.0.xml"/> + <Include file="libs\Ace3\AceConsole-3.0\AceConsole-3.0.xml"/> + <Include file="libs\Ace3\AceGUI-3.0\AceGUI-3.0.xml"/> + <Include file="libs\Ace3\AceConfig-3.0\AceConfig-3.0.xml"/> + <Include file="libs\Ace3\AceComm-3.0\AceComm-3.0.xml"/> + <Include file="libs\Ace3\AceTab-3.0\AceTab-3.0.xml"/> + <Include file="libs\Ace3\AceSerializer-3.0\AceSerializer-3.0.xml"/> +</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Bootstrap/DependencyLoader.toc Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,11 @@ +## Interface: 40000 + +## Notes: Bootstrap for DependencyLoader_Core +## Author: mckenziemc + +## LoadManagers: !!!LoadFirst, AddonLoader +## X-LoadFirst: true +## X-LoadOn-Always: true + + +load.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Bootstrap/bootstrap.lua Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,36 @@ +-- bootstrap.lua +-- Bootstrap code for DependencyLoader, allowing +-- the user to successfully load it without +-- explicitly enabling its own dependencies. + + +local addonName, addonTable = ... + +-- TODO: move and use dependency parsing function here? +local dependencies = {"LibStub", "LibPrint-1.0", "Ace3"} + +local canLoad = true +for _, addon in pairs(dependencies) do + local reason = select(6, GetAddOnInfo(addon)) + + if reason ~= nil and reason ~= "DISABLED" then + canLoad = false + break + end +end + +if not canLoad then + print("Can't load DependencyLoader") + return +end + + +print("Loading DependencyLoader") + +for _, addon in pairs(dependencies) do + EnableAddOn(addon) +end + +EnableAddOn("DependencyLoader_Core") +LoadAddOn("DependencyLoader_Core") +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Bootstrap/embeds.xml Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,6 @@ +<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> + <script file="libs\LibStub\LibStub.lua"/> + <include file="Ace3.xml"/> + <include file="libs\LibBuilder-1.0\load.xml"/> + <include file="libs\LibPrint-1.0\load.xml"/> +</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DependencyLoader_Bootstrap/load.xml Sun Dec 05 00:12:57 2010 -0800 @@ -0,0 +1,1 @@ +<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> <include file="embeds.xml"/> <Script file="bootstrap.lua"/> </Ui> \ No newline at end of file
--- a/DependencyLoader_Core/Addon.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,248 +0,0 @@ --- Addon --- Represents individual addon modules - - -local addonName, addonTable = ... - - --- NOTE: I assume that the API addon functions are --- slightly quicker with an index than with a number. - --- TODO: modify the dependency stuff to use the Errata module if available - -local Addon, addon = addonTable:NewClass("Addon") - - --- load ability masks -Addon.loadMasks = { - reload = bit.lshift(1, 0), -- can load after reloadui - ondemand = bit.lshift(1, 1), -- can load on demand - forceafter = bit.lshift(1, 2), -- force load after it would normally be loaded - forcebefore = bit.lshift(1, 3), -- force load before it would normally be loaded -} - - -Addon.addons = {} -Addon.nameToIndex = {} - - --- Internal function --- Creates a new Addon object --- @param id Name or index of the addon. -function Addon:New(id) - local instance = {} - setmetatable(instance, self.instanceMetatable) - - if type(id) == "number" then - -- TODO: make sure it's in range - instance.index = id - instance.name = GetAddOnInfo(id) - else - -- FIXME: allow blizzard addons? - local index - - for i=1,GetNumAddOns() do - if GetAddOnInfo(i) == id then - index = i - break - end - end - - if index then - instance.name = GetAddOnInfo(id) - instance.index = index - else - error("Addon not found") - end - end - - return instance -end - - ---- Retrieves an Addon object. --- @param id Name or index of the addon to retrieve. --- @return The Addon object, or nil if not found. -function Addon:Get(id) - if not self:Exists(id) then - return nil - end - - if type(id) == "number" then - if self.addons[id] ~= nil then - return self.addons[id] - end - - local new = self:New(id) - self.addons[new:GetIndex()] = new - self.nameToIndex[new:GetName()] = id - - return new - elseif type(id) == "string" then - if self.nameToIndex[id] then - return self.addons[self.nameToIndex[id] ] - end - - local new = self:New(id) - self.addons[new:GetIndex()] = new - self.nameToIndex[id] = new:GetIndex() - - return new - end -end - --- Checks if an addon exists with the specified name. --- @param addon Name of the addon. --- @return True if the addon is present, false otherwise. -function Addon:Exists(addon) - if type(addon) == "number" then - if addon >= 1 and addon <= GetNumAddOns() then - return true - else - return false - end - elseif type(addon) == "string" then - local status = select(6, GetAddOnInfo(addon)) - - if status == "MISSING" then - return false - else - return true - end - else - error() - end -end - - -function Addon:GetLoadMasks() - return self.masks -end - - -function addon:GetName() - return self.name -end - - -function addon:GetIndex() - return self.index -end - - -function addon:IsEnabled() - -- FIXME: written while tired; review later - local status = select(6, GetAddOnInfo(self.index)) - - if status == "DISABLED" then - return false - else - return true - end -end - - -function addon:GetLoadBitfield() - local bitfield = 0 - - if self:CanLoad() then - bitfield = bitfield + self.masks.reload - end - - if self:CanLoD() then - bitfield = bitfield + self.masks.ondemand - end - - if self:CanForceLoadAfter() then - bitfield = bitfield + self.masks.forceafter - end - - if self:CanForceLoadBefore() then - bitfield = bitfield + self.masks.forcebefore - end - - return bitfield -end - - ---- Checks if the addon is loadable. --- Considers interface issues, missing, etc. (NYI) --- Does not check dependencies. -function addon:CanLoad() - -- FIXME: an addon may be present but unloadable if loading out of date addons is disabled. - return true -end - - -function addon:CanLoD() - -- FIXME: what will the client say about addons using LoadManagers if the LM was force-loaded? - if IsAddOnLoadOnDemand(self.name) then - return true - else - return false - end -end - - -function addon:CanForceLoadAfter() - -- TODO: check Errata module - return false -end - - -function addon:CanForceLoadBefore() - -- TODO: check Errata module - return false -- TODO: check if there's any reason addons can't be forceloaded -end - - -function addon:Enable() - -- FIXME: delay this till after PLAYER_LOGIN or it'll get force-loaded - EnableAddOn(self.name) -end - - --- NOTE: only call for LoD, not force-loading -function addon:Load() - assert(self:CanLoD()) - - EnableAddOn(self.name) - LoadAddOn(self.name) -end - - -function addon:ForceLoad() - assert(self:CanForceLoad()) - -- TODO: make sure force-loading is available at this time - - EnableAddOn(self.name) -- This should cause the game to also load this addon -end - - -function addon:GetDependencies() - -- TODO: consider no-lib embeds as deps? - return GetAddOnDependencies(self.index) -end - - -function addon:GetEmbeds() - local embeds = {} - - local embedString = GetAddOnMetadata(self.name, "X-Embeds") - - if embedString then - for match in string.gmatch(embedString, "[^,%s]+") do - table.insert(embeds, match) - end - end - - return unpack(embeds) -end - -function addon:IsLoaded() - if IsAddOnLoaded(self.index) then - return true - else - return false - end -end
--- a/DependencyLoader_Core/Core.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,293 +0,0 @@ - - - -local addonName, addonTable = ... - - -local Core, core = addonTable:NewClass("Core") - - -function Core:New() - local instance = {} - setmetatable(instance, self.instanceMetatable) - - instance.addons = {} - instance.nameToIndex = {} - - for i=1,GetNumAddOns() do - local newAddon = Addon:New(i) - - instance.addons[i] = newAddon - instance.nameToIndex[newAddon:GetName()] = i - end - - -- TODO: enable dependencies for any addons that have already loaded - - return instance -end - - --- @param addon Name or index of the addon to retrieve. --- @return The addon object, or nil if not found -function core:GetAddon(addon) - if not Addon:Exists(addon) then - return nil - end - - local index - - if type(addon) == "string" then - index = self.nameToIndex[addon] - elseif type(addon) == "number" then - index = addon - end - - return self.addons[index] -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) - -- convert root to an Addon object - root = self:GetAddon(root) - assert(root) - - if root:IsLoaded() then - return true - end - - -- check if the root itself can be force-loaded - if not root:CanForceLoad() then - return false - end - - -- 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 - - -- if it's already loaded then skip to next one - if not dep:IsLoaded() then - if not self:CanForceLoadTree(depName) then - return false - end - end - end - - return true -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) - 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
--- a/DependencyLoader_Core/DependencyLoader_Core.toc Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -## Interface: 40000 - -# TODO: actually explain what DependencyLoader does. -## Notes: Core module of DependencyLoader -## Author: mckenziemc - -# TODO: figure out some way to allow AddonLoader -# to work with DependencyLoader -## Dependencies: DependencyLoader, LibStub, LibPrint-1.0, Ace3 - -## LoadOnDemand: 1 - - -load.xml
--- a/DependencyLoader_Core/Tree.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,287 +0,0 @@ --- 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
--- a/DependencyLoader_Core/class.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ --- class.lua --- Implements a generic class builder. - - -local addonName, addonTable = ... - --- FIXME: prevent duplicate class definitions - -print( string.format([[running %s\class.lua]], addonName) ) - -addonTable.classes = {} - -function addonTable:NewClass(name) - local class, prototype, metatable = {}, {}, {} - - class.prototype = prototype - - metatable.__index = prototype - class.instanceMetatable = metatable - - self.classes[name] = class - - return class, prototype -end
--- a/DependencyLoader_Core/frontend.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ --- main.lua --- - -local addonName, addonTable = ... - - -local DependencyLoader = LibStub("AceAddon-3.0"):NewAddon(addonName) -_G[addonName] = DependencyLoader - -local libPrint = LibStub("LibPrint-1.0") -DependencyLoader.printStream = libPrint:NewStream("DependencyLoader", "DpLdr", print) -DependencyLoader.debugStream = libPrint:NewStream("DependencyLoader", "DpLdr", "mcm") - --- temp -DependencyLoader.classes = addonTable.classes - -function DependencyLoader:Print(...) - self.printStream:Print(...) -end - - -function DependencyLoader:Debug(...) - self.debugStream:Print(...) -end - - -function DependencyLoader:OnInitialize() - self:Debug("Initializing and enabling", addonName) - self:Enable() -end - - -function DependencyLoader:OnEnable() - self.core = addonTable.classes.Core:New() - - self:Print("Enabled", addonName) - - self:FixCurrentAddons() -end - -function DependencyLoader:OnDisable() - self:Print("Disabled", addonName) -end - - --- TODO: move this into core? - --- Enables any dependencies needed by the addons --- that have already been enabled -function DependencyLoader:FixCurrentAddons() - local core = self.core - - for i=1, GetNumAddOns() do - local addon = self.core:GetAddon(i) - - if addon:IsEnabled() then - if addon:IsLoaded() then - -- TODO: it might still help to enable its embeds - else - self:Debug("Checking", addon:GetName()) - - if addonTable.classes.Core:ForceLoadAvailable() then - if core:CanForceLoadTree(addon:GetName()) then - core:ForceLoadTree(addon:GetName()) - else - print("Can't force load", addon:GetName()) - end - else - if core:CanLoDTree(addon:GetName()) then - core:PrepareLoDTree(addon:GetName()) - else - print("Couldn't load", addon:GetName(), "on demand.") - end - end - end - end - end -end - - - - - \ No newline at end of file
--- a/DependencyLoader_Core/load.xml Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -<ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> <script file="start.lua"/> <script file="class.lua"/> <script file="Addon.lua"/> <script file="Core.lua"/> <script file="frontend.lua"/> </ui> \ No newline at end of file
--- a/DependencyLoader_Core/start.lua Sat Dec 04 23:05:34 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ --- start.lua --- Initializes components of DependencyLoader - - -local addonName, addonTable = ... - - -print( string.format([[running %s\start.lua]], addonName) ) - --- NOTE: We don't have to check if this module's dependencies --- are available: it lists them normally in its .toc file and --- the bootstrap module will take care of enabling them first. - --- prepare output functions -local lp = LibStub("LibPrint-1.0") -local printStream = lp:NewStream("DependencyLoader", "DepLoader", "DepLdr", print) -local debugStream = lp:NewStream("DependencyLoader", "DepLoader", "DepLdr", "mcm") - -addonTable.print = function(...) printStream:Print(...) end -addonTable.debug = function(...) debugStream:Print(...) end -