Files
2026-07-13 13:00:08 +08:00

73 lines
2.1 KiB
Go

//go:build windows
package main
import (
"os"
"os/exec"
"path/filepath"
"syscall"
"time"
)
const windowsUpdateHelperFileName = "reasonix-update-helper.exe"
// installerCommand runs the NSIS updater, forcing $INSTDIR to dir via /D= so the
// update overwrites the current install in place. NSIS requires /D= to be the
// final, unquoted token taken verbatim to the end of the line, so the raw command
// line is set directly — exec.Command would quote a path containing spaces (e.g.
// C:\Users\Jane Doe\...) and NSIS would then mis-parse the target directory.
func installerCommand(name, dir string) *exec.Cmd {
cmd := exec.Command(name)
cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: installerCommandLine(name, dir), HideWindow: true}
return cmd
}
func startWindowsUpdateHandoff(installerPath, installDir, relaunchPath string) error {
if err := startWindowsUpdateHelper(installerPath, installDir, relaunchPath); err == nil {
return nil
}
return installerCommand(installerPath, installDir).Start()
}
func startWindowsUpdateHelper(installerPath, installDir, relaunchPath string) error {
if installDir == "" {
return os.ErrNotExist
}
helperPath, err := prepareWindowsUpdateHelper(installDir)
if err != nil {
return err
}
cmd := exec.Command(helperPath, windowsUpdateHandoffArgs(os.Getpid(), installerPath, installDir, relaunchPath)...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
return cmd.Start()
}
func prepareWindowsUpdateHelper(installDir string) (string, error) {
src := filepath.Join(installDir, windowsUpdateHelperFileName)
data, err := os.ReadFile(src)
if err != nil {
return "", err
}
dir, err := updateCacheDir()
if err != nil {
return "", err
}
cleanupWindowsUpdateHelpers(dir)
dst := filepath.Join(dir, "reasonix-update-helper-"+time.Now().UTC().Format("20060102150405.000000000")+".exe")
if err := os.WriteFile(dst, data, 0o700); err != nil {
return "", err
}
return dst, nil
}
func cleanupWindowsUpdateHelpers(dir string) {
matches, err := filepath.Glob(filepath.Join(dir, "reasonix-update-helper-*.exe"))
if err != nil {
return
}
for _, name := range matches {
_ = os.Remove(name)
}
}