summaryrefslogtreecommitdiff
path: root/xmake/core/base
diff options
context:
space:
mode:
Diffstat (limited to 'xmake/core/base')
-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
4 files changed, 193 insertions, 66 deletions
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)