You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.9 KiB
Lua
99 lines
2.9 KiB
Lua
--[[
|
|
Lua 5.2/5.3 hotfix. Hot update functions and keep old data.
|
|
Author: Jin Qing ( http://blog.csdn.net/jq0123 )
|
|
--]]
|
|
local M = {}
|
|
|
|
local module_updater = require("hotfix.internal.module_updater")
|
|
local functions_replacer = require("hotfix.internal.functions_replacer")
|
|
|
|
-- Do not update and replace protected objects.
|
|
local protected = {}
|
|
|
|
-- To protect self.
|
|
local function add_self_to_protect()
|
|
M.add_protect {
|
|
M,
|
|
M.hotfix_module,
|
|
M.log_error,
|
|
M.log_info,
|
|
M.log_debug,
|
|
M.add_protect,
|
|
M.remove_protect,
|
|
module_updater,
|
|
module_updater.log_debug,
|
|
module_updater.update_loaded_module,
|
|
functions_replacer,
|
|
functions_replacer.replace_all
|
|
}
|
|
end -- add_self_to_protect
|
|
|
|
-- Hotfix module with new module object.
|
|
-- Update package.loaded[module_name] and replace all functions.
|
|
-- module_obj is the newly loaded module object.
|
|
local function hotfix_module_with_obj(module_name, module_obj)
|
|
assert("string" == type(module_name))
|
|
add_self_to_protect()
|
|
module_updater.log_debug = M.log_debug
|
|
|
|
-- Step 1: Update package.loaded[module_name], recording updated functions.
|
|
local updated_function_map = module_updater.update_loaded_module(module_name, protected, module_obj)
|
|
-- Step 2: Replace old functions with new ones in module_obj, _G and registry.
|
|
functions_replacer.replace_all(protected, updated_function_map, module_obj)
|
|
end -- hotfix_module_with_obj()
|
|
|
|
-- Hotfix module.
|
|
-- Skip unloaded module.
|
|
-- Usage: hotfix_module("mymodule.sub_module")
|
|
-- Returns package.loaded[module_name].
|
|
function M.hotfix_module(module_name)
|
|
assert("string" == type(module_name))
|
|
if not package.loaded[module_name] then
|
|
M.log_debug("Skip unloaded module: " .. module_name)
|
|
return package.loaded[module_name]
|
|
end
|
|
M.log_debug("Hot fix module: " .. module_name)
|
|
|
|
local file_path = assert(package.searchpath(module_name, package.path))
|
|
local fp = assert(io.open(file_path))
|
|
local chunk = fp:read("*all")
|
|
fp:close()
|
|
|
|
-- Load chunk.
|
|
local func = assert(load(chunk, "@" .. file_path))
|
|
local ok, obj = assert(pcall(func))
|
|
if nil == obj then
|
|
obj = true
|
|
end -- obj may be false
|
|
|
|
hotfix_module_with_obj(module_name, obj)
|
|
return package.loaded[module_name]
|
|
end
|
|
|
|
-- User can set log functions. Default is no log.
|
|
-- Like: require("hotfix").log_info = function(s) mylog:info(s) end
|
|
function M.log_error(msg_str)
|
|
end
|
|
function M.log_info(msg_str)
|
|
end
|
|
function M.log_debug(msg_str)
|
|
end
|
|
|
|
-- Add objects to protect.
|
|
-- Example: add_protect({table, math, print})
|
|
function M.add_protect(object_array)
|
|
for _, obj in pairs(object_array) do
|
|
protected[obj] = true
|
|
end
|
|
end -- add_protect()
|
|
|
|
-- Remove objects in protected set.
|
|
-- Example: remove_protect({table, math, print})
|
|
function M.remove_protect(object_array)
|
|
for _, obj in pairs(object_array) do
|
|
protected[obj] = nil
|
|
end
|
|
end -- remove_protect()
|
|
|
|
return M
|