7 Commits
0.1.0 ... 0.3.4

3 changed files with 88 additions and 4 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
nimcache/
cliutils
*.sw?

View File

@ -1,5 +1,7 @@
import docopt, json, posix, nre, strutils import docopt, json, osproc, posix, nre, streams, strtabs, unicode
import os except sleep import os except sleep
import strutils except toUpper, toLower
type type
CombinedConfig* = object CombinedConfig* = object
@ -17,6 +19,85 @@ proc getVal*(cfg: CombinedConfig, key, default: string): string =
else: return default 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 makeProcMsgHandler*(outSink, errSink: File, prefixCmd: bool = true): HandleProcMsgCB =
result = proc(outMsg, errMsg: TaintedString, cmd: string): void {.closure.} =
let prefix = if cmd == nil or not prefixCmd: "" else: cmd & ": "
if outMsg != nil: outSink.writeLine(prefix & outMsg)
if errMsg != nil: errSink.writeLine(prefix & errMsg)
proc makeProcMsgHandler*(outSink, errSink: Stream, prefixCmd: bool = true): HandleProcMsgCB =
result = proc(outMsg, errMsg: TaintedString, cmd: string): void {.closure.} =
let prefix = if cmd == nil or not prefixCmd: "" else: cmd & ": "
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)
proc waitFor*(p: Process, msgCB: HandleProcMsgCB, procCmd: string = ""): int =
var pout = outputStream(p)
var perr = errorStream(p)
var line = newStringOfCap(120).TaintedString
while true:
if pout.readLine(line):
msgCB.sendMsg(line, nil, procCmd)
elif perr.readLine(line):
msgCB.sendMsg(nil, line, procCmd)
else:
result = peekExitCode(p)
if result != -1: break
close(p)
proc exec*(command: string, workingDir: string = "",
args: openArray[string] = [], env: StringTableRef = nil,
options: set[ProcessOption] = {poUsePath},
msgCB: HandleProcMsgCB = nil): int
{.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
var p = startProcess(command, workingDir, args, env, options)
result = waitFor(p, msgCB, command)
proc execWithOutput*(command: string, workingDir:string = "",
args: openArray[string] = [], env: StringTableRef = nil,
options: set[ProcessOption] = {poUsePath},
msgCB: HandleProcMsgCB = nil):
tuple[output: TaintedString, error: TaintedString, exitCode: int] =
result = (TaintedString"", TaintedString"", -1)
var outSeq, errSeq: seq[TaintedString]
outSeq = @[]; errSeq = @[]
var outputCollector = combineProcMsgHandlers(msgCB,
proc(outMsg, errMsg: TaintedString, cmd: string): void {.closure.} =
if outMsg != nil: outSeq.add(outMsg)
if errMsg != nil: errSeq.add(errMsg))
result[2] = exec(command, workingDir, args, env, options, outputCollector)
result[0] = outSeq.join("\n")
result[1] = errSeq.join("\n")
## Daemonize
var var
pidFileInner: string pidFileInner: string
fi, fo, fe: File fi, fo, fe: File
@ -29,7 +110,7 @@ proc onStop(sig: cint) {.noconv.} =
quit(QuitSuccess) quit(QuitSuccess)
proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): int = proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): Pid =
if fileExists(pidfile): if fileExists(pidfile):
raise newException(IOError, "pidfile " & pidfile & " already exists, daemon already running?") raise newException(IOError, "pidfile " & pidfile & " already exists, daemon already running?")

View File

@ -1,11 +1,11 @@
# Package # Package
version = "0.1.0" version = "0.3.4"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Helper functions for writing command line interfaces." description = "Helper functions for writing command line interfaces."
license = "MIT" license = "MIT"
# Dependencies # Dependencies
requires @["nim >= 0.15.3", "docopt"] requires @["nim >= 0.18.0", "docopt"]