From f77efa1cd7e700e977468b2f58acf0c246a03d68 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 4 Nov 2016 16:30:06 -0500 Subject: [PATCH] Initial commit with CombinedConfig and daemonize implementations. --- cliutils.nim | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ cliutils.nimble | 11 +++++++ 2 files changed, 94 insertions(+) create mode 100644 cliutils.nim create mode 100644 cliutils.nimble diff --git a/cliutils.nim b/cliutils.nim new file mode 100644 index 0000000..1d5940d --- /dev/null +++ b/cliutils.nim @@ -0,0 +1,83 @@ +import docopt, json, posix, nre, strutils +import os except sleep + +type + CombinedConfig* = object + docopt*: Table[string, Value] + json*: JsonNode + +proc getVal*(cfg: CombinedConfig, key, default: string): string = + let argKey = "--" & key + let envKey = key.replace('-', '_').toUpper + let jsonKey = key.replace(re"(-\w)", proc (m: RegexMatch): string = ($m)[1..1].toUpper) + + if cfg.docopt[argKey]: return $cfg.docopt[argKey] + elif existsEnv(envKey): return getEnv(envKey) + elif cfg.json.hasKey(jsonKey): return cfg.json[jsonKey].getStr + else: return default + + +var + pidFileInner: string + fi, fo, fe: File + +proc onStop(sig: cint) {.noconv.} = + close(fi) + close(fo) + close(fe) + removeFile(pidFileInner) + + quit(QuitSuccess) + +proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): int = + + if fileExists(pidfile): + raise newException(IOError, "pidfile " & pidfile & " already exists, daemon already running?") + + let pid1 = fork() + + # Are we the child process? + if pid1 == 0: + + # Yes, so let's get ready to execute the main code given to us. + discard chdir("/") + discard setsid() + discard umask(0) + + # Fork again... but I'm not sure why. + let pid2 = fork() + + # We don't need the intermediate process, so if we are not the child this + # time, lets just quit + if pid2 > 0: quit(QuitSuccess) + + # If we are the grandchild let's set up our environment. + flushFile(stdout) + flushFile(stderr) + + if not si.isNil and si != "": + fi = open(si, fmRead) + discard dup2(getFileHandle(fi), getFileHandle(stdin)) + + if not so.isNil and so != "": + fo = open(so, fmAppend) + discard dup2(getFileHandle(fo), getFileHandle(stdout)) + + if not se.isNil and so != "": + fe = open(se, fmAppend) + discard dup2(getFileHandle(fe), getFileHandle(stderr)) + + pidFileInner = pidfile + + # Add hooks to cleanup after ourselves when we're asked to die. + signal(SIGINT, onStop) + signal(SIGTERM, onStop) + + # Find out what our actual PID is and save it + let childPid = getpid() + writeFile(pidfile, $childPid) + + # Finally, execute our main + daemonMain() + + return pid1 diff --git a/cliutils.nimble b/cliutils.nimble new file mode 100644 index 0000000..eebaf6f --- /dev/null +++ b/cliutils.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Jonathan Bernard" +description = "Helper functions for writing command line interfaces." +license = "MIT" + +# Dependencies + +requires @["nim >= 0.15.3", "docopt"] +