//go:build windows package update import ( "context" "fmt" "os" "os/exec" "path/filepath" "syscall" ) // Apply downloads the new exe and schedules replacement after exit (Windows). func Apply(ctx context.Context, manifestURL string) (string, error) { latest, _, _, exe, tmp, err := prepareDownload(ctx, manifestURL) if err != nil { return "", err } dir := filepath.Dir(exe) bat := filepath.Join(dir, "navis-update.bat") script := "@echo off\r\n" + "setlocal EnableExtensions\r\n" + "cd /d \"" + dir + "\"\r\n" + "set \"EXE=" + exe + "\"\r\n" + "set \"NEW=" + tmp + "\"\r\n" + ":wait\r\n" + "ping -n 2 127.0.0.1 >nul\r\n" + "del /f /q \"%EXE%\" >nul 2>&1\r\n" + "if exist \"%EXE%\" goto wait\r\n" + "move /y \"%NEW%\" \"%EXE%\" >nul\r\n" + "if not exist \"%EXE%\" exit /b 1\r\n" + "start \"\" \"%EXE%\"\r\n" + "exit /b 0\r\n" if err := os.WriteFile(bat, []byte(script), 0o755); err != nil { return "", err } cmd := exec.Command("cmd.exe", "/C", bat) cmd.Dir = dir cmd.SysProcAttr = &syscall.SysProcAttr{ HideWindow: true, CreationFlags: 0x00000008 | 0x00000200, // DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP } if err := cmd.Start(); err != nil { return "", fmt.Errorf("start updater: %w", err) } return latest, nil }