Restoring the PowerShell helper put it in update.go, which is shared — so a Linux build would have tried to run `powershell` to relaunch itself. It compiled and vetted cleanly for linux/amd64, which is exactly why it needed catching before somebody built it: the fault only shows on a real update, on a machine that has no PowerShell. scheduleRelaunch now lives in the platform files. Windows keeps the helper. Linux starts the new binary directly, which is right there and not a compromise: nothing holds an executable open while it runs, so the swap has already succeeded, and there is no mutex to race — the single-instance guard is an flock the dying process releases as it exits, and the new one waits for our pid first. The two guards were looking at the old location and had to follow: the Wait-Process/Start-Process check moves into relaunch_windows_test.go where it belongs, and TestEveryRelaunchPassesItsPid now scans updateswap_linux.go too — the direct spawn moved there, and without it the test would have gone quiet again. Checked from Windows, as BUILDING-LINUX.md says is done at every release: GOOS=linux go build ./... and go vet ./... both clean.
54 lines
1.8 KiB
Go
54 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestWaitPidArg(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
args []string
|
|
want int
|
|
}{
|
|
{"after the flag", []string{"--post-update", "--wait-pid", "4321"}, 4321},
|
|
{"joined with =", []string{"--wait-pid=4321"}, 4321},
|
|
{"absent", []string{"--post-update"}, 0},
|
|
{"flag with nothing after it", []string{"--wait-pid"}, 0},
|
|
{"not a number", []string{"--wait-pid", "later"}, 0},
|
|
} {
|
|
if got := waitPidArg(tc.args); got != tc.want {
|
|
t.Errorf("%s: got %d, wanted %d", tc.name, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A relaunch started from INSIDE this process has to tell the new one which
|
|
// process to wait for.
|
|
//
|
|
// The update path no longer does that from inside: its PowerShell helper waits
|
|
// for the pid and starts the exe once we are gone, which is what two rewrites
|
|
// failed to reproduce. RestartApp still spawns directly, and if a relaunch is
|
|
// ever added the same way without --wait-pid, it is the old bug again.
|
|
func TestEveryRelaunchPassesItsPid(t *testing.T) {
|
|
// Both spellings: a relaunch built inline with exec.Command, and one built
|
|
// through relaunchCmd. The pattern used to name only the first, and when the
|
|
// update path moved to a PowerShell helper and RestartApp to relaunchCmd it
|
|
// quietly matched nothing at all — a guard that passes because it looks
|
|
// nowhere.
|
|
spawn := regexp.MustCompile(`(exec\.Command|relaunchCmd)\(exe, "--(post-update|relaunch)"[^)]*\)`)
|
|
for _, file := range []string{"update.go", "app.go", "updateswap_linux.go"} {
|
|
src, err := os.ReadFile(file)
|
|
if err != nil {
|
|
t.Fatalf("read %s: %v", file, err)
|
|
}
|
|
for _, call := range spawn.FindAllString(string(src), -1) {
|
|
if !strings.Contains(call, "--wait-pid") {
|
|
t.Errorf("%s: %s does not tell the new instance which process to wait for", file, call)
|
|
}
|
|
}
|
|
}
|
|
}
|