Initial commit with CombinedConfig and daemonize implementations.
This commit is contained in:
commit
f77efa1cd7
83
cliutils.nim
Normal file
83
cliutils.nim
Normal file
@ -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
|
11
cliutils.nimble
Normal file
11
cliutils.nimble
Normal file
@ -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"]
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user