//go:build windows package selfupdate import ( "os" "path/filepath" ) // swap replaces target with newPath. Windows cannot rename a file onto // a running executable, but it can rename the running executable out of // the way first: move target -> target.old, then move new -> target. // target.old is removed best-effort; if Windows holds it open, the file // remains and the caller should print a one-line hint. func swap(newPath, target string) error { info, err := os.Stat(target) if err != nil { return err } dir := filepath.Dir(target) tmp, err := os.CreateTemp(dir, ".eeco-new-*") if err != nil { return err } tmpName := tmp.Name() if err := tmp.Close(); err != nil { os.Remove(tmpName) return err } if err := copyFile(newPath, tmpName); err != nil { os.Remove(tmpName) return err } if err := os.Chmod(tmpName, info.Mode()); err != nil { os.Remove(tmpName) return err } old := target + ".old" _ = os.Remove(old) if err := os.Rename(target, old); err != nil { os.Remove(tmpName) return err } if err := os.Rename(tmpName, target); err != nil { _ = os.Rename(old, target) os.Remove(tmpName) return err } _ = os.Remove(old) return nil }