annotate DependencyLoader/DependencyLoader.lua @ 15:a46bf694050c

cleaned up Tree's methods a bit and improved documentation Addon:Exists will now return false for Blizzard addons (needs to be handled better) Addon.lua will now use the raw hooks from the interface module fixed the inverted returns from IsForceLoadAvailable EnableAddOn and LoadAddOn hooks will now skip the extra processing if the addon does not exist or is a Blizzard addon moved the EnableAddOn queing to the interface
author mckenziemc
date Sat, 11 Dec 2010 01:48:39 -0800
parents 78b28ebdc169
children
rev   line source
mckenziemc@10 1 -- DependencyLoader
mckenziemc@0 2 --
mckenziemc@0 3
mckenziemc@15 4 -- TODO: disable bootstrap if we load successfully?
mckenziemc@12 5
mckenziemc@14 6 -- TODO: implement a feature to disable unneeded libraries when a parent
mckenziemc@14 7 -- is disabled?
mckenziemc@14 8
mckenziemc@0 9 local addonName, addonTable = ...
mckenziemc@0 10
mckenziemc@0 11
mckenziemc@15 12 local DependencyLoader = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceHook-3.0", "AceEvent-3.0")
mckenziemc@0 13 _G[addonName] = DependencyLoader
mckenziemc@0 14
mckenziemc@10 15 addonTable.interface = DependencyLoader
mckenziemc@10 16
mckenziemc@15 17 local classes = addonTable.classes
mckenziemc@15 18
mckenziemc@10 19
mckenziemc@12 20 local LibPrint = LibStub("LibPrint-1.0")
mckenziemc@10 21 local LibScriptLink = LibStub("LibScriptLink-1.0")
mckenziemc@10 22
mckenziemc@12 23 DependencyLoader.printStream = LibPrint:NewStream("DependencyLoader", "DpLdr", print)
mckenziemc@12 24 DependencyLoader.debugStream = LibPrint:NewStream("DependencyLoader", "DpLdr", "mcm")
mckenziemc@0 25
mckenziemc@15 26 DependencyLoader.queuedEnables = {} -- addons queued to be enabled after PLAYER_LOGIN
mckenziemc@15 27
mckenziemc@0 28
mckenziemc@0 29 function DependencyLoader:Print(...)
mckenziemc@0 30 self.printStream:Print(...)
mckenziemc@0 31 end
mckenziemc@0 32
mckenziemc@0 33
mckenziemc@0 34 function DependencyLoader:Debug(...)
mckenziemc@0 35 self.debugStream:Print(...)
mckenziemc@0 36 end
mckenziemc@0 37
mckenziemc@0 38
mckenziemc@0 39 function DependencyLoader:OnInitialize()
mckenziemc@10 40 self:Debug("Initializing", addonName)
mckenziemc@0 41 self:Enable()
mckenziemc@0 42 end
mckenziemc@0 43
mckenziemc@0 44
mckenziemc@0 45 function DependencyLoader:OnEnable()
mckenziemc@15 46 -- this may get called early so don't rely on
mckenziemc@15 47 -- it as an indicator for PLAYER_LOGIN
mckenziemc@15 48
mckenziemc@15 49 self:RegisterEvent("PLAYER_LOGIN")
mckenziemc@15 50
mckenziemc@12 51 self:RawHook("LoadAddOn", true)
mckenziemc@12 52 self:RawHook("EnableAddOn", true)
mckenziemc@12 53
mckenziemc@12 54 self:PrepareAllAddons()
mckenziemc@12 55
mckenziemc@10 56 self:Print("Enabled", addonName)
mckenziemc@0 57 end
mckenziemc@0 58
mckenziemc@10 59
mckenziemc@15 60 function DependencyLoader:PLAYER_LOGIN(...)
mckenziemc@15 61 self:Debug(...)
mckenziemc@15 62
mckenziemc@15 63 self:ProcessEnableQueue()
mckenziemc@15 64 end
mckenziemc@15 65
mckenziemc@15 66
mckenziemc@0 67 function DependencyLoader:OnDisable()
mckenziemc@0 68 self:Print("Disabled", addonName)
mckenziemc@0 69 end
mckenziemc@0 70
mckenziemc@0 71
mckenziemc@10 72 -- Does not consider user settings or addon errata.
mckenziemc@10 73 function DependencyLoader:IsForceLoadAvailable()
mckenziemc@15 74 if IsLoggedIn() then
mckenziemc@15 75 return false
mckenziemc@15 76 else
mckenziemc@15 77 return true
mckenziemc@15 78 end
mckenziemc@10 79 end
mckenziemc@10 80
mckenziemc@10 81
mckenziemc@10 82 function DependencyLoader:IsForceLoadAllowed()
mckenziemc@10 83 -- TODO: check user settings
mckenziemc@10 84 return true
mckenziemc@10 85 end
mckenziemc@10 86
mckenziemc@10 87
mckenziemc@10 88 function DependencyLoader:CanForceLoad()
mckenziemc@10 89 return self:IsForceLoadAvailable() and self:IsForceLoadAllowed()
mckenziemc@10 90 end
mckenziemc@10 91
mckenziemc@0 92
mckenziemc@0 93 -- Enables any dependencies needed by the addons
mckenziemc@0 94 -- that have already been enabled
mckenziemc@12 95 function DependencyLoader:PrepareAllAddons()
mckenziemc@10 96 local requestReload = false
mckenziemc@10 97
mckenziemc@0 98 for i=1, GetNumAddOns() do
mckenziemc@15 99 local addon = classes.Addon:Get(i)
mckenziemc@0 100
mckenziemc@10 101 -- TODO: what if an addon was loaded but its deps were then disabled?
mckenziemc@10 102 if addon:IsEnabled() and not addon:IsLoaded() then
mckenziemc@12 103 self:EnableAddOn(addon:GetName())
mckenziemc@0 104 end
mckenziemc@0 105 end
mckenziemc@10 106
mckenziemc@12 107 --[[
mckenziemc@10 108 if requestReload then
mckenziemc@10 109 local message = LibScriptLink:NewLink(ReloadUI) .. " to reload your UI."
mckenziemc@10 110 self:Print(message)
mckenziemc@10 111 end
mckenziemc@12 112 ]]
mckenziemc@0 113 end
mckenziemc@10 114
mckenziemc@10 115
mckenziemc@15 116 -- FIXME: use pcall in EnableAddOn and LoadAddOn, so that if my part errors,
mckenziemc@15 117 -- it can still use the unhooked version
mckenziemc@15 118
mckenziemc@10 119 function DependencyLoader:EnableAddOn(...)
mckenziemc@12 120 local id = ...
mckenziemc@12 121
mckenziemc@15 122 self:Debug("EnableAddOn", ...)
mckenziemc@12 123
mckenziemc@15 124 -- even though we know EnableAddOn can cause force-loading before PLAYER_LOGIN,
mckenziemc@15 125 -- DO NOT attempt to "fix" it: another addon that -does- know about
mckenziemc@15 126 -- the different behavior might call our hook.
mckenziemc@15 127
mckenziemc@15 128 if classes.Addon:Exists(id) then
mckenziemc@15 129 local addon = classes.Addon:Get(id)
mckenziemc@15 130 local tree = classes.Tree:Get(addon)
mckenziemc@12 131
mckenziemc@15 132 local requestReload = false
mckenziemc@12 133
mckenziemc@15 134 if self:CanForceLoad() then
mckenziemc@15 135 -- NOTE: if we can force-load, then will enabling LoD addons cause them to load too?
mckenziemc@15 136 -- A: no, they will still wait for LoadAddOn
mckenziemc@15 137
mckenziemc@15 138 -- Can the addon be loaded on demand if force-loading is
mckenziemc@15 139 -- allowed for its dependencies
mckenziemc@15 140 -- if so, enable all deps and force-load if nec.
mckenziemc@15 141 -- deps will get enabled if all parents are lod, force-loaded
mckenziemc@15 142 -- if any parent can't be loaded on demand
mckenziemc@15 143 -- else
mckenziemc@15 144 -- if the addon is not loadable on demand but the tree can be
mckenziemc@15 145 -- force-loaded, then force-load it all
mckenziemc@15 146 -- deps will all get loaded since req. for root to load
mckenziemc@15 147 -- else
mckenziemc@15 148 -- if it can be loaded with a reloadui then prepare after login
mckenziemc@15 149 -- else
mckenziemc@15 150 -- it can't be loaded, maybe tell the user
mckenziemc@15 151
mckenziemc@15 152 if tree:CanForceLoad() then
mckenziemc@15 153 if addon:CanLoD() then
mckenziemc@15 154 tree:PrepareForLoD()
mckenziemc@15 155 else
mckenziemc@15 156 tree:ForceLoad()
mckenziemc@15 157 end
mckenziemc@15 158 elseif tree:CanLoad() then
mckenziemc@15 159 tree:PrepareForLoad()
mckenziemc@15 160 requestReload = true
mckenziemc@15 161 else
mckenziemc@15 162 -- TODO: tell user
mckenziemc@15 163 end
mckenziemc@15 164
mckenziemc@15 165
mckenziemc@15 166 --[[
mckenziemc@15 167 if tree:CanLoDWithForce() then
mckenziemc@15 168 tree:PrepareForLoD()
mckenziemc@15 169 elseif tree:CanForceLoad() then
mckenziemc@15 170 tree:ForceLoad()
mckenziemc@15 171 elseif tree:CanLoad() then
mckenziemc@15 172 tree:PrepareForLoad()
mckenziemc@15 173 requestReload = true
mckenziemc@15 174 else
mckenziemc@15 175 -- TODO: tell user
mckenziemc@15 176 end
mckenziemc@15 177 ]]
mckenziemc@12 178 else
mckenziemc@15 179 -- if it can be loaded on demand (deps are loaded or LoD) then
mckenziemc@15 180 -- prepare it (enable all deps)
mckenziemc@15 181 -- else
mckenziemc@15 182 -- if it can be loaded (and isn't already) then
mckenziemc@15 183 -- if force loading is available, we have to wait, then enable everything
mckenziemc@15 184 -- else
mckenziemc@15 185 -- prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT)
mckenziemc@15 186 -- else
mckenziemc@15 187 -- can't be loaded, maybe tell the user
mckenziemc@15 188
mckenziemc@15 189 if tree:CanLoD() then
mckenziemc@15 190 tree:PrepareForLoad()
mckenziemc@15 191 -- don't actually intend to reload, just enable everything
mckenziemc@15 192 elseif tree:CanLoad() then
mckenziemc@15 193 tree:PrepareForLoad()
mckenziemc@15 194 requestReload = true
mckenziemc@15 195 else
mckenziemc@15 196 -- TODO: tell user
mckenziemc@15 197 end
mckenziemc@12 198 end
mckenziemc@12 199
mckenziemc@15 200 if requestReload then
mckenziemc@15 201 self:RequestReload()
mckenziemc@12 202 end
mckenziemc@12 203 end
mckenziemc@12 204
mckenziemc@15 205 -- propogate the call even if it doesn't exist or deps are unavailable
mckenziemc@12 206 return self.hooks.EnableAddOn(...)
mckenziemc@10 207 end
mckenziemc@12 208
mckenziemc@12 209
mckenziemc@12 210
mckenziemc@12 211 --- Prepares the addon tree rooted at the specified addon
mckenziemc@12 212 function DependencyLoader:LoadAddOn(...)
mckenziemc@12 213 local id = ...
mckenziemc@12 214
mckenziemc@15 215 self:Debug("LoadAddOn", ...)
mckenziemc@12 216
mckenziemc@15 217 if classes.Addon:Exists(id) then
mckenziemc@15 218 local addon = classes.Addon:Get(id)
mckenziemc@15 219 local tree = classes.Tree:Get(addon)
mckenziemc@12 220
mckenziemc@12 221 if tree:CanLoD() then
mckenziemc@12 222 tree:PrepareForLoD()
mckenziemc@12 223 elseif tree:CanLoad() then
mckenziemc@12 224 tree:PrepareForReload()
mckenziemc@12 225 end
mckenziemc@12 226 end
mckenziemc@12 227
mckenziemc@12 228 -- call even if it can't be loaded so regular returns appear
mckenziemc@12 229 return self.hooks.LoadAddOn(...)
mckenziemc@12 230 end
mckenziemc@15 231
mckenziemc@15 232
mckenziemc@15 233 function DependencyLoader:RequestReload()
mckenziemc@15 234 -- TODO: this should only run once
mckenziemc@15 235 end
mckenziemc@15 236
mckenziemc@15 237
mckenziemc@15 238 function DependencyLoader:QueueEnable(name)
mckenziemc@15 239 self.queuedEnables[name] = true
mckenziemc@15 240 end
mckenziemc@15 241
mckenziemc@15 242
mckenziemc@15 243 function DependencyLoader:RawEnableAddOn(...)
mckenziemc@15 244 return self.hooks.EnableAddOn(...)
mckenziemc@15 245 end
mckenziemc@15 246
mckenziemc@15 247
mckenziemc@15 248 function DependencyLoader:RawLoadAddOn(...)
mckenziemc@15 249 return self.hooks.LoadAddOn(...)
mckenziemc@15 250 end
mckenziemc@15 251
mckenziemc@15 252
mckenziemc@15 253 function DependencyLoader:ProcessEnableQueue()
mckenziemc@15 254 for addon in pairs(self.queuedEnables) do
mckenziemc@15 255 self:RawEnableAddOn(addon)
mckenziemc@15 256 self.queuedEnables[addon] = nil
mckenziemc@15 257 end
mckenziemc@15 258 end