summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2012-08-04 10:54:43 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2012-08-04 10:54:43 +0100
commit5f232e4aaaad5b56d970a425c532e95240f82491 (patch)
treeb87633788132df1b89a81d58e819f5bf79b2b4fd
parentbfbad391533d99e072fde43c774d60c1d9f80f8e (diff)
downloadsupple-5f232e4aaaad5b56d970a425c532e95240f82491.tar.gz
SUPPLE: Better support for error messages, show them in the example
-rw-r--r--example/simple-example.lua9
-rw-r--r--lib/supple/comms.lua143
-rw-r--r--lib/supple/host.lua27
-rw-r--r--lib/supple/objects.lua27
-rw-r--r--lib/supple/request.lua2
-rw-r--r--lib/supple/sandbox.lua2
-rw-r--r--test/test-supple.request.lua3
7 files changed, 144 insertions, 69 deletions
diff --git a/example/simple-example.lua b/example/simple-example.lua
index 33f62e8..327167f 100644
--- a/example/simple-example.lua
+++ b/example/simple-example.lua
@@ -44,3 +44,12 @@ setmetatable(tab, mt)
-- Finally, run the subcode
print(supple.host.run(subcode, "@test-code", tab))
assert(tab.tot == 24)
+
+-- Now run a supple command which we expect to error out.
+print(supple.host.run("unknown()", "@test-code"))
+
+-- And now, one where we pass an error from host to sandbox and back
+print(supple.host.run("local f = ... f()", "@test-code", function() unknown() end))
+
+-- And now, one where we pass an error from sandbox to host to sandbox and back
+print(supple.host.run("local f = ... f(function() unknown() end)", "@test-code", function(ff) ff() end))
diff --git a/lib/supple/comms.lua b/lib/supple/comms.lua
index efe737f..25aeb39 100644
--- a/lib/supple/comms.lua
+++ b/lib/supple/comms.lua
@@ -18,6 +18,8 @@ local objects = require "supple.objects"
local unpack = unpack
local tonumber = tonumber
local error = error
+local getinfo = debug.getinfo
+local concat = table.concat
local fd = -1
@@ -49,67 +51,94 @@ local function recv_msg()
return str
end
-local function wait_for_response()
- local back = request.deserialise(recv_msg())
- -- back could be three things
- -- an error (raise it)
- if back.error then
- error(back.message .. "\n" .. back.traceback)
- end
- -- A result, return it
- if back.error == false then
- return unpack(back.results)
+local function captcha(msg)
+ local traceback = {}
+ local level = 2
+ local info = getinfo(level, "Snlf")
+ while info do
+ if info.currentline > 0 and
+ not info.short_src:match("/supple/[^%.]+%.lua$") then
+ local ttype, tag = objects.find_tag(info.func)
+ if ttype then
+ info.name = tag
+ end
+ local line =
+ ("\t%s:%d in function %s"):format(info.short_src,
+ info.currentline,
+ info.name or "<anon>")
+ traceback[#traceback+1] = line
+ end
+ level = level + 1
+ info = getinfo(level, "Snlf")
end
- -- A method call, call it
+ return {msg, concat(traceback, "\n") or ""}
+end
- local function safe_method(fn)
- local ok, res = pcall(fn)
- local resp
- if not ok then
- resp = request.error(res, "")
+local function wait_for_response()
+ repeat
+ local back = request.deserialise(recv_msg())
+ -- back could be three things
+ -- an error (raise it)
+ if back.error then
+ local msg = back.message
+ if back.traceback and back.traceback ~= "" then
+ msg = msg .. "\n" .. back.traceback
+ end
+ error(msg, 2)
+ end
+ -- A result, return it
+ if back.error == false then
+ return unpack(back.results)
+ end
+ -- A method call, call it
+
+ local function safe_method(fn)
+ local ok, res = xpcall(fn, captcha)
+ local resp
+ if not ok then
+ resp = request.error(unpack(res))
+ else
+ resp = request.response(unpack(res))
+ end
+ send_msg(resp)
+ end
+ if back.method == "__gc" then
+ -- __gc is the garbage collect mechanism
+ objects.forget_mine(back.object)
+ send_msg(request.response())
+ elseif back.method == "__call" then
+ -- __call is the function call mechanism
+ safe_method(function()
+ local obj = objects.receive { tag = back.object }
+ return {obj(unpack(back.args))}
+ end)
+ elseif back.method == "__len" then
+ safe_method(function()
+ local obj = objects.receive { tag = back.object }
+ return {#obj}
+ end)
+ elseif back.method == "__index" then
+ safe_method(function()
+ local obj = objects.receive { tag = back.object }
+ return {obj[back.args[1]]}
+ end)
+ elseif back.method == "__newindex" then
+ safe_method(function()
+ local obj = objects.receive { tag = back.object }
+ obj[back.args[1]] = back.args[2]
+ return {}
+ end)
else
- resp = request.response(unpack(res))
+ safe_method(function()
+ local obj = objects.receive { tag = back.object }
+ local meth = capi.raw_getmm(obj, back.method)
+ if not meth then
+ error("Unknown or disallowed method: " .. back.method, "")
+ end
+ return {meth(obj, unpack(back.args))}
+ end)
end
- send_msg(resp)
- end
- if back.method == "__gc" then
- -- __gc is the garbage collect mechanism
- objects.forget_mine(back.object)
- send_msg(request.response())
- elseif back.method == "__call" then
- -- __call is the function call mechanism
- safe_method(function()
- local obj = objects.receive { tag = back.object }
- return {obj(unpack(back.args))}
- end)
- elseif back.method == "__len" then
- safe_method(function()
- local obj = objects.receive { tag = back.object }
- return {#obj}
- end)
- elseif back.method == "__index" then
- safe_method(function()
- local obj = objects.receive { tag = back.object }
- return {obj[back.args[1]]}
- end)
- elseif back.method == "__newindex" then
- safe_method(function()
- local obj = objects.receive { tag = back.object }
- obj[back.args[1]] = back.args[2]
- return {}
- end)
- else
- safe_method(function()
- local obj = objects.receive { tag = back.object }
- local meth = capi.raw_getmm(obj, back.method)
- if not meth then
- error("Unknown or disallowed method: " .. back.method, "")
- end
- return {meth(obj, unpack(back.args))}
- end)
- end
- -- And try again
- return wait_for_response()
+ until false
end
local function make_call(object, method, ...)
diff --git a/lib/supple/host.lua b/lib/supple/host.lua
index a828046..f0181fa 100644
--- a/lib/supple/host.lua
+++ b/lib/supple/host.lua
@@ -15,6 +15,7 @@ local subprocess = require 'luxio.subprocess'
local comms = require 'supple.comms'
local objects = require 'supple.objects'
+local hostname = "host"
local counter = 0
local function run_wrapper()
@@ -50,7 +51,7 @@ local function run_sandbox(codestr, codename, ...)
local child, commsfd = run_wrapper()
counter = counter + 1
- objects.set_name(("host-%d"):format(counter))
+ objects.set_name(("host[%d,%%d]"):format(counter))
comms._set_fd(commsfd)
objects.set_proc_call(comms.call)
@@ -58,21 +59,37 @@ local function run_sandbox(codestr, codename, ...)
if not func then
error(err)
end
+ -- Clear 'err' because it'll be the environment table for the function
+ -- which we do not need to fill out.
+ err = nil
- local ret = {func(...)}
-
+ -- In a protected manner, capture the output of the call
+ local args, ret = {...}
+ local function capture()
+ ret = {func(unpack(args))}
+ end
+ local ok, err = pcall(capture)
-- We need to clean up, so dump all the objects
func = nil
- err = nil
-- And ask the supple API to clear down too
objects.clean_down(true)
comms._set_fd(-1)
luxio.kill(child.pid, luxio.SIGKILL)
child:wait()
- return unpack(ret)
+ if ok then
+ return ok, unpack(ret)
+ else
+ return ok, err
+ end
+end
+
+local function set_hostname(newname)
+ hostname = newname
+ counter = 0
end
return {
run = run_sandbox,
+ set_name = set_hostname,
} \ No newline at end of file
diff --git a/lib/supple/objects.lua b/lib/supple/objects.lua
index 5aa1ec7..9220502 100644
--- a/lib/supple/objects.lua
+++ b/lib/supple/objects.lua
@@ -56,6 +56,19 @@ local integral = {
number = true,
}
+local function new_tag(special_tag)
+ local retstr = special_tag
+ if not retstr then
+ if not my_name:match("%%d") then
+ retstr = ("%s:%d"):format(my_name, my_counter)
+ else
+ retstr = my_name:format(my_counter)
+ end
+ my_counter = my_counter + 1
+ end
+ return retstr
+end
+
local function give(obj, special_tag)
-- If the object is integral, return it directly
if integral[type(obj)] then
@@ -74,9 +87,7 @@ local function give(obj, special_tag)
return { tag = tag }
end
-- otherwise wrap it freshly for us and return that.
- local tag = (special_tag and special_tag or
- ("%s:%d"):format(my_name, my_counter))
- my_counter = my_counter + 1
+ local tag = new_tag(special_tag)
local expn = capi.explain(obj, tag)
my_objects_by_obj[obj] = tag
my_objects_by_tag[tag] = obj
@@ -135,6 +146,15 @@ local function forget_mine(tag)
my_objects_by_obj[obj] = nil
end
+local function find_tag(obj)
+ if my_objects_by_obj[obj] then
+ return "my", my_objects_by_obj[obj]
+ end
+ if their_objects_by_obj[obj] then
+ return "their", their_objects_by_obj[obj]
+ end
+end
+
return {
set_name = set_name,
get_name = get_name,
@@ -143,4 +163,5 @@ return {
receive = receive,
clean_down = clean_down,
forget_mine = forget_mine,
+ find_tag = find_tag,
}
diff --git a/lib/supple/request.lua b/lib/supple/request.lua
index 97f8f4f..ab8388a 100644
--- a/lib/supple/request.lua
+++ b/lib/supple/request.lua
@@ -22,7 +22,7 @@ local setfenv = setfenv
local function serialise_error(errstr, traceback)
return tconcat {
"error=true,",
- ("message=%q,"):format(("%s: %s"):format(objects.get_name(), errstr)),
+ ("message=%q,"):format(errstr),
("traceback=%q"):format(traceback)
}
end
diff --git a/lib/supple/sandbox.lua b/lib/supple/sandbox.lua
index 92b3afd..3c807cb 100644
--- a/lib/supple/sandbox.lua
+++ b/lib/supple/sandbox.lua
@@ -118,7 +118,7 @@ local function run()
return 1
end
- objects.set_name(("supple-sandbox[%d]"):format(luxio.getpid()))
+ objects.set_name(("supple-sandbox[%d,%%d]"):format(luxio.getpid()))
objects.set_proc_call(comms.call)
local function wrappered_load(str, name)
diff --git a/test/test-supple.request.lua b/test/test-supple.request.lua
index 2ea7e66..6ed5f5b 100644
--- a/test/test-supple.request.lua
+++ b/test/test-supple.request.lua
@@ -32,9 +32,8 @@ end
local suite = setmetatable({}, {__newindex = add_test})
function suite.serialise_error()
- objects.set_name("n")
local err = request.error("m","tb")
- assert(err == [[error=true,message="n: m",traceback="tb"]],
+ assert(err == [[error=true,message="m",traceback="tb"]],
"Error did not serialise properly")
end