My program is a website manager which is browser based. The user can enable and disable plugins from the plugin-page. The plugins are included at compiletime with macros, therefore I need to close the program, re-compile it with user specified parameters and then start it again.
I have been experimenting with execCmd() and startProcess() in various combination with supporting .sh and .nim files. But when my program has been recompiled under a new name, e.g. -o:newName, I am closing (quit()) the main-program-process, but this closes the child-processes running the support files, which should start the main-program-process again = the new compiled program does not start again.
My current solution is using a script.sh with a loop and checking for newName on each loop, but I do not want to force the end user to use this script for running the program.
until ./main-program; do
echo "main-program exited $?. Respawning.." >&2
sleep 1
cp main-program main-program.bak
mv newName main-program
done
Just found this on StackOverflow.
Have you played Minecraft?
The game has a "launcher" that gets started to manage the game session, and it can restart the game if it crashes. Anyway, you could make a launcher (no GUI or user input needed of course) in Nim. The launcher could then call the main executable with exec().
So there would be two executables - the actual one (it gets recompiled often), and the "bootstrap". Both could be written in Nim. The important part is that the bootstrap invokes another executable using exec(). It does not import the other stuff and call it directly.
Good idea twetzel59! Thanks for digging into it.
I'll give it a try a later and return with my results.
The launcher now works as a standalone and as a nimble package.
Folder structure:
websitecreator.nim <-- Launcher
websitecreator_main.nim <-- Main executable
Code (websitecreator.nim):
import osproc, os, sequtils
proc checkCompileOptions(): string =
# Checking for known compile options
# and returning them as a space separated string.
# See README.md for explation of the options.
result = ""
when defined(newdb):
result.add(" -d:newdb")
when defined(newuser):
result.add(" -d:newuser")
when defined(insertdata):
result.add(" -d:insertdata")
when defined(nginx):
result.add(" -d:nginx")
when defined(adminnotify):
result.add(" -d:adminnotify")
when defined(dev):
result.add(" -d:dev")
when defined(devemailon):
result.add(" -d:devemailon")
when defined(demo):
result.add(" -d:demo")
let compileOptions = checkCompileOptions()
# User specified args
template addArgs(inExec = false): string =
let args = foldl(commandLineParams(), a & (b & " "), "")
if inExec:
" --run " & args
else:
" " & args
proc launcherActivated() =
# 1) Executing the main-program in a loop.
# 2) Each time the main-program quits, there's a check
# for a new version
echo "Launcher initialized"
while true:
if fileExists(getAppDir() & "/websitecreator_main_new"):
moveFile(getAppDir() & "/websitecreator_main_new", getAppDir() & "/websitecreator_main")
echo execProcess(getAppDir() & "/websitecreator_main" & addArgs(true))
echo "Quitted"
# Checking if the main-program file exists. If not it will
# be compiled with args and compiler options (compiler
# options should be specified in the *.nim.pkg)
if not fileExists(getAppDir() & "/websitecreator_main") or compileOptions != "":
echo "Compiling"
echo " - Using params:" & addArgs()
echo " - Using compile options in *.nim.cfg"
echo " "
echo " .. please wait while compiling"
let output = execCmd("nim c " & compileOptions & " " & getAppDir() & "/websitecreator_main.nim")
if output == 1:
echo "\nAn error occured"
else:
echo "\nCompiling done. Starting:"
launcherActivated()
else:
launcherActivated()