hotfix.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. --[[
  2. Lua 5.2/5.3 hotfix. Hot update functions and keep old data.
  3. Author: Jin Qing ( http://blog.csdn.net/jq0123 )
  4. --]]
  5. local M = {}
  6. local module_updater = require("hotfix.internal.module_updater")
  7. local functions_replacer = require("hotfix.internal.functions_replacer")
  8. -- Do not update and replace protected objects.
  9. local protected = {}
  10. -- To protect self.
  11. local function add_self_to_protect()
  12. M.add_protect{
  13. M,
  14. M.hotfix_module,
  15. M.log_error,
  16. M.log_info,
  17. M.log_debug,
  18. M.add_protect,
  19. M.remove_protect,
  20. module_updater,
  21. module_updater.log_debug,
  22. module_updater.update_loaded_module,
  23. functions_replacer,
  24. functions_replacer.replace_all,
  25. }
  26. end -- add_self_to_protect
  27. -- Hotfix module with new module object.
  28. -- Update package.loaded[module_name] and replace all functions.
  29. -- module_obj is the newly loaded module object.
  30. local function hotfix_module_with_obj(module_name, module_obj)
  31. assert("string" == type(module_name))
  32. add_self_to_protect()
  33. module_updater.log_debug = M.log_debug
  34. -- Step 1: Update package.loaded[module_name], recording updated functions.
  35. local updated_function_map = module_updater.update_loaded_module(
  36. module_name, protected, module_obj)
  37. -- Step 2: Replace old functions with new ones in module_obj, _G and registry.
  38. functions_replacer.replace_all(protected, updated_function_map, module_obj, module_name)
  39. end -- hotfix_module_with_obj()
  40. -- Hotfix module.
  41. -- Skip unloaded module.
  42. -- Usage: hotfix_module("mymodule.sub_module")
  43. -- Returns package.loaded[module_name].
  44. function M.hotfix_module(module_name)
  45. assert("string" == type(module_name))
  46. if not package.loaded[module_name] then
  47. M.log_debug("Skip unloaded module: " .. module_name)
  48. return package.loaded[module_name]
  49. end
  50. M.log_debug("Hot fix module: " .. module_name)
  51. local file_path = assert(package.searchpath(module_name, package.path))
  52. local fp = assert(io.open(file_path))
  53. local chunk = fp:read("*all")
  54. fp:close()
  55. -- Load chunk.
  56. local func = assert(load(chunk, '@'..file_path))
  57. local ok, obj = assert(pcall(func))
  58. if nil == obj then obj = true end -- obj may be false
  59. hotfix_module_with_obj(module_name, obj)
  60. return package.loaded[module_name]
  61. end
  62. -- User can set log functions. Default is no log.
  63. -- Like: require("hotfix").log_info = function(s) mylog:info(s) end
  64. function M.log_error(msg_str) end
  65. function M.log_info(msg_str) end
  66. function M.log_debug(msg_str) end
  67. -- Add objects to protect.
  68. -- Example: add_protect({table, math, print})
  69. function M.add_protect(object_array)
  70. for _, obj in pairs(object_array) do
  71. protected[obj] = true
  72. end
  73. end -- add_protect()
  74. -- Remove objects in protected set.
  75. -- Example: remove_protect({table, math, print})
  76. function M.remove_protect(object_array)
  77. for _, obj in pairs(object_array) do
  78. protected[obj] = nil
  79. end
  80. end -- remove_protect()
  81. return M