diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-08-04 10:54:43 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-08-04 10:54:43 +0100 |
commit | 5f232e4aaaad5b56d970a425c532e95240f82491 (patch) | |
tree | b87633788132df1b89a81d58e819f5bf79b2b4fd /lib | |
parent | bfbad391533d99e072fde43c774d60c1d9f80f8e (diff) | |
download | supple-5f232e4aaaad5b56d970a425c532e95240f82491.tar.gz |
SUPPLE: Better support for error messages, show them in the example
Diffstat (limited to 'lib')
-rw-r--r-- | lib/supple/comms.lua | 143 | ||||
-rw-r--r-- | lib/supple/host.lua | 27 | ||||
-rw-r--r-- | lib/supple/objects.lua | 27 | ||||
-rw-r--r-- | lib/supple/request.lua | 2 | ||||
-rw-r--r-- | lib/supple/sandbox.lua | 2 |
5 files changed, 134 insertions, 67 deletions
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) |