package main import ( "os/exec" "path/filepath" ) // relaunchCmd builds the command that starts OpsLog again — after an update, or // after a database switch. // // It exists to hold one fact in one place: a relaunch of OPSLOG ITSELF must not // suppress the new process's window. // // The auto-update relaunch used to go through hideConsole, which sets // SysProcAttr{HideWindow: true}. On Windows that puts SW_HIDE into the // STARTUPINFO handed to CreateProcess, and Windows applies it to the first // top-level window the new process shows. So the updated OpsLog started // perfectly, took the single-instance mutex, connected the rig — and never // became visible. Reported by two operators on 0.27.23 as "it goes to reload // and just fails to load": a process in the task manager, no window, killing it // and starting it by hand working every time. // // It arrived with the removal of the PowerShell helper. PowerShell's // Start-Process launched the exe with a normal show, and the direct // exec.Command that replaced it borrowed hideConsole from the console tools // beside it — where hiding a console window is exactly right, and where every // other caller still belongs. Two self-relaunches then differed by that one // line, and only the hidden one was ever reported broken. // // So: nothing that touches the WINDOW. RestartApp never called hideConsole and // the database-switch relaunch never showed the fault, which is what proved it. // There is no console to suppress either way — OpsLog is linked for the Windows // GUI subsystem. What SysProcAttr does carry now is detachment, below, which is // about process parentage and not about the window. // Two things the PowerShell helper did that the direct launch did not, both // restored here after operators kept reporting the relaunch failing: // // 1. It launched through Start-Process, so the new OpsLog was a child of // PowerShell — which then exited. The direct launch makes it a child of // the OpsLog that is dying, inside the same process group and console. // detachProcess puts it back on its own. // 2. It slept 400 ms after the old process was gone, before starting // anything. See postExitSettle in main.go. func relaunchCmd(exe string, args ...string) *exec.Cmd { cmd := exec.Command(exe, args...) cmd.Dir = filepath.Dir(exe) detachProcess(cmd) return cmd }