summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2016-03-01 22:45:47 +0800
committerruki <[email protected]>2016-03-01 22:45:47 +0800
commit33cf83635ed21a2e39f09f2a28dceaf6f6abd5cd (patch)
tree73456c9dd87729e95aee9ff6236882c3fcff84a1
parent197c9a41fdb374f8338c6dd40af8df4eb5371b29 (diff)
import module with sandbox for tasks
-rwxr-xr-xxmake/actions/config/main.lua19
-rwxr-xr-xxmake/actions/config/xmake.lua5
-rw-r--r--xmake/core/base/deprecated/interpreter.lua8
-rw-r--r--xmake/core/base/interpreter.lua25
-rw-r--r--xmake/core/base/sandbox.lua89
-rw-r--r--xmake/core/base/task.lua137
-rw-r--r--xmake/core/sandbox/import.lua62
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