Giter Site home page Giter Site logo

hotfix's Introduction

hotfix

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

Usage

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

helper/hotfix_helper.lua is an example to hotfix modified modules using lfs.

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 want to.

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_module("test")
test.func()  -- "new"  
func()       -- "old"

Todo: Replace functions of local variables in all threads using:

    debug.getlocal ([thread,] f, local)
    debug.setlocal ([thread,] level, local, value)

Why not protect the global variables

We can protect the glocal variables on loading.

  • [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

hotfix's People

Contributors

jinq0123 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.