From be91137318d2a5ce317f4b3dcd3ba3829218aaa6 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Tue, 15 Aug 2017 14:01:08 -0500 Subject: [PATCH] Added blocking process execution, ENV loading. --- .gitignore | 3 +++ cliutils.nim | 72 ++++++++++++++++++++++++++++++++++++++++++++++++- cliutils.nimble | 2 +- 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..516fad9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +nimcache/ +cliutils +*.sw? diff --git a/cliutils.nim b/cliutils.nim index 1d5940d..b53d99f 100644 --- a/cliutils.nim +++ b/cliutils.nim @@ -1,4 +1,4 @@ -import docopt, json, posix, nre, strutils +import docopt, json, osproc, posix, nre, streams, strutils, strtabs import os except sleep type @@ -17,6 +17,76 @@ proc getVal*(cfg: CombinedConfig, key, default: string): string = else: return default +proc loadEnv*(): StringTableRef = + result = newStringTable() + + for k, v in envPairs(): + result[k] = v + +## Process execution +type HandleProcMsgCB* = proc (outMsg: TaintedString, + errMsg: TaintedString, cmd: string): void + +proc sendMsg*(h: HandleProcMsgCB, outMsg: TaintedString, + errMsg: TaintedString = nil, cmd: string): void = + if h != nil: h(outMsg, errMsg, cmd) + +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 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) + + +## Daemonize + var pidFileInner: string fi, fo, fe: File diff --git a/cliutils.nimble b/cliutils.nimble index eebaf6f..24ecbbd 100644 --- a/cliutils.nimble +++ b/cliutils.nimble @@ -1,6 +1,6 @@ # Package -version = "0.1.0" +version = "0.2.0" author = "Jonathan Bernard" description = "Helper functions for writing command line interfaces." license = "MIT"