All Projects → jinq0123 → hotfix

jinq0123 / hotfix

Licence: Apache-2.0 license
Lua 5.2/5.3 hotfix. Hot update functions and keep old data.

Programming Languages

lua
6591 projects

Projects that are alternatives of or similar to hotfix

Jspatch
JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.
Stars: ✭ 11,337 (+16820.9%)
Mutual labels:  hotfix
lets-hotfix
Dynamic class reloading for java。Java代码热更新,支持本地、远程
Stars: ✭ 124 (+85.07%)
Mutual labels:  reload
SDKHoxFix
Android 上SDK的代码热更方案(Android-HoxFix-SDK-Native-Java)
Stars: ✭ 60 (-10.45%)
Mutual labels:  hotfix
Android article
Android热更新、异步并发、性能优化、编译打包、适配相关等文档 by yang。huh...The palest ink is better than the best memory.
Stars: ✭ 181 (+170.15%)
Mutual labels:  hotfix
Micro
🏎Fast diffing and type safe SwiftUI style data source for UICollectionView
Stars: ✭ 77 (+14.93%)
Mutual labels:  reload
arelo
a simple auto reload (live reload) utility
Stars: ✭ 54 (-19.4%)
Mutual labels:  reload
Glean
hotfix for go applications via plugin, supports Linux and MacOS
Stars: ✭ 125 (+86.57%)
Mutual labels:  hotfix
HotUpdateSolution
Hot update solution for unity3d
Stars: ✭ 30 (-55.22%)
Mutual labels:  hotfix
module-invalidate
Invalidate node.js modules loaded through require()
Stars: ✭ 19 (-71.64%)
Mutual labels:  reload
U3dFrameworkTolua
游客学院框架,Fairygui+Tolua
Stars: ✭ 61 (-8.96%)
Mutual labels:  hotfix
Rocketcocoa
A framework for running any extra Cocoa code dynamically
Stars: ✭ 187 (+179.1%)
Mutual labels:  hotfix
sanic-admin
sanic-admin is a command line tool for automatically restarting sanic.
Stars: ✭ 15 (-77.61%)
Mutual labels:  reload
reload
Simple managed reload mechanism for Go
Stars: ✭ 18 (-73.13%)
Mutual labels:  reload
Htframework
Unity HTFramework, a rapid development framework of client to the unity.
Stars: ✭ 179 (+167.16%)
Mutual labels:  hotfix
universal-hot-reload
Hot reload client and server webpack bundles for the ultimate development experience
Stars: ✭ 79 (+17.91%)
Mutual labels:  reload
Nice Ts
基于puerts的Unity游戏框架,集成fairygui,protobufjs并采用addressables管理资源
Stars: ✭ 131 (+95.52%)
Mutual labels:  hotfix
active reloader rb
Rails gem that reloads browser as soon as any file is changed
Stars: ✭ 11 (-83.58%)
Mutual labels:  reload
ultron
Another Android Real-time Hotfix Based Instant Run
Stars: ✭ 20 (-70.15%)
Mutual labels:  hotfix
tinker-dex-dump
用来查看tinker生成的dexdiff格式内容工具,收录于微信tinker官方wiki
Stars: ✭ 112 (+67.16%)
Mutual labels:  hotfix
easy-materialize-rtl
Simple way to set RTL for materializecss.com.
Stars: ✭ 20 (-70.15%)
Mutual labels:  reload

hotfix

Lua 5.2/5.3 hotfix. Hot update functions and keep old data.

What does hotfix do

If we have a test.lua

local M = {}

M.count = 0

function M.func()
    M.count = M.count + 1
    return "v1"
end

return M

Require test and call func(), then count will be 1.

> test = require("test")                              
> test.func()                                         
v1                                                    
> test.count                                          
1                                                     

Change "v1" to "v2" in test.lua, then hotfix module test and call func() again. The result shows that func() has been updated, but the count is kept.

