# # # add_file "tests/common/automate_stdio.lua" # content [9a6086c1c1cbb2fbb79cbd77264228c6bca5abda] # ============================================================ --- tests/common/automate_stdio.lua 9a6086c1c1cbb2fbb79cbd77264228c6bca5abda +++ tests/common/automate_stdio.lua 9a6086c1c1cbb2fbb79cbd77264228c6bca5abda @@ -0,0 +1,150 @@ +stdio = {} +stdio.got = {} +stdio.buffer = "" + +function stdio.start(opts) + local args = {} + local fn = mtn + + table.insert(args, "automate") + table.insert(args, "stdio") + + if type(opts) == "table" then + for k, v in pairs(opts) do + table.insert(args, v) + end + end + + local argv = fn(unpack(args)) + local out = bg(argv, false, false, false) + local mt = getmetatable(out) + + mt.enqueue = function(obj, cmd, opts, callback) + if (type(opts) ~= "table" and type(opts) ~= "nil") then + err("enqueue wants a table or nil as opts") + end + + if (type(cmd) ~= "table") then + err("enqueue wants a table as cmd") + end + + local cmdStr = "" + + if (type(opts) ~= "table" then + cmdStr = cmdStr .. "o" + for k, v in pairs(opts) do + cmdStr = cmdStr .. string.len(v) .. ":" .. v + end + cmdStr = cmdStr .. "e " + end + + cmdStr = cmdStr .. "l" + for k, v in pairs(cmd) do + cmdStr = cmdStr .. string.len(v) .. ":" .. v + end + cmdStr = cmdStr .. "e" + + stdio.write(obj, cmdStr, callback) + end + + return out +end + +function stdio.write(proc, input, callback) +end + +function stdio.parse(dat) + -- append new data to the buffer + stdio.buffer = stdio.buffer .. dat + + while true do + local startIdx, endIdx, cmdNum, cmdExitCode, msgBand, msgLen = + string.find(stdio.buffer, "(%d+):(%d+):([mlewpt]):(%d+):") + + cmdNum = cmdNum + 0 + cmdExitCode = cmdExitCode + 0 + msgLen = msgLen + 0 + + -- check if we need to wait for more data + if startIdx == nil or + msgLen > string.len(string.sub(stdio.buffer, endIdx + 1)) then + break + end + + if stdio.got[cmdNum] == nil then stdio.got[cmdNum] = {} end + + -- no msg for this command should follow once we processed 'l' + check(stdio.got[cmdNum]['exitCode'] == nil) + + -- process the different bands + payload = string.sub(buffer, endIdx+1, endIdx+msgLen) + + if msgBand ~= "t" then + if msgBand == "l" then + stdio.got[cmdNum]['exitCode'] = cmdExitCode + msgBand = "m" + end + if stdio.got[cmdNum][msgBand] == nil then + stdio.got[cmdNum][msgBand] = "" + end + stdio.got[cmdNum][msgBand] = stdio.got[cmdNum][msgBand] .. payload + else + if stdio.got[cmdNum]['tickers'] == nil then + stdio.got[cmdNum]['tickers'] = {} + end + -- it makes no sense to remember the inbetween states of the ticker + -- elements, so we only note the max and the currently reached count + -- as well as the ticker's name + for tick in string.gmatch(payload, "[^;]+;") do + local startIdx, endIdx, tickSym, tickVal = + string.find(tick, "(%a+)([^;]*);") + check(startIdx ~= nil) + + if (string.len(tickVal) == 0) then + check(stdio.got[cmdNum]['tickers'][tickSym] ~= nil) + check(stdio.got[cmdNum]['tickers'][tickSym]['finished'] == nil) + stdio.got[cmdNum]['tickers'][tickSym]['finished'] = true + else + local tickType = string.sub(tickVal, 1, 1) + tickVal = string.sub(tickVal, 2) + + -- the ticker definition - should be the very first thing + if tickType == ":" then + check(stdio.got[cmdNum]['tickers'][tickSym] == nil) + stdio.got[cmdNum]['tickers'][tickSym] = {} + stdio.got[cmdNum]['tickers'][tickSym]['name'] = tickVal + -- the ticker initialization - this might come in a couple of times + elseif tickType == "=" then + check(stdio.got[cmdNum]['tickers'][tickSym] ~= nil) + check(stdio.got[cmdNum]['tickers'][tickSym]['max'] = tickVal + 0 + -- the ticker progress value + elseif tickType == "#" then + check(stdio.got[cmdNum]['tickers'][tickSym] ~= nil) + check(stdio.got[cmdNum]['tickers'][tickSym]['max'] ~= nil) + + stdio.got[cmdNum]['tickers'][tickSym]['current'] = tickVal + 0 + + check(stdio.got[cmdNum]['tickers'][tickSym]['max'] == 0 or + stdio.got[cmdNum]['tickers'][tickSym]['max'] >= + stdio.got[cmdNum]['tickers'][tickSym]['current']) + else + check(false) + end + + -- this should throw if we get a tick after the ticker + -- has already been finished + check(stdio.got[cmdNum]['tickers'][tickSym]['finished'] == nil) + end + end + end + stdio.buffer = string.sub(stdio.buffer, endIdx+1+msgLen) + end +end + +function stdio.get(cmdNum) + local out = stdio.got[cmdNum] + if out ~= nil then + table.remove(stdio.got, cmdNum) + end + return out +end