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