> hotfix = require("hotfix.hotfix")                          
> hotfix.hotfix_module("test")                        
table: 0000000002752060                               
> test.func()                                         
v2                                                    
> test.count                                          
2                                                     

Install

Using LuaRocks:

luarocks install hotfix

Or manually copy lua/hotfix directory into your Lua module path.

Usage

local hotfix = require("hotfix.hotfix")
hotfix.hotfix_module("mymodule.sub_module")

helper/hotfix_helper.lua is an example to hotfix modified modules using lfs. Please see helper/README.md.

hotfix_module(module_name)

hotfix_module() uses package.searchpath(module_name, package.path) to search the path of module. The module is reloaded and the returned value is updated to package.loaded[module_name]. If the returned value is nil, then package.loaded[module_name] is assigned to true. hotfix_module() returns the final value of package.loaded[module_name].

hotfix_module() will skip unloaded module to avoid unexpected loading, and also to work around the issue of "Three dots module name will be nil".

Functons are updated to new ones but old upvalues are kept. Old tables are kept and new fields are inserted. All references to old functions are replaced to new ones.

The module may change any global variables if it wants to. See "Why not protect the global variables" below.

Local variable which is not referenced by _G is not updated.

-- test.lua: return { function func() return "old" end }
local test = require("test")  -- referenced by _G.package.loaded["test"]
local func = test.func        -- is not upvalue nor is referenced by _G
-- test.lua: return { function func() return "new" end }
require("hotfix.hotfix").hotfix_module("test")
test.func()  -- "new"  
func()       -- "old"

Why not protect the global variables

We can protect the global variables on loading in some ways, but there are other problems.

  • [1] uses a read only ENV to load.
    local env = {}
    setmetatable(env, { __index = _G })
    load(chunk, check_name, 't', env)

But it can not stop indirect write. Global variables may be changed. In the following example, t is OK but math.sin is changed.

Lua 5.3.2  Copyright (C) 1994-2015 Lua.org, PUC-Rio
> math.sin(123)
-0.45990349068959
> do
>> local _ENV = setmetatable({}, {__index = _G})
>> t = 123
>> math.sin = print
>> end
> t
nil
> math.sin(123)
123
  • [2] uses a fake ENV to load and ignores all operations. In this case, we can not init new local variables.
local M = {}
+ local log = require("log")  -- Can not require!
function M.foo()
+    log.info("test")
end
return M

Another problem is the new function's _ENV is not the real ENV. Following test will fail because set_global() has a protected ENV.

log("New upvalue which is a function set global...")
run_test([[
        local M = {}
        function M.foo() return 12345 end
        return M
    ]],
    function() assert(nil == global_test) end,
    [[
        local M = {}
        local function set_global() global_test = 11111 end
        function M.foo()
            set_global()
        end
        return M
    ]],
    function()
        assert(nil == test.foo())
        assert(11111 == global_test)  -- FAIL!
        global_test = nil
    end)

How to run test

Run main.lua in test dir. main.lua will write a test.lua file and hotfix it. main.lua will write log to log.txt.

D:\Jinq\Git\hotfix\test>..\..\..\tools\lua-5.3.2_Win64_bin\lua53
Lua 5.3.2  Copyright (C) 1994-2015 Lua.org, PUC-Rio
> require("main").run()
main.lua:80: assertion failed!

Unexpected update

log function is changed from print to an empty function. The hotfix will replace all print to an empty function which is totally unexpected.

local M = {}
local log = print
function M.foo() log("Old") end
return M
local M = {}
local log = function() end
function M.foo() log("Old") end
return M

hotfix.add_protect{print} can protect print function from being replaced. But it also means that log can not be updated.

Known issue

Can not load utf8 with BOM.

hotfix.lua:210: file.lua:1: unexpected symbol near '<\239>'

Three dots module name will be nil.

--- test.lua.
-- @module test
local module_name = ...
print(module_name)

require("test") will print "test", but hotfix which uses load() will print "nil".

Reference

local M = {}
+ function M.foo() end  -- Can not add M.foo().
return M
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].