diff options
| author | ruki <[email protected]> | 2016-03-01 22:45:47 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2016-03-01 22:45:47 +0800 |
| commit | 33cf83635ed21a2e39f09f2a28dceaf6f6abd5cd (patch) | |
| tree | 73456c9dd87729e95aee9ff6236882c3fcff84a1 | |
| parent | 197c9a41fdb374f8338c6dd40af8df4eb5371b29 (diff) | |
import module with sandbox for tasks
| -rwxr-xr-x | xmake/actions/config/main.lua | 19 | ||||
| -rwxr-xr-x | xmake/actions/config/xmake.lua | 5 | ||||
| -rw-r--r-- | xmake/core/base/deprecated/interpreter.lua | 8 | ||||
| -rw-r--r-- | xmake/core/base/interpreter.lua | 25 | ||||
| -rw-r--r-- | xmake/core/base/sandbox.lua | 89 | ||||
| -rw-r--r-- | xmake/core/base/task.lua | 137 | ||||
| -rw-r--r-- | xmake/core/sandbox/import.lua | 62 |
7 files changed, 272 insertions, 73 deletions
diff --git a/xmake/actions/config/main.lua b/xmake/actions/config/main.lua index 59da0ad0a..19686aa4f 100755 --- a/xmake/actions/config/main.lua +++ b/xmake/actions/config/main.lua @@ -20,8 +20,27 @@ -- @file main.lua -- +import("core") +import("core.project") + +print("global") +print(project) +print(core.project) + +function test() + + print("test") + print(project) + print(core.project) +end function main() + print("main") + print(project) + print(core.project) + + -- test + test() end diff --git a/xmake/actions/config/xmake.lua b/xmake/actions/config/xmake.lua index 446ba5d4a..effe5d3d7 100755 --- a/xmake/actions/config/xmake.lua +++ b/xmake/actions/config/xmake.lua @@ -29,8 +29,13 @@ task("config") -- on run on_task_run(function () + import("main") import("core.project") + + print(main) + print(main.print) print(project) + print(main.main()) end) diff --git a/xmake/core/base/deprecated/interpreter.lua b/xmake/core/base/deprecated/interpreter.lua index 91c734660..44c8314d7 100644 --- a/xmake/core/base/deprecated/interpreter.lua +++ b/xmake/core/base/deprecated/interpreter.lua @@ -121,15 +121,15 @@ function deprecated_interpreter.api_register_set_script(self, scope_kind, prefix -- warning utils.warning("please uses on_%s(), \"set_%s()\" has been deprecated!", name, name, scope) - -- bind script and get new script with sandbox - local newscript, errors = sandbox.bind(script, self) - if not newscript then + -- make sandbox instance with the given script + local instance, errors = sandbox.make(script, self) + if not instance then os.raise("set_%s(): %s", name, errors) end -- update script? scope[name] = {} - table.insert(scope[name], newscript) + table.insert(scope[name], instance:script()) end diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua index 9afa12f1e..551dad5fc 100644 --- a/xmake/core/base/interpreter.lua +++ b/xmake/core/base/interpreter.lua @@ -469,7 +469,7 @@ function interpreter.load(self, file, scope_kind, remove_repeat, enable_filter) self._PRIVATE._CURFILE = file -- init the root directory - self._PRIVATE._ROOTDIR = self._PRIVATE._ROOTDIR or path.directory(file) + self._PRIVATE._ROOTDIR = path.directory(file) assert(self._PRIVATE._ROOTDIR) -- init mtime for the current file @@ -504,7 +504,7 @@ function interpreter.filter(self) -- check assert(self and self._PRIVATE) - -- get filter + -- get it return self._PRIVATE._FILTER end @@ -514,10 +514,20 @@ function interpreter.filter_set(self, filter) -- check assert(self and self._PRIVATE) - -- set filter + -- set it self._PRIVATE._FILTER = filter end +-- get root directory +function interpreter.rootdir(self) + + -- check + assert(self and self._PRIVATE) + + -- get it + return self._PRIVATE._ROOTDIR +end + -- set root directory function interpreter.rootdir_set(self, rootdir) @@ -735,16 +745,15 @@ function interpreter.api_register_on_script(self, scope_kind, prefix, ...) -- define implementation local implementation = function (self, scope, name, script) - -- bind script and get new script with sandbox - local newscript, errors = sandbox.bind(script, self) - if not newscript then + -- make sandbox instance with the given script + local instance, errors = sandbox.make(script, self) + if not instance then os.raise("on_%s(): %s", name, errors) end -- update script? scope[name] = {} - table.insert(scope[name], newscript) - + table.insert(scope[name], instance:script()) end -- register implementation diff --git a/xmake/core/base/sandbox.lua b/xmake/core/base/sandbox.lua index 49c863263..252241e2f 100644 --- a/xmake/core/base/sandbox.lua +++ b/xmake/core/base/sandbox.lua @@ -141,8 +141,8 @@ function sandbox._init() return self end --- bind script into the sandbox -function sandbox.bind(script, interp) +-- make sandbox instance with the given script +function sandbox.make(script, interp) -- check assert(script and interp) @@ -156,29 +156,14 @@ function sandbox.bind(script, interp) -- save filter self._PRIVATE._FILTER = interp:filter() + -- save root directory + self._PRIVATE._ROOTDIR = interp:rootdir() + -- this script is file? load it first if type(script) == "string" then - -- check - if not os.isfile(script) then - return nil, string.format("the script file(%s) not found!", script) - end - - -- load it - local filescript, errors = loadfile(script) - if filescript then - - -- bind public scope - setfenv(filescript, self._PUBLIC) - - -- get main script - script = filescript() - if type(script) == "table" and script.main then - script = script.main - end - else - return nil, errors - end + -- TODO + assert(false) end -- no script? @@ -194,8 +179,11 @@ function sandbox.bind(script, interp) -- bind public scope setfenv(script, self._PUBLIC) + -- save script + self._PRIVATE._SCRIPT = script + -- ok - return script + return self end -- load script in the sandbox @@ -205,6 +193,51 @@ function sandbox.load(script, ...) return xpcall(script, sandbox._traceback, ...) end +-- fork a new sandbox from the given sandbox +function sandbox.fork(self, script) + + -- no script? + if script == nil then + return nil, "no script!" + end + + -- invalid script? + if script ~= nil and type(script) ~= "function" then + return nil, "invalid script!" + end + + -- init a new sandbox instance + local instance = sandbox._init() + + -- check + assert(instance and instance._PUBLIC and instance._PRIVATE) + + -- inherit the filter + instance._PRIVATE._FILTER = self:filter() + + -- inherit the root directory + instance._PRIVATE._ROOTDIR = self:rootdir() + + -- bind public scope + setfenv(script, instance._PUBLIC) + + -- save script + instance._PRIVATE._SCRIPT = script + + -- ok? + return instance +end + +-- get script from the given sandbox +function sandbox.script(self) + + -- check + assert(self and self._PRIVATE) + + -- get it + return self._PRIVATE._SCRIPT +end + -- get filter from the given sandbox function sandbox.filter(self) @@ -215,6 +248,16 @@ function sandbox.filter(self) return self._PRIVATE._FILTER end +-- get root directory from the given sandbox +function sandbox.rootdir(self) + + -- check + assert(self and self._PRIVATE) + + -- get it + return self._PRIVATE._ROOTDIR +end + -- get current instance in the sandbox modules function sandbox.instance() diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index 2c13ded6f..cda0c3356 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -97,39 +97,112 @@ function task._interpreter() return interp end --- load the given task script file -function task._load(filepath) +-- bind tasks for menu with an sandbox instance +function task._bind(tasks) + + -- check + assert(tasks) -- get interpreter local interp = task._interpreter() assert(interp) - -- load task - local results, errors = interp:load(filepath, "task", true, true) - if not results and os.isfile(filepath) then - -- trace - utils.error(errors) + -- bind sandbox for menus + for _, taskinfo in pairs(tasks) do + + -- has menu? + if taskinfo.menu then + + -- translate options + local options = taskinfo.menu.options + if options then + + -- make full options + local options_full = {} + for _, opt in ipairs(options) do + + -- this option is function? translate it + if type(opt) == "function" then + + -- make sandbox instance with the given script + local instance, errors = sandbox.make(opt, interp) + if not instance then + return false, errors + end + + -- update option script + opt = instance:script() + end + + -- insert option + table.insert(options_full, opt) + end + + -- update the options + options = options_full + taskinfo.menu.options = options_full + + -- bind sandbox for option description + for _, opt in ipairs(options) do + + -- bind description + if type(opt) == "table" then + for i = 5, 64 do + + -- the description, @note some option may be nil + local description = opt[i] + if not description then break end + + -- the description is function? wrap it for calling it in the sandbox + if type(description) == "function" then + + -- make sandbox instance with the given script + local instance, errors = sandbox.make(description, interp) + if not instance then + return false, errors + end + + -- check + assert(instance:script()) + + -- update option script + opt[i] = instance:script() + end + end + end + end + end + end end - -- ok? - return results + -- ok + return true end --- call the sandbox script -function task._call(script, ...) +-- load the given task script file +function task._load(filepath) -- get interpreter local interp = task._interpreter() assert(interp) - -- bind script and get new script with sandbox - local newscript, errors = sandbox.bind(script, interp) - if not newscript then - return false, errors + -- load tasks + local tasks, errors = interp:load(filepath, "task", true, true) + if not tasks and os.isfile(filepath) then + -- trace + utils.error(errors) end - -- load it - return sandbox.load(script, ...) + -- bind tasks for menu with an sandbox instance + local ok, errors = task._bind(tasks) + if not ok then + -- trace + utils.error(errors) + return + end + + -- ok? + return tasks end -- get all tasks @@ -150,8 +223,10 @@ function task.tasks() if files then for _, filepath in ipairs(files) do - -- load it + -- load tasks local results = task._load(filepath) + + -- save tasks if results then table.join2(tasks, results) end @@ -208,7 +283,7 @@ function task.run(name) if on_script then -- call it in the sandbox - ok, errors = task._call(on_script) + ok, errors = sandbox.load(on_script) if not ok then utils.error(errors) break @@ -220,7 +295,7 @@ function task.run(name) if not ok and taskinfo.failure then -- call it in the sandbox - ok, errors = task._call(taskinfo.failure) + ok, errors = sandbox.load(taskinfo.failure) if not ok then utils.error(errors) end @@ -257,13 +332,13 @@ function task.menu() -- make full options local options_full = {} - for _, option in ipairs(options) do + for _, opt in ipairs(options) do -- this option is function? translate it - if type(option) == "function" then + if type(opt) == "function" then -- call menu script in the sandbox - local ok, results = task._call(option) + local ok, results = sandbox.load(opt) if ok then if results then for _, opt in ipairs(results) do @@ -275,7 +350,7 @@ function task.menu() os.raise("taskmenu: %s", results) end else - table.insert(options_full, option) + table.insert(options_full, opt) end end @@ -287,31 +362,31 @@ function task.menu() if interp:filter() then -- filter option - for _, option in ipairs(options) do + for _, opt in ipairs(options) do -- filter default - local default = option[4] + local default = opt[4] if type(default) == "string" then - option[4] = interp:filter():handle(default) + opt[4] = interp:filter():handle(default) end -- filter description for i = 5, 64 do -- the description, @note some option may be nil - local description = option[i] + local description = opt[i] if not description then break end -- the description is string? if type(description) == "string" then - option[i] = interp:filter():handle(description) + opt[i] = interp:filter():handle(description) -- the description is function? wrap it for calling it in the sandbox elseif type(description) == "function" then - option[i] = function () + opt[i] = function () -- call it in the sandbox - local ok, results = task._call(description) + local ok, results = sandbox.load(description) if not ok then -- errors os.raise("taskmenu: %s", results) diff --git a/xmake/core/sandbox/import.lua b/xmake/core/sandbox/import.lua index c59cdbe87..626554600 100644 --- a/xmake/core/sandbox/import.lua +++ b/xmake/core/sandbox/import.lua @@ -27,7 +27,9 @@ local sandbox_import = sandbox_import or {} local os = require("base/os") local path = require("base/path") local utils = require("base/utils") +local table = require("base/table") local string = require("base/string") +local sandbox = require("base/sandbox") -- get module name function sandbox_import._modulename(name) @@ -46,7 +48,7 @@ function sandbox_import._modulename(name) end -- load module from file -function sandbox_import._loadfile(filepath) +function sandbox_import._loadfile(filepath, instance) -- check assert(filepath) @@ -57,7 +59,39 @@ function sandbox_import._loadfile(filepath) return nil, errors end - -- load module + -- with sandbox? + if instance then + + -- fork a new sandbox for this script + instance, errors = instance:fork(script) + if not instance then + return nil, errors + end + + -- backup the scope variables first + local scope_public = getfenv(instance:script()) + local scope_backup = {} + table.copy2(scope_backup, scope_public) + + -- load module with sandbox + local ok, errors = sandbox.load(instance:script()) + if not ok then + return nil, errors + end + + -- only export new public functions + local result = {} + for k, v in pairs(scope_public) do + if type(v) == "function" and scope_backup[k] == nil then + result[k] = v + end + end + + -- get module + return result + end + + -- load module without sandbox local ok, result = xpcall(script, debug.traceback) if not ok then return nil, result @@ -68,7 +102,7 @@ function sandbox_import._loadfile(filepath) end -- load module -function sandbox_import._load(dir, name) +function sandbox_import._load(dir, name, instance) -- check assert(dir and name) @@ -82,7 +116,7 @@ function sandbox_import._load(dir, name) if os.isfile(path.join(dir, name .. ".lua")) then -- load module - local result, errors = sandbox_import._loadfile(path.join(dir, name .. ".lua")) + local result, errors = sandbox_import._loadfile(path.join(dir, name .. ".lua"), instance) if not result then return nil, errors end @@ -100,7 +134,7 @@ function sandbox_import._load(dir, name) for _, modulefile in ipairs(modulefiles) do -- load module - local result, errors = sandbox_import._loadfile(modulefile) + local result, errors = sandbox_import._loadfile(modulefile, instance) if not result then return nil, errors end @@ -169,8 +203,22 @@ function sandbox_import.import(name, alias) -- check assert(name) - -- load module from the sandbox directory - local module, errors = sandbox_import._load(path.join(xmake._CORE_DIR, "sandbox/import"), name) + -- get the current sandbox instance + local instance = sandbox.instance() + assert(instance) + + -- the root directory for this sandbox script + local rootdir = instance:rootdir() + assert(rootdir) + + -- load module from the sandbox root directory first + local module, errors = sandbox_import._load(rootdir, name, instance) + if not module then + -- load module from the sandbox core directory + module, errors = sandbox_import._load(path.join(xmake._CORE_DIR, "sandbox/import"), name) + end + + -- check if not module then os.raise("cannot import module: %s, %s", name, errors) end |
