diff --git a/selfupdate.go b/selfupdate.go index 3917b31..a91efb7 100644 --- a/selfupdate.go +++ b/selfupdate.go @@ -230,12 +230,7 @@ func (c config) Install(tag, asset string) error { } } - c.Printf("moving to %#v\n", target) - if err = os.Rename(fExecutable.Name(), target); err != nil { - return err - } - - return nil + return c.swap(fExecutable.Name(), target) } func (c config) verify(executable string) error { diff --git a/swap.go b/swap.go new file mode 100644 index 0000000..eba4088 --- /dev/null +++ b/swap.go @@ -0,0 +1,12 @@ +//go:build !windows + +package selfupdate + +import ( + "os" +) + +func (c config) swap(source, target string) error { + c.Printf("moving to %#v\n", target) + return os.Rename(source, target) +} diff --git a/swap_windows.go b/swap_windows.go new file mode 100644 index 0000000..c38c4f6 --- /dev/null +++ b/swap_windows.go @@ -0,0 +1,46 @@ +package selfupdate + +import ( + "os" + "syscall" +) + +func (c config) swap(source, target string) error { + old := target + ".old" + if _, err := os.Stat(old); err == nil { + if err := c.confirm("remove %#v\n", old); err != nil { + return err + } + if err := os.Remove(old); err != nil { + return err + } + } + + c.Printf("moving current executable to %#v\n", old) + if err := os.Rename(target, old); err != nil { + return err + } + + c.Printf("moving new executable to %#v\n", target) + if err := os.Rename(source, target); err != nil { + _ = os.Rename(old, target) // try to restore old executable + return err + } + + c.Printf("hiding %#v\n", old) + return setHidden(old) +} + +func setHidden(path string) error { + filenameW, err := syscall.UTF16PtrFromString(path) + if err != nil { + return err + } + + err = syscall.SetFileAttributes(filenameW, syscall.FILE_ATTRIBUTE_HIDDEN) + if err != nil { + return err + } + + return nil +}