import os, osproc, streams, strtabs from posix import kill type HandleProcMsgCB* = proc (outMsg: TaintedString, errMsg: TaintedString, cmd: string): void proc sendMsg*(h: HandleProcMsgCB, outMsg: TaintedString, errMsg: TaintedString = nil, cmd: string = "strawboss"): void = if h != nil: h(outMsg, errMsg, cmd) proc raiseEx*(reason: string): void = raise newException(Exception, reason) proc envToTable*(): StringTableRef = result = newStringTable() for k, v in envPairs(): result[k] = v proc waitForWithOutput*(p: Process, msgCB: HandleProcMsgCB, procCmd: string = ""): tuple[output: TaintedString, error: TaintedString, exitCode: int] = var pout = outputStream(p) var perr = errorStream(p) result = (TaintedString"", TaintedString"", -1) var line = newStringOfCap(120).TaintedString while true: if pout.readLine(line): msgCB.sendMsg(line, nil, procCmd) result[0].string.add(line.string) result[0].string.add("\n") elif perr.readLine(line): msgCB.sendMsg(nil, line, procCmd) result[1].string.add(line.string) result[1].string.add("\n") else: result[2] = peekExitCode(p) if result[2] != -1: break close(p) proc exec*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poUsePath}, msgCB: HandleProcMsgCB = nil): tuple[output: TaintedString, error: TaintedString, exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} = var p = startProcess(command, workingDir, args, env, options) result = waitForWithOutput(p, msgCb, command) proc loadEnv*(): StringTableRef = result = newStringTable() for k, v in envPairs(): result[k] = v proc makeProcMsgHandler*(outSink, errSink: File): HandleProcMsgCB = result = proc(outMsg, errMsg: TaintedString, cmd: string): void {.closure.} = let prefix = if cmd != nil: cmd & ": " else: "" if outMsg != nil: outSink.writeLine(prefix & outMsg) if errMsg != nil: errSink.writeLine(prefix & errMsg) proc makeProcMsgHandler*(outSink, errSink: Stream): HandleProcMsgCB = result = proc(outMsg, errMsg: TaintedString, cmd: string): void {.closure.} = let prefix = if cmd != nil: cmd & ": " else: "" if outMsg != nil: outSink.writeLine(prefix & outMsg) if errMsg != nil: errSink.writeLine(prefix & errMsg) proc combineProcMsgHandlers*(a, b: HandleProcMsgCB): HandleProcMsgCB = if a == nil: result = b elif b == nil: result = a else: result = proc(cmd: string, outMsg, errMsg: TaintedString): void = a(cmd, outMsg, errMsg) b(cmd, outMsg, errMsg)