annotate modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.lua @ 28:21bcaf8215ff

- converted to Ace3 - rearranged file layout - configGUI menus not working right now
author Flick <flickerstreak@gmail.com>
date Mon, 17 Mar 2008 18:24:53 +0000
parents
children
rev   line source
flickerstreak@28 1 --[[
flickerstreak@28 2 Name: AceLibrary
flickerstreak@28 3 Revision: $Rev: 49421 $
flickerstreak@28 4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
flickerstreak@28 5 Inspired By: Iriel (iriel@vigilance-committee.org)
flickerstreak@28 6 Tekkub (tekkub@gmail.com)
flickerstreak@28 7 Revision: $Rev: 49421 $
flickerstreak@28 8 Website: http://www.wowace.com/
flickerstreak@28 9 Documentation: http://www.wowace.com/index.php/AceLibrary
flickerstreak@28 10 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
flickerstreak@28 11 Description: Versioning library to handle other library instances, upgrading,
flickerstreak@28 12 and proper access.
flickerstreak@28 13 It also provides a base for libraries to work off of, providing
flickerstreak@28 14 proper error tools. It is handy because all the errors occur in the
flickerstreak@28 15 file that called it, not in the library file itself.
flickerstreak@28 16 Dependencies: None
flickerstreak@28 17 License: LGPL v2.1
flickerstreak@28 18 ]]
flickerstreak@28 19
flickerstreak@28 20 local ACELIBRARY_MAJOR = "AceLibrary"
flickerstreak@28 21 local ACELIBRARY_MINOR = "$Revision: 49421 $"
flickerstreak@28 22
flickerstreak@28 23 local _G = getfenv(0)
flickerstreak@28 24 local previous = _G[ACELIBRARY_MAJOR]
flickerstreak@28 25 if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
flickerstreak@28 26
flickerstreak@28 27 do
flickerstreak@28 28 -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
flickerstreak@28 29 -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
flickerstreak@28 30 local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
flickerstreak@28 31 local LibStub = _G[LIBSTUB_MAJOR]
flickerstreak@28 32
flickerstreak@28 33 if not LibStub or LibStub.minor < LIBSTUB_MINOR then
flickerstreak@28 34 LibStub = LibStub or {libs = {}, minors = {} }
flickerstreak@28 35 _G[LIBSTUB_MAJOR] = LibStub
flickerstreak@28 36 LibStub.minor = LIBSTUB_MINOR
flickerstreak@28 37
flickerstreak@28 38 function LibStub:NewLibrary(major, minor)
flickerstreak@28 39 assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
flickerstreak@28 40 minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
flickerstreak@28 41 local oldminor = self.minors[major]
flickerstreak@28 42 if oldminor and oldminor >= minor then return nil end
flickerstreak@28 43 self.minors[major], self.libs[major] = minor, self.libs[major] or {}
flickerstreak@28 44 return self.libs[major], oldminor
flickerstreak@28 45 end
flickerstreak@28 46
flickerstreak@28 47 function LibStub:GetLibrary(major, silent)
flickerstreak@28 48 if not self.libs[major] and not silent then
flickerstreak@28 49 error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
flickerstreak@28 50 end
flickerstreak@28 51 return self.libs[major], self.minors[major]
flickerstreak@28 52 end
flickerstreak@28 53
flickerstreak@28 54 function LibStub:IterateLibraries() return pairs(self.libs) end
flickerstreak@28 55 setmetatable(LibStub, { __call = LibStub.GetLibrary })
flickerstreak@28 56 end
flickerstreak@28 57 end
flickerstreak@28 58 local LibStub = _G.LibStub
flickerstreak@28 59
flickerstreak@28 60 -- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
flickerstreak@28 61 -- disabled in the addon screen, set this to true.
flickerstreak@28 62 local DONT_ENABLE_LIBRARIES = nil
flickerstreak@28 63
flickerstreak@28 64 local function safecall(func,...)
flickerstreak@28 65 local success, err = pcall(func,...)
flickerstreak@28 66 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
flickerstreak@28 67 end
flickerstreak@28 68
flickerstreak@28 69 local WoW22 = false
flickerstreak@28 70 if type(GetBuildInfo) == "function" then
flickerstreak@28 71 local success, buildinfo = pcall(GetBuildInfo)
flickerstreak@28 72 if success and type(buildinfo) == "string" then
flickerstreak@28 73 local num = tonumber(buildinfo:match("^(%d+%.%d+)"))
flickerstreak@28 74 if num and num >= 2.2 then
flickerstreak@28 75 WoW22 = true
flickerstreak@28 76 end
flickerstreak@28 77 end
flickerstreak@28 78 end
flickerstreak@28 79
flickerstreak@28 80 -- @table AceLibrary
flickerstreak@28 81 -- @brief System to handle all versioning of libraries.
flickerstreak@28 82 local AceLibrary = {}
flickerstreak@28 83 local AceLibrary_mt = {}
flickerstreak@28 84 setmetatable(AceLibrary, AceLibrary_mt)
flickerstreak@28 85
flickerstreak@28 86 local function error(self, message, ...)
flickerstreak@28 87 if type(self) ~= "table" then
flickerstreak@28 88 return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
flickerstreak@28 89 end
flickerstreak@28 90
flickerstreak@28 91 local stack = debugstack()
flickerstreak@28 92 if not message then
flickerstreak@28 93 local second = stack:match("\n(.-)\n")
flickerstreak@28 94 message = "error raised! " .. second
flickerstreak@28 95 else
flickerstreak@28 96 local arg = { ... } -- not worried about table creation, as errors don't happen often
flickerstreak@28 97
flickerstreak@28 98 for i = 1, #arg do
flickerstreak@28 99 arg[i] = tostring(arg[i])
flickerstreak@28 100 end
flickerstreak@28 101 for i = 1, 10 do
flickerstreak@28 102 table.insert(arg, "nil")
flickerstreak@28 103 end
flickerstreak@28 104 message = message:format(unpack(arg))
flickerstreak@28 105 end
flickerstreak@28 106
flickerstreak@28 107 if getmetatable(self) and getmetatable(self).__tostring then
flickerstreak@28 108 message = ("%s: %s"):format(tostring(self), message)
flickerstreak@28 109 elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
flickerstreak@28 110 message = ("%s: %s"):format(self:GetLibraryVersion(), message)
flickerstreak@28 111 elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
flickerstreak@28 112 message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
flickerstreak@28 113 end
flickerstreak@28 114
flickerstreak@28 115 local first = stack:gsub("\n.*", "")
flickerstreak@28 116 local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
flickerstreak@28 117 file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
flickerstreak@28 118
flickerstreak@28 119
flickerstreak@28 120 local i = 0
flickerstreak@28 121 for s in stack:gmatch("\n([^\n]*)") do
flickerstreak@28 122 i = i + 1
flickerstreak@28 123 if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
flickerstreak@28 124 file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
flickerstreak@28 125 file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
flickerstreak@28 126 break
flickerstreak@28 127 end
flickerstreak@28 128 end
flickerstreak@28 129 local j = 0
flickerstreak@28 130 for s in stack:gmatch("\n([^\n]*)") do
flickerstreak@28 131 j = j + 1
flickerstreak@28 132 if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
flickerstreak@28 133 return _G.error(message, j+1)
flickerstreak@28 134 end
flickerstreak@28 135 end
flickerstreak@28 136 return _G.error(message, 2)
flickerstreak@28 137 end
flickerstreak@28 138
flickerstreak@28 139 local assert
flickerstreak@28 140 if not WoW22 then
flickerstreak@28 141 function assert(self, condition, message, ...)
flickerstreak@28 142 if not condition then
flickerstreak@28 143 if not message then
flickerstreak@28 144 local stack = debugstack()
flickerstreak@28 145 local second = stack:match("\n(.-)\n")
flickerstreak@28 146 message = "assertion failed! " .. second
flickerstreak@28 147 end
flickerstreak@28 148 return error(self, message, ...)
flickerstreak@28 149 end
flickerstreak@28 150 return condition
flickerstreak@28 151 end
flickerstreak@28 152 end
flickerstreak@28 153
flickerstreak@28 154 local type = type
flickerstreak@28 155 local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
flickerstreak@28 156 if type(num) ~= "number" then
flickerstreak@28 157 return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
flickerstreak@28 158 elseif type(kind) ~= "string" then
flickerstreak@28 159 return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
flickerstreak@28 160 end
flickerstreak@28 161 arg = type(arg)
flickerstreak@28 162 if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
flickerstreak@28 163 local stack = debugstack()
flickerstreak@28 164 local func = stack:match("`argCheck'.-([`<].-['>])")
flickerstreak@28 165 if not func then
flickerstreak@28 166 func = stack:match("([`<].-['>])")
flickerstreak@28 167 end
flickerstreak@28 168 if kind5 then
flickerstreak@28 169 return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
flickerstreak@28 170 elseif kind4 then
flickerstreak@28 171 return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
flickerstreak@28 172 elseif kind3 then
flickerstreak@28 173 return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
flickerstreak@28 174 elseif kind2 then
flickerstreak@28 175 return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
flickerstreak@28 176 else
flickerstreak@28 177 return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
flickerstreak@28 178 end
flickerstreak@28 179 end
flickerstreak@28 180 end
flickerstreak@28 181
flickerstreak@28 182 local pcall
flickerstreak@28 183 do
flickerstreak@28 184 local function check(self, ret, ...)
flickerstreak@28 185 if not ret then
flickerstreak@28 186 local s = ...
flickerstreak@28 187 return error(self, (s:gsub(".-%.lua:%d-: ", "")))
flickerstreak@28 188 else
flickerstreak@28 189 return ...
flickerstreak@28 190 end
flickerstreak@28 191 end
flickerstreak@28 192
flickerstreak@28 193 function pcall(self, func, ...)
flickerstreak@28 194 return check(self, _G.pcall(func, ...))
flickerstreak@28 195 end
flickerstreak@28 196 end
flickerstreak@28 197
flickerstreak@28 198 local recurse = {}
flickerstreak@28 199 local function addToPositions(t, major)
flickerstreak@28 200 if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
flickerstreak@28 201 rawset(t, recurse, true)
flickerstreak@28 202 AceLibrary.positions[t] = major
flickerstreak@28 203 for k,v in pairs(t) do
flickerstreak@28 204 if type(v) == "table" and not rawget(v, recurse) then
flickerstreak@28 205 addToPositions(v, major)
flickerstreak@28 206 end
flickerstreak@28 207 if type(k) == "table" and not rawget(k, recurse) then
flickerstreak@28 208 addToPositions(k, major)
flickerstreak@28 209 end
flickerstreak@28 210 end
flickerstreak@28 211 local mt = getmetatable(t)
flickerstreak@28 212 if mt and not rawget(mt, recurse) then
flickerstreak@28 213 addToPositions(mt, major)
flickerstreak@28 214 end
flickerstreak@28 215 rawset(t, recurse, nil)
flickerstreak@28 216 end
flickerstreak@28 217 end
flickerstreak@28 218
flickerstreak@28 219 local function svnRevisionToNumber(text)
flickerstreak@28 220 local kind = type(text)
flickerstreak@28 221 if kind == "number" or tonumber(text) then
flickerstreak@28 222 return tonumber(text)
flickerstreak@28 223 elseif kind == "string" then
flickerstreak@28 224 if text:find("^%$Revision: (%d+) %$$") then
flickerstreak@28 225 return tonumber((text:match("^%$Revision: (%d+) %$$")))
flickerstreak@28 226 elseif text:find("^%$Rev: (%d+) %$$") then
flickerstreak@28 227 return tonumber((text:match("^%$Rev: (%d+) %$$")))
flickerstreak@28 228 elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
flickerstreak@28 229 return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
flickerstreak@28 230 end
flickerstreak@28 231 end
flickerstreak@28 232 return nil
flickerstreak@28 233 end
flickerstreak@28 234
flickerstreak@28 235 local crawlReplace
flickerstreak@28 236 do
flickerstreak@28 237 local recurse = {}
flickerstreak@28 238 local function func(t, to, from)
flickerstreak@28 239 if recurse[t] then
flickerstreak@28 240 return
flickerstreak@28 241 end
flickerstreak@28 242 recurse[t] = true
flickerstreak@28 243 local mt = getmetatable(t)
flickerstreak@28 244 setmetatable(t, nil)
flickerstreak@28 245 rawset(t, to, rawget(t, from))
flickerstreak@28 246 rawset(t, from, nil)
flickerstreak@28 247 for k,v in pairs(t) do
flickerstreak@28 248 if v == from then
flickerstreak@28 249 t[k] = to
flickerstreak@28 250 elseif type(v) == "table" then
flickerstreak@28 251 if not recurse[v] then
flickerstreak@28 252 func(v, to, from)
flickerstreak@28 253 end
flickerstreak@28 254 end
flickerstreak@28 255
flickerstreak@28 256 if type(k) == "table" then
flickerstreak@28 257 if not recurse[k] then
flickerstreak@28 258 func(k, to, from)
flickerstreak@28 259 end
flickerstreak@28 260 end
flickerstreak@28 261 end
flickerstreak@28 262 setmetatable(t, mt)
flickerstreak@28 263 if mt then
flickerstreak@28 264 if mt == from then
flickerstreak@28 265 setmetatable(t, to)
flickerstreak@28 266 elseif not recurse[mt] then
flickerstreak@28 267 func(mt, to, from)
flickerstreak@28 268 end
flickerstreak@28 269 end
flickerstreak@28 270 end
flickerstreak@28 271 function crawlReplace(t, to, from)
flickerstreak@28 272 func(t, to, from)
flickerstreak@28 273 for k in pairs(recurse) do
flickerstreak@28 274 recurse[k] = nil
flickerstreak@28 275 end
flickerstreak@28 276 end
flickerstreak@28 277 end
flickerstreak@28 278
flickerstreak@28 279 -- @function destroyTable
flickerstreak@28 280 -- @brief remove all the contents of a table
flickerstreak@28 281 -- @param t table to destroy
flickerstreak@28 282 local function destroyTable(t)
flickerstreak@28 283 setmetatable(t, nil)
flickerstreak@28 284 for k,v in pairs(t) do
flickerstreak@28 285 t[k] = nil
flickerstreak@28 286 end
flickerstreak@28 287 end
flickerstreak@28 288
flickerstreak@28 289 local function isFrame(frame)
flickerstreak@28 290 return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
flickerstreak@28 291 end
flickerstreak@28 292
flickerstreak@28 293 -- @function copyTable
flickerstreak@28 294 -- @brief Create a shallow copy of a table and return it.
flickerstreak@28 295 -- @param from The table to copy from
flickerstreak@28 296 -- @return A shallow copy of the table
flickerstreak@28 297 local function copyTable(from, to)
flickerstreak@28 298 if not to then
flickerstreak@28 299 to = {}
flickerstreak@28 300 end
flickerstreak@28 301 for k,v in pairs(from) do
flickerstreak@28 302 to[k] = v
flickerstreak@28 303 end
flickerstreak@28 304 setmetatable(to, getmetatable(from))
flickerstreak@28 305 return to
flickerstreak@28 306 end
flickerstreak@28 307
flickerstreak@28 308 -- @function deepTransfer
flickerstreak@28 309 -- @brief Fully transfer all data, keeping proper previous table
flickerstreak@28 310 -- backreferences stable.
flickerstreak@28 311 -- @param to The table with which data is to be injected into
flickerstreak@28 312 -- @param from The table whose data will be injected into the first
flickerstreak@28 313 -- @param saveFields If available, a shallow copy of the basic data is saved
flickerstreak@28 314 -- in here.
flickerstreak@28 315 -- @param list The account of table references
flickerstreak@28 316 -- @param list2 The current status on which tables have been traversed.
flickerstreak@28 317 local deepTransfer
flickerstreak@28 318 do
flickerstreak@28 319 -- @function examine
flickerstreak@28 320 -- @brief Take account of all the table references to be shared
flickerstreak@28 321 -- between the to and from tables.
flickerstreak@28 322 -- @param to The table with which data is to be injected into
flickerstreak@28 323 -- @param from The table whose data will be injected into the first
flickerstreak@28 324 -- @param list An account of the table references
flickerstreak@28 325 local function examine(to, from, list, major)
flickerstreak@28 326 list[from] = to
flickerstreak@28 327 for k,v in pairs(from) do
flickerstreak@28 328 if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
flickerstreak@28 329 if from[k] == to[k] then
flickerstreak@28 330 list[from[k]] = to[k]
flickerstreak@28 331 elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
flickerstreak@28 332 list[from[k]] = from[k]
flickerstreak@28 333 elseif not list[from[k]] then
flickerstreak@28 334 examine(to[k], from[k], list, major)
flickerstreak@28 335 end
flickerstreak@28 336 end
flickerstreak@28 337 end
flickerstreak@28 338 return list
flickerstreak@28 339 end
flickerstreak@28 340
flickerstreak@28 341 function deepTransfer(to, from, saveFields, major, list, list2)
flickerstreak@28 342 setmetatable(to, nil)
flickerstreak@28 343 if not list then
flickerstreak@28 344 list = {}
flickerstreak@28 345 list2 = {}
flickerstreak@28 346 examine(to, from, list, major)
flickerstreak@28 347 end
flickerstreak@28 348 list2[to] = to
flickerstreak@28 349 for k,v in pairs(to) do
flickerstreak@28 350 if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
flickerstreak@28 351 if saveFields then
flickerstreak@28 352 saveFields[k] = v
flickerstreak@28 353 end
flickerstreak@28 354 to[k] = nil
flickerstreak@28 355 elseif v ~= _G then
flickerstreak@28 356 if saveFields then
flickerstreak@28 357 saveFields[k] = copyTable(v)
flickerstreak@28 358 end
flickerstreak@28 359 end
flickerstreak@28 360 end
flickerstreak@28 361 for k in pairs(from) do
flickerstreak@28 362 if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
flickerstreak@28 363 if not list2[to[k]] then
flickerstreak@28 364 deepTransfer(to[k], from[k], nil, major, list, list2)
flickerstreak@28 365 end
flickerstreak@28 366 to[k] = list[to[k]] or list2[to[k]]
flickerstreak@28 367 else
flickerstreak@28 368 rawset(to, k, from[k])
flickerstreak@28 369 end
flickerstreak@28 370 end
flickerstreak@28 371 setmetatable(to, getmetatable(from))
flickerstreak@28 372 local mt = getmetatable(to)
flickerstreak@28 373 if mt then
flickerstreak@28 374 if list[mt] then
flickerstreak@28 375 setmetatable(to, list[mt])
flickerstreak@28 376 elseif mt.__index and list[mt.__index] then
flickerstreak@28 377 mt.__index = list[mt.__index]
flickerstreak@28 378 end
flickerstreak@28 379 end
flickerstreak@28 380 destroyTable(from)
flickerstreak@28 381 end
flickerstreak@28 382 end
flickerstreak@28 383
flickerstreak@28 384 local function TryToEnable(addon)
flickerstreak@28 385 if DONT_ENABLE_LIBRARIES then return end
flickerstreak@28 386 local isondemand = IsAddOnLoadOnDemand(addon)
flickerstreak@28 387 if isondemand then
flickerstreak@28 388 local _, _, _, enabled = GetAddOnInfo(addon)
flickerstreak@28 389 EnableAddOn(addon)
flickerstreak@28 390 local _, _, _, _, loadable = GetAddOnInfo(addon)
flickerstreak@28 391 if not loadable and not enabled then
flickerstreak@28 392 DisableAddOn(addon)
flickerstreak@28 393 end
flickerstreak@28 394
flickerstreak@28 395 return loadable
flickerstreak@28 396 end
flickerstreak@28 397 end
flickerstreak@28 398
flickerstreak@28 399 -- @method TryToLoadStandalone
flickerstreak@28 400 -- @brief Attempt to find and load a standalone version of the requested library
flickerstreak@28 401 -- @param major A string representing the major version
flickerstreak@28 402 -- @return If library is found and loaded, true is return. If not loadable, false is returned.
flickerstreak@28 403 -- If the library has been requested previously, nil is returned.
flickerstreak@28 404 local function TryToLoadStandalone(major)
flickerstreak@28 405 if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
flickerstreak@28 406 if AceLibrary.scannedlibs[major] then return end
flickerstreak@28 407
flickerstreak@28 408 AceLibrary.scannedlibs[major] = true
flickerstreak@28 409
flickerstreak@28 410 local name, _, _, enabled, loadable = GetAddOnInfo(major)
flickerstreak@28 411
flickerstreak@28 412 loadable = (enabled and loadable) or TryToEnable(name)
flickerstreak@28 413
flickerstreak@28 414 local loaded = false
flickerstreak@28 415 if loadable then
flickerstreak@28 416 loaded = true
flickerstreak@28 417 LoadAddOn(name)
flickerstreak@28 418 end
flickerstreak@28 419
flickerstreak@28 420 local field = "X-AceLibrary-" .. major
flickerstreak@28 421 for i = 1, GetNumAddOns() do
flickerstreak@28 422 if GetAddOnMetadata(i, field) then
flickerstreak@28 423 name, _, _, enabled, loadable = GetAddOnInfo(i)
flickerstreak@28 424
flickerstreak@28 425 loadable = (enabled and loadable) or TryToEnable(name)
flickerstreak@28 426 if loadable then
flickerstreak@28 427 loaded = true
flickerstreak@28 428 LoadAddOn(name)
flickerstreak@28 429 end
flickerstreak@28 430 end
flickerstreak@28 431 end
flickerstreak@28 432 return loaded
flickerstreak@28 433 end
flickerstreak@28 434
flickerstreak@28 435 -- @method IsNewVersion
flickerstreak@28 436 -- @brief Obtain whether the supplied version would be an upgrade to the
flickerstreak@28 437 -- current version. This allows for bypass code in library
flickerstreak@28 438 -- declaration.
flickerstreak@28 439 -- @param major A string representing the major version
flickerstreak@28 440 -- @param minor An integer or an svn revision string representing the minor version
flickerstreak@28 441 -- @return whether the supplied version would be newer than what is
flickerstreak@28 442 -- currently available.
flickerstreak@28 443 function AceLibrary:IsNewVersion(major, minor)
flickerstreak@28 444 argCheck(self, major, 2, "string")
flickerstreak@28 445 TryToLoadStandalone(major)
flickerstreak@28 446
flickerstreak@28 447 if type(minor) == "string" then
flickerstreak@28 448 local m = svnRevisionToNumber(minor)
flickerstreak@28 449 if m then
flickerstreak@28 450 minor = m
flickerstreak@28 451 else
flickerstreak@28 452 _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
flickerstreak@28 453 end
flickerstreak@28 454 end
flickerstreak@28 455 argCheck(self, minor, 3, "number")
flickerstreak@28 456 local lib, oldMinor = LibStub:GetLibrary(major, true)
flickerstreak@28 457 if lib then
flickerstreak@28 458 return oldMinor < minor
flickerstreak@28 459 end
flickerstreak@28 460 local data = self.libs[major]
flickerstreak@28 461 if not data then
flickerstreak@28 462 return true
flickerstreak@28 463 end
flickerstreak@28 464 return data.minor < minor
flickerstreak@28 465 end
flickerstreak@28 466
flickerstreak@28 467 -- @method HasInstance
flickerstreak@28 468 -- @brief Returns whether an instance exists. This allows for optional support of a library.
flickerstreak@28 469 -- @param major A string representing the major version.
flickerstreak@28 470 -- @param minor (optional) An integer or an svn revision string representing the minor version.
flickerstreak@28 471 -- @return Whether an instance exists.
flickerstreak@28 472 function AceLibrary:HasInstance(major, minor)
flickerstreak@28 473 argCheck(self, major, 2, "string")
flickerstreak@28 474 if minor ~= false then
flickerstreak@28 475 TryToLoadStandalone(major)
flickerstreak@28 476 end
flickerstreak@28 477
flickerstreak@28 478 local lib, ver = LibStub:GetLibrary(major, true)
flickerstreak@28 479 if not lib and self.libs[major] then
flickerstreak@28 480 lib, ver = self.libs[major].instance, self.libs[major].minor
flickerstreak@28 481 end
flickerstreak@28 482 if minor then
flickerstreak@28 483 if type(minor) == "string" then
flickerstreak@28 484 local m = svnRevisionToNumber(minor)
flickerstreak@28 485 if m then
flickerstreak@28 486 minor = m
flickerstreak@28 487 else
flickerstreak@28 488 _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
flickerstreak@28 489 end
flickerstreak@28 490 end
flickerstreak@28 491 argCheck(self, minor, 3, "number")
flickerstreak@28 492 if not lib then
flickerstreak@28 493 return false
flickerstreak@28 494 end
flickerstreak@28 495 return ver == minor
flickerstreak@28 496 end
flickerstreak@28 497 return not not lib
flickerstreak@28 498 end
flickerstreak@28 499
flickerstreak@28 500 -- @method GetInstance
flickerstreak@28 501 -- @brief Returns the library with the given major/minor version.
flickerstreak@28 502 -- @param major A string representing the major version.
flickerstreak@28 503 -- @param minor (optional) An integer or an svn revision string representing the minor version.
flickerstreak@28 504 -- @return The library with the given major/minor version.
flickerstreak@28 505 function AceLibrary:GetInstance(major, minor)
flickerstreak@28 506 argCheck(self, major, 2, "string")
flickerstreak@28 507 if minor ~= false then
flickerstreak@28 508 TryToLoadStandalone(major)
flickerstreak@28 509 end
flickerstreak@28 510
flickerstreak@28 511 local data, ver = LibStub:GetLibrary(major, true)
flickerstreak@28 512 if not data then
flickerstreak@28 513 if self.libs[major] then
flickerstreak@28 514 data, ver = self.libs[major].instance, self.libs[major].minor
flickerstreak@28 515 else
flickerstreak@28 516 _G.error(("Cannot find a library instance of %s."):format(major), 2)
flickerstreak@28 517 return
flickerstreak@28 518 end
flickerstreak@28 519 end
flickerstreak@28 520 if minor then
flickerstreak@28 521 if type(minor) == "string" then
flickerstreak@28 522 local m = svnRevisionToNumber(minor)
flickerstreak@28 523 if m then
flickerstreak@28 524 minor = m
flickerstreak@28 525 else
flickerstreak@28 526 _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
flickerstreak@28 527 end
flickerstreak@28 528 end
flickerstreak@28 529 argCheck(self, minor, 2, "number")
flickerstreak@28 530 if ver ~= minor then
flickerstreak@28 531 _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
flickerstreak@28 532 end
flickerstreak@28 533 end
flickerstreak@28 534 return data
flickerstreak@28 535 end
flickerstreak@28 536
flickerstreak@28 537 -- Syntax sugar. AceLibrary("FooBar-1.0")
flickerstreak@28 538 AceLibrary_mt.__call = AceLibrary.GetInstance
flickerstreak@28 539
flickerstreak@28 540 local donothing = function() end
flickerstreak@28 541
flickerstreak@28 542 local AceEvent
flickerstreak@28 543
flickerstreak@28 544 local tmp = {}
flickerstreak@28 545
flickerstreak@28 546 -- @method Register
flickerstreak@28 547 -- @brief Registers a new version of a given library.
flickerstreak@28 548 -- @param newInstance the library to register
flickerstreak@28 549 -- @param major the major version of the library
flickerstreak@28 550 -- @param minor the minor version of the library
flickerstreak@28 551 -- @param activateFunc (optional) A function to be called when the library is
flickerstreak@28 552 -- fully activated. Takes the arguments
flickerstreak@28 553 -- (newInstance [, oldInstance, oldDeactivateFunc]). If
flickerstreak@28 554 -- oldInstance is given, you should probably call
flickerstreak@28 555 -- oldDeactivateFunc(oldInstance).
flickerstreak@28 556 -- @param deactivateFunc (optional) A function to be called by a newer library's
flickerstreak@28 557 -- activateFunc.
flickerstreak@28 558 -- @param externalFunc (optional) A function to be called whenever a new
flickerstreak@28 559 -- library is registered.
flickerstreak@28 560 function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
flickerstreak@28 561 argCheck(self, newInstance, 2, "table")
flickerstreak@28 562 argCheck(self, major, 3, "string")
flickerstreak@28 563 if major ~= ACELIBRARY_MAJOR then
flickerstreak@28 564 for k,v in pairs(_G) do
flickerstreak@28 565 if v == newInstance then
flickerstreak@28 566 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
flickerstreak@28 567 end
flickerstreak@28 568 end
flickerstreak@28 569 end
flickerstreak@28 570 if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
flickerstreak@28 571 _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
flickerstreak@28 572 end
flickerstreak@28 573 if type(minor) == "string" then
flickerstreak@28 574 local m = svnRevisionToNumber(minor)
flickerstreak@28 575 if m then
flickerstreak@28 576 minor = m
flickerstreak@28 577 else
flickerstreak@28 578 _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
flickerstreak@28 579 end
flickerstreak@28 580 end
flickerstreak@28 581 argCheck(self, minor, 4, "number")
flickerstreak@28 582 if math.floor(minor) ~= minor or minor < 0 then
flickerstreak@28 583 error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
flickerstreak@28 584 end
flickerstreak@28 585 argCheck(self, activateFunc, 5, "function", "nil")
flickerstreak@28 586 argCheck(self, deactivateFunc, 6, "function", "nil")
flickerstreak@28 587 argCheck(self, externalFunc, 7, "function", "nil")
flickerstreak@28 588 if not deactivateFunc then
flickerstreak@28 589 deactivateFunc = donothing
flickerstreak@28 590 end
flickerstreak@28 591 local data = self.libs[major]
flickerstreak@28 592 if not data then
flickerstreak@28 593 -- This is new
flickerstreak@28 594 if LibStub:GetLibrary(major, true) then
flickerstreak@28 595 error(self, "Cannot register library %q. It is already registered with LibStub.", major)
flickerstreak@28 596 end
flickerstreak@28 597 local instance = LibStub:NewLibrary(major, minor)
flickerstreak@28 598 copyTable(newInstance, instance)
flickerstreak@28 599 crawlReplace(instance, instance, newInstance)
flickerstreak@28 600 destroyTable(newInstance)
flickerstreak@28 601 if AceLibrary == newInstance then
flickerstreak@28 602 self = instance
flickerstreak@28 603 AceLibrary = instance
flickerstreak@28 604 end
flickerstreak@28 605 self.libs[major] = {
flickerstreak@28 606 instance = instance,
flickerstreak@28 607 minor = minor,
flickerstreak@28 608 deactivateFunc = deactivateFunc,
flickerstreak@28 609 externalFunc = externalFunc,
flickerstreak@28 610 }
flickerstreak@28 611 rawset(instance, 'GetLibraryVersion', function(self)
flickerstreak@28 612 return major, minor
flickerstreak@28 613 end)
flickerstreak@28 614 if not rawget(instance, 'error') then
flickerstreak@28 615 rawset(instance, 'error', error)
flickerstreak@28 616 end
flickerstreak@28 617 if not WoW22 and not rawget(instance, 'assert') then
flickerstreak@28 618 rawset(instance, 'assert', assert)
flickerstreak@28 619 end
flickerstreak@28 620 if not rawget(instance, 'argCheck') then
flickerstreak@28 621 rawset(instance, 'argCheck', argCheck)
flickerstreak@28 622 end
flickerstreak@28 623 if not rawget(instance, 'pcall') then
flickerstreak@28 624 rawset(instance, 'pcall', pcall)
flickerstreak@28 625 end
flickerstreak@28 626 addToPositions(instance, major)
flickerstreak@28 627 if activateFunc then
flickerstreak@28 628 safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
flickerstreak@28 629
flickerstreak@28 630 --[[ if major ~= ACELIBRARY_MAJOR then
flickerstreak@28 631 for k,v in pairs(_G) do
flickerstreak@28 632 if v == instance then
flickerstreak@28 633 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
flickerstreak@28 634 end
flickerstreak@28 635 end
flickerstreak@28 636 end]]
flickerstreak@28 637 end
flickerstreak@28 638
flickerstreak@28 639 if externalFunc then
flickerstreak@28 640 for k, data_instance in LibStub:IterateLibraries() do -- all libraries
flickerstreak@28 641 tmp[k] = data_instance
flickerstreak@28 642 end
flickerstreak@28 643 for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
flickerstreak@28 644 tmp[k] = data.instance
flickerstreak@28 645 end
flickerstreak@28 646 for k, data_instance in pairs(tmp) do
flickerstreak@28 647 if k ~= major then
flickerstreak@28 648 safecall(externalFunc, instance, k, data_instance)
flickerstreak@28 649 end
flickerstreak@28 650 tmp[k] = nil
flickerstreak@28 651 end
flickerstreak@28 652 end
flickerstreak@28 653
flickerstreak@28 654 for k,data in pairs(self.libs) do -- only Ace libraries
flickerstreak@28 655 if k ~= major and data.externalFunc then
flickerstreak@28 656 safecall(data.externalFunc, data.instance, major, instance)
flickerstreak@28 657 end
flickerstreak@28 658 end
flickerstreak@28 659 if major == "AceEvent-2.0" then
flickerstreak@28 660 AceEvent = instance
flickerstreak@28 661 end
flickerstreak@28 662 if AceEvent then
flickerstreak@28 663 AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
flickerstreak@28 664 end
flickerstreak@28 665
flickerstreak@28 666 return instance
flickerstreak@28 667 end
flickerstreak@28 668 if minor <= data.minor then
flickerstreak@28 669 -- This one is already obsolete, raise an error.
flickerstreak@28 670 _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
flickerstreak@28 671 return
flickerstreak@28 672 end
flickerstreak@28 673 local instance = data.instance
flickerstreak@28 674 -- This is an update
flickerstreak@28 675 local oldInstance = {}
flickerstreak@28 676
flickerstreak@28 677 local libStubInstance = LibStub:GetLibrary(major, true)
flickerstreak@28 678 if not libStubInstance then -- non-LibStub AceLibrary registered the library
flickerstreak@28 679 -- pass
flickerstreak@28 680 elseif libStubInstance ~= instance then
flickerstreak@28 681 error(self, "Cannot register library %q. It is already registered with LibStub.", major)
flickerstreak@28 682 else
flickerstreak@28 683 LibStub:NewLibrary(major, minor) -- upgrade the minor version
flickerstreak@28 684 end
flickerstreak@28 685
flickerstreak@28 686 addToPositions(newInstance, major)
flickerstreak@28 687 local isAceLibrary = (AceLibrary == newInstance)
flickerstreak@28 688 local old_error, old_assert, old_argCheck, old_pcall
flickerstreak@28 689 if isAceLibrary then
flickerstreak@28 690 self = instance
flickerstreak@28 691 AceLibrary = instance
flickerstreak@28 692
flickerstreak@28 693 old_error = instance.error
flickerstreak@28 694 if not WoW22 then
flickerstreak@28 695 old_assert = instance.assert
flickerstreak@28 696 end
flickerstreak@28 697 old_argCheck = instance.argCheck
flickerstreak@28 698 old_pcall = instance.pcall
flickerstreak@28 699
flickerstreak@28 700 self.error = error
flickerstreak@28 701 if not WoW22 then
flickerstreak@28 702 self.assert = assert
flickerstreak@28 703 end
flickerstreak@28 704 self.argCheck = argCheck
flickerstreak@28 705 self.pcall = pcall
flickerstreak@28 706 end
flickerstreak@28 707 deepTransfer(instance, newInstance, oldInstance, major)
flickerstreak@28 708 crawlReplace(instance, instance, newInstance)
flickerstreak@28 709 local oldDeactivateFunc = data.deactivateFunc
flickerstreak@28 710 data.minor = minor
flickerstreak@28 711 data.deactivateFunc = deactivateFunc
flickerstreak@28 712 data.externalFunc = externalFunc
flickerstreak@28 713 rawset(instance, 'GetLibraryVersion', function()
flickerstreak@28 714 return major, minor
flickerstreak@28 715 end)
flickerstreak@28 716 if not rawget(instance, 'error') then
flickerstreak@28 717 rawset(instance, 'error', error)
flickerstreak@28 718 end
flickerstreak@28 719 if not WoW22 and not rawget(instance, 'assert') then
flickerstreak@28 720 rawset(instance, 'assert', assert)
flickerstreak@28 721 end
flickerstreak@28 722 if not rawget(instance, 'argCheck') then
flickerstreak@28 723 rawset(instance, 'argCheck', argCheck)
flickerstreak@28 724 end
flickerstreak@28 725 if not rawget(instance, 'pcall') then
flickerstreak@28 726 rawset(instance, 'pcall', pcall)
flickerstreak@28 727 end
flickerstreak@28 728 if isAceLibrary then
flickerstreak@28 729 for _,v in pairs(self.libs) do
flickerstreak@28 730 local i = type(v) == "table" and v.instance
flickerstreak@28 731 if type(i) == "table" then
flickerstreak@28 732 if not rawget(i, 'error') or i.error == old_error then
flickerstreak@28 733 rawset(i, 'error', error)
flickerstreak@28 734 end
flickerstreak@28 735 if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then
flickerstreak@28 736 rawset(i, 'assert', assert)
flickerstreak@28 737 end
flickerstreak@28 738 if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
flickerstreak@28 739 rawset(i, 'argCheck', argCheck)
flickerstreak@28 740 end
flickerstreak@28 741 if not rawget(i, 'pcall') or i.pcall == old_pcall then
flickerstreak@28 742 rawset(i, 'pcall', pcall)
flickerstreak@28 743 end
flickerstreak@28 744 end
flickerstreak@28 745 end
flickerstreak@28 746 end
flickerstreak@28 747 if activateFunc then
flickerstreak@28 748 safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
flickerstreak@28 749
flickerstreak@28 750 --[[ if major ~= ACELIBRARY_MAJOR then
flickerstreak@28 751 for k,v in pairs(_G) do
flickerstreak@28 752 if v == instance then
flickerstreak@28 753 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
flickerstreak@28 754 end
flickerstreak@28 755 end
flickerstreak@28 756 end]]
flickerstreak@28 757 else
flickerstreak@28 758 safecall(oldDeactivateFunc, oldInstance)
flickerstreak@28 759 end
flickerstreak@28 760 oldInstance = nil
flickerstreak@28 761
flickerstreak@28 762 if externalFunc then
flickerstreak@28 763 for k, data_instance in LibStub:IterateLibraries() do -- all libraries
flickerstreak@28 764 tmp[k] = data_instance
flickerstreak@28 765 end
flickerstreak@28 766 for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
flickerstreak@28 767 tmp[k] = data.instance
flickerstreak@28 768 end
flickerstreak@28 769 for k, data_instance in pairs(tmp) do
flickerstreak@28 770 if k ~= major then
flickerstreak@28 771 safecall(externalFunc, instance, k, data_instance)
flickerstreak@28 772 end
flickerstreak@28 773 tmp[k] = nil
flickerstreak@28 774 end
flickerstreak@28 775 end
flickerstreak@28 776
flickerstreak@28 777 return instance
flickerstreak@28 778 end
flickerstreak@28 779
flickerstreak@28 780 function AceLibrary:IterateLibraries()
flickerstreak@28 781 local t = {}
flickerstreak@28 782 for major, instance in LibStub:IterateLibraries() do
flickerstreak@28 783 t[major] = instance
flickerstreak@28 784 end
flickerstreak@28 785 for major, data in pairs(self.libs) do
flickerstreak@28 786 t[major] = data.instance
flickerstreak@28 787 end
flickerstreak@28 788 return pairs(t)
flickerstreak@28 789 end
flickerstreak@28 790
flickerstreak@28 791 local function manuallyFinalize(major, instance)
flickerstreak@28 792 if AceLibrary.libs[major] then
flickerstreak@28 793 -- don't work on Ace libraries
flickerstreak@28 794 return
flickerstreak@28 795 end
flickerstreak@28 796 local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
flickerstreak@28 797 if finalizedExternalLibs[major] then
flickerstreak@28 798 return
flickerstreak@28 799 end
flickerstreak@28 800 finalizedExternalLibs[major] = true
flickerstreak@28 801
flickerstreak@28 802 for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
flickerstreak@28 803 if k ~= major and data.externalFunc then
flickerstreak@28 804 safecall(data.externalFunc, data.instance, major, instance)
flickerstreak@28 805 end
flickerstreak@28 806 end
flickerstreak@28 807 end
flickerstreak@28 808
flickerstreak@28 809 -- @function Activate
flickerstreak@28 810 -- @brief The activateFunc for AceLibrary itself. Called when
flickerstreak@28 811 -- AceLibrary properly registers.
flickerstreak@28 812 -- @param self Reference to AceLibrary
flickerstreak@28 813 -- @param oldLib (optional) Reference to an old version of AceLibrary
flickerstreak@28 814 -- @param oldDeactivate (optional) Function to deactivate the old lib
flickerstreak@28 815 local function activate(self, oldLib, oldDeactivate)
flickerstreak@28 816 AceLibrary = self
flickerstreak@28 817 if not self.libs then
flickerstreak@28 818 self.libs = oldLib and oldLib.libs or {}
flickerstreak@28 819 self.scannedlibs = oldLib and oldLib.scannedlibs or {}
flickerstreak@28 820 end
flickerstreak@28 821 if not self.positions then
flickerstreak@28 822 self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
flickerstreak@28 823 end
flickerstreak@28 824 self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
flickerstreak@28 825 self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
flickerstreak@28 826 self.frame:UnregisterAllEvents()
flickerstreak@28 827 self.frame:RegisterEvent("ADDON_LOADED")
flickerstreak@28 828 self.frame:SetScript("OnEvent", function()
flickerstreak@28 829 for major, instance in LibStub:IterateLibraries() do
flickerstreak@28 830 manuallyFinalize(major, instance)
flickerstreak@28 831 end
flickerstreak@28 832 end)
flickerstreak@28 833 for major, instance in LibStub:IterateLibraries() do
flickerstreak@28 834 manuallyFinalize(major, instance)
flickerstreak@28 835 end
flickerstreak@28 836
flickerstreak@28 837 -- Expose the library in the global environment
flickerstreak@28 838 _G[ACELIBRARY_MAJOR] = self
flickerstreak@28 839
flickerstreak@28 840 if oldDeactivate then
flickerstreak@28 841 oldDeactivate(oldLib)
flickerstreak@28 842 end
flickerstreak@28 843 end
flickerstreak@28 844
flickerstreak@28 845 if not previous then
flickerstreak@28 846 previous = AceLibrary
flickerstreak@28 847 end
flickerstreak@28 848 if not previous.libs then
flickerstreak@28 849 previous.libs = {}
flickerstreak@28 850 end
flickerstreak@28 851 AceLibrary.libs = previous.libs
flickerstreak@28 852 if not previous.positions then
flickerstreak@28 853 previous.positions = setmetatable({}, { __mode = "k" })
flickerstreak@28 854 end
flickerstreak@28 855 AceLibrary.positions = previous.positions
flickerstreak@28 856 AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)