diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 6359c9b..93e34d8 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,19 +1,7 @@ { "ImportPath": "github.com/sanbornm/go-selfupdate", - "GoVersion": "go1.3", - "Packages": [ - "./selfupdate/" - ], + "GoVersion": "go1.4", "Deps": [ - { - "ImportPath": "bitbucket.org/kardianos/osext", - "Comment": "null-13", - "Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e" - }, - { - "ImportPath": "github.com/inconshreveable/go-update", - "Rev": "221d034a558b4c21b0624b2a450c076913854a57" - }, { "ImportPath": "github.com/kr/binarydist", "Rev": "9955b0ab8708602d411341e55fffd7e0700f86bd" diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE deleted file mode 100644 index 18527a2..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 Daniel Theophanes - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go deleted file mode 100644 index 37efbb2..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Extensions to the standard "os" package. -package osext - -import "path/filepath" - -// Executable returns an absolute path that can be used to -// re-invoke the current program. -// It may not be valid after the current program exits. -func Executable() (string, error) { - p, err := executable() - return filepath.Clean(p), err -} - -// Returns same path as Executable, returns just the folder -// path. Excludes the executable name. -func ExecutableFolder() (string, error) { - p, err := Executable() - if err != nil { - return "", err - } - folder, _ := filepath.Split(p) - return folder, nil -} - -// Depricated. Same as Executable(). -func GetExePath() (exePath string, err error) { - return Executable() -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go deleted file mode 100644 index 4468a73..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package osext - -import ( - "syscall" - "os" - "strconv" -) - -func executable() (string, error) { - f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") - if err != nil { - return "", err - } - defer f.Close() - return syscall.Fd2path(int(f.Fd())) -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go deleted file mode 100644 index 546fec9..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux netbsd openbsd - -package osext - -import ( - "errors" - "os" - "runtime" -) - -func executable() (string, error) { - switch runtime.GOOS { - case "linux": - return os.Readlink("/proc/self/exe") - case "netbsd": - return os.Readlink("/proc/curproc/exe") - case "openbsd": - return os.Readlink("/proc/curproc/file") - } - return "", errors.New("ExecPath not implemented for " + runtime.GOOS) -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go deleted file mode 100644 index b66cac8..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin freebsd - -package osext - -import ( - "os" - "path/filepath" - "runtime" - "syscall" - "unsafe" -) - -var initCwd, initCwdErr = os.Getwd() - -func executable() (string, error) { - var mib [4]int32 - switch runtime.GOOS { - case "freebsd": - mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} - case "darwin": - mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} - } - - n := uintptr(0) - // Get length. - _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) - if errNum != 0 { - return "", errNum - } - if n == 0 { // This shouldn't happen. - return "", nil - } - buf := make([]byte, n) - _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) - if errNum != 0 { - return "", errNum - } - if n == 0 { // This shouldn't happen. - return "", nil - } - for i, v := range buf { - if v == 0 { - buf = buf[:i] - break - } - } - var err error - execPath := string(buf) - // execPath will not be empty due to above checks. - // Try to get the absolute path if the execPath is not rooted. - if execPath[0] != '/' { - execPath, err = getAbs(execPath) - if err != nil { - return execPath, err - } - } - // For darwin KERN_PROCARGS may return the path to a symlink rather than the - // actual executable. - if runtime.GOOS == "darwin" { - if execPath, err = filepath.EvalSymlinks(execPath); err != nil { - return execPath, err - } - } - return execPath, nil -} - -func getAbs(execPath string) (string, error) { - if initCwdErr != nil { - return execPath, initCwdErr - } - // The execPath may begin with a "../" or a "./" so clean it first. - // Join the two paths, trailing and starting slashes undetermined, so use - // the generic Join function. - return filepath.Join(initCwd, filepath.Clean(execPath)), nil -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go deleted file mode 100644 index dc661db..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin linux freebsd netbsd windows - -package osext - -import ( - "fmt" - "os" - oexec "os/exec" - "path/filepath" - "runtime" - "testing" -) - -const execPath_EnvVar = "OSTEST_OUTPUT_EXECPATH" - -func TestExecPath(t *testing.T) { - ep, err := Executable() - if err != nil { - t.Fatalf("ExecPath failed: %v", err) - } - // we want fn to be of the form "dir/prog" - dir := filepath.Dir(filepath.Dir(ep)) - fn, err := filepath.Rel(dir, ep) - if err != nil { - t.Fatalf("filepath.Rel: %v", err) - } - cmd := &oexec.Cmd{} - // make child start with a relative program path - cmd.Dir = dir - cmd.Path = fn - // forge argv[0] for child, so that we can verify we could correctly - // get real path of the executable without influenced by argv[0]. - cmd.Args = []string{"-", "-test.run=XXXX"} - cmd.Env = []string{fmt.Sprintf("%s=1", execPath_EnvVar)} - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("exec(self) failed: %v", err) - } - outs := string(out) - if !filepath.IsAbs(outs) { - t.Fatalf("Child returned %q, want an absolute path", out) - } - if !sameFile(outs, ep) { - t.Fatalf("Child returned %q, not the same file as %q", out, ep) - } -} - -func sameFile(fn1, fn2 string) bool { - fi1, err := os.Stat(fn1) - if err != nil { - return false - } - fi2, err := os.Stat(fn2) - if err != nil { - return false - } - return os.SameFile(fi1, fi2) -} - -func init() { - if e := os.Getenv(execPath_EnvVar); e != "" { - // first chdir to another path - dir := "/" - if runtime.GOOS == "windows" { - dir = filepath.VolumeName(".") - } - os.Chdir(dir) - if ep, err := Executable(); err != nil { - fmt.Fprint(os.Stderr, "ERROR: ", err) - } else { - fmt.Fprint(os.Stderr, ep) - } - os.Exit(0) - } -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go deleted file mode 100644 index 72d282c..0000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package osext - -import ( - "syscall" - "unicode/utf16" - "unsafe" -) - -var ( - kernel = syscall.MustLoadDLL("kernel32.dll") - getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") -) - -// GetModuleFileName() with hModule = NULL -func executable() (exePath string, err error) { - return getModuleFileName() -} - -func getModuleFileName() (string, error) { - var n uint32 - b := make([]uint16, syscall.MAX_PATH) - size := uint32(len(b)) - - r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) - n = uint32(r0) - if n == 0 { - return "", e1 - } - return string(utf16.Decode(b[0:n])), nil -} diff --git a/Godeps/_workspace/src/github.com/inconshreveable/go-update/README b/Godeps/_workspace/src/github.com/inconshreveable/go-update/README deleted file mode 100644 index 467def8..0000000 --- a/Godeps/_workspace/src/github.com/inconshreveable/go-update/README +++ /dev/null @@ -1,137 +0,0 @@ -PACKAGE DOCUMENTATION - -package update - import "github.com/inconshreveable/go-update" - - Package update allows a program to "self-update", replacing its - executable file with new bytes. - - Package update provides the facility to create user experiences like - auto-updating or user-approved updates which manifest as user prompts in - commercial applications with copy similar to "Restart to being using the - new version of X". - - Updating your program to a new version is as easy as: - - err := update.FromUrl("http://release.example.com/2.0/myprogram") - if err != nil { - fmt.Printf("Update failed: %v", err) - } - - The most low-level API is FromStream() which updates the current - executable with the bytes read from an io.Reader. - - Additional APIs are provided for common update strategies which include - updating from a file with FromFile() and updating from the internet with - FromUrl(). - - Using the more advaced Download.UpdateFromUrl() API gives you the - ability to resume an interrupted download to enable large updates to - complete even over intermittent or slow connections. This API also - enables more fine-grained control over how the update is downloaded from - the internet as well as access to download progress, - - -VARIABLES - -var ( - // Returned when the remote server indicates that no download is available - UpdateUnavailable error -) - - -FUNCTIONS - -func FromFile(filepath string) (err error) - FromFile reads the contents of the given file and uses them to update - the current program's executable file by calling FromStream(). - -func FromStream(newBinary io.Reader) (err error) - FromStream reads the contents of the supplied io.Reader newBinary and - uses them to update the current program's executable file. - - FromStream performs the following actions to ensure a cross-platform - safe update: - - - Renames the current program's executable file from - /path/to/program-name to /path/to/.program-name.old - - - Opens the now-empty path /path/to/program-name with mode 0755 and - copies the contents of newBinary into the file. - - - If the copy is successful, it erases /path/to/.program.old. If this - operation fails, no error is reported. - - - If the copy is unsuccessful, it attempts to rename - /path/to/.program-name.old back to /path/to/program-name. If this - operation fails, the error is not reported in order to not mask the - error that caused the rename recovery attempt. - -func FromUrl(url string) error - FromUrl downloads the contents of the given url and uses them to update - the current program's executable file. It is a convenience function - which is equivalent to - - NewDownload().UpdateFromUrl(url) - - See Download.UpdateFromUrl for more details. - - -TYPES - -type Download struct { - // net/http.Client to use when downloading the update. - // If nil, a default http.Client is used - HttpClient *http.Client - - // Path on the file system to dowload the update to - // If empty, a temporary file is used. - // After the download begins, this path will be set - // so that the client can use it to resume aborted - // downloads - Path string - - // Progress returns the percentage of the download - // completed as an integer between 0 and 100 - Progress chan (int) - - // HTTP Method to use in the download request. Default is "GET" - Method string -} - Type Download encapsulates the necessary parameters and state needed to - download an update from the internet. Create an instance with the - NewDownload() factory function. - - -func NewDownload() *Download - NewDownload initializes a new Download object - - -func (d *Download) UpdateFromUrl(url string) (err error) - UpdateFromUrl downloads the given url from the internet to a file on - disk and then calls FromStream() to update the current program's - executable file with the contents of that file. - - If the update is successful, the downloaded file will be erased from - disk. Otherwise, it will remain in d.Path to allow the download to - resume later or be skipped entirely. - - Only HTTP/1.1 servers that implement the Range header are supported. - - UpdateFromUrl() uses HTTP status codes to determine what action to take. - - - The HTTP server should return 200 or 206 for the update to be - downloaded. - - - The HTTP server should return 204 if no update is available at this - time. This will cause UpdateFromUrl to return the error - UpdateUnavailable. - - - If the HTTP server returns a 3XX redirect, it will be followed - according to d.HttpClient's redirect policy. - - - Any other HTTP status code will cause UpdateFromUrl to return an - error. - - - diff --git a/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go b/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go deleted file mode 100644 index eee72e2..0000000 --- a/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go +++ /dev/null @@ -1,455 +0,0 @@ -/* -Package update allows a program to "self-update", replacing its executable file -with new bytes. - -Package update provides the facility to create user experiences like auto-updating -or user-approved updates which manifest as user prompts in commercial applications -with copy similar to "Restart to being using the new version of X". - -Updating your program to a new version is as easy as: - - err := update.FromUrl("http://release.example.com/2.0/myprogram") - if err != nil { - fmt.Printf("Update failed: %v", err) - } - -The most low-level API is FromStream() which updates the current executable -with the bytes read from an io.Reader. - -Additional APIs are provided for common update strategies which include -updating from a file with FromFile() and updating from the internet with -FromUrl(). - -Using the more advaced Download.UpdateFromUrl() API gives you the ability -to resume an interrupted download to enable large updates to complete even -over intermittent or slow connections. This API also enables more fine-grained -control over how the update is downloaded from the internet as well as access to -download progress, -*/ -package update - -import ( - "compress/gzip" - "fmt" - "bitbucket.org/kardianos/osext" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "runtime" -) - -type MeteredReader struct { - rd io.ReadCloser - totalSize int64 - progress chan int - totalRead int64 - ticks int64 -} - -func (m *MeteredReader) Close() error { - return m.rd.Close() -} - -func (m *MeteredReader) Read(b []byte) (n int, err error) { - chunkSize := (m.totalSize / 100) + 1 - lenB := int64(len(b)) - - var nChunk int - for start := int64(0); start < lenB; start += int64(nChunk) { - end := start + chunkSize - if end > lenB { - end = lenB - } - - nChunk, err = m.rd.Read(b[start:end]) - - n += nChunk - m.totalRead += int64(nChunk) - - if m.totalRead > (m.ticks * chunkSize) { - m.ticks += 1 - // try to send on channel, but don't block if it's full - select { - case m.progress <- int(m.ticks + 1): - default: - } - - // give the progress channel consumer a chance to run - runtime.Gosched() - } - - if err != nil { - return - } - } - - return -} - -// We wrap the round tripper when making requests -// because we need to add headers to the requests we make -// even when they are requests made after a redirect -type RoundTripper struct { - RoundTripFn func(*http.Request) (*http.Response, error) -} - -func (rt *RoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { - return rt.RoundTripFn(r) -} - -// Type Download encapsulates the necessary parameters and state -// needed to download an update from the internet. Create an instance -// with the NewDownload() factory function. -// -// You may only use a Download once, -type Download struct { - // net/http.Client to use when downloading the update. - // If nil, a default http.Client is used - HttpClient *http.Client - - // Path on the file system to dowload the update to - // If empty, a temporary file is used. - // After the download begins, this path will be set - // so that the client can use it to resume aborted - // downloads - Path string - - // Progress returns the percentage of the download - // completed as an integer between 0 and 100 - Progress chan (int) - - // HTTP Method to use in the download request. Default is "GET" - Method string - - // HTTP URL to issue the download request to - Url string - - // Set to true when the server confirms a new version is available - // even if the updating process encounters an error later on - Available bool -} - -// NewDownload initializes a new Download object -func NewDownload(url string) *Download { - return &Download{ - HttpClient: new(http.Client), - Progress: make(chan int), - Method: "GET", - Url: url, - } -} - -func (d *Download) sharedHttp(offset int64) (resp *http.Response, err error) { - // create the download request - req, err := http.NewRequest(d.Method, d.Url, nil) - if err != nil { - return - } - - // we have to add headers like this so they get used across redirects - trans := d.HttpClient.Transport - if trans == nil { - trans = http.DefaultTransport - } - - d.HttpClient.Transport = &RoundTripper{ - RoundTripFn: func(r *http.Request) (*http.Response, error) { - // add header for download continuation - if offset > 0 { - r.Header.Add("Range", fmt.Sprintf("%d-", offset)) - } - - // ask for gzipped content so that net/http won't unzip it for us - // and destroy the content length header we need for progress calculations - r.Header.Add("Accept-Encoding", "gzip") - - return trans.RoundTrip(r) - }, - } - - // issue the download request - return d.HttpClient.Do(req) -} - -func (d *Download) Check() (available bool, err error) { - resp, err := d.sharedHttp(0) - if err != nil { - return - } - resp.Body.Close() - - switch resp.StatusCode { - // ok - case 200, 206: - available = true - - // no update available - case 204: - available = false - - // server error - default: - err = fmt.Errorf("Non 2XX response when downloading update: %s", resp.Status) - return - } - - return -} - -// Get() downloads the given url from the internet to a file on disk -// and then calls FromStream() to update the current program's executable file -// with the contents of that file. -// -// If the update is successful, the downloaded file will be erased from disk. -// Otherwise, it will remain in d.Path to allow the download to resume later -// or be skipped entirely. -// -// Only HTTP/1.1 servers that implement the Range header support resuming a -// partially completed download. -// -// UpdateFromUrl() uses HTTP status codes to determine what action to take. -// -// - The HTTP server should return 200 or 206 for the update to be downloaded. -// -// - The HTTP server should return 204 if no update is available at this time. -// -// - If the HTTP server returns a 3XX redirect, it will be followed -// according to d.HttpClient's redirect policy. -// -// - Any other HTTP status code will cause UpdateFromUrl to return an error. -func (d *Download) Get() (err error) { - var offset int64 = 0 - var fp *os.File - - // Close the progress channel whenever this function completes - defer close(d.Progress) - - // open a file where we will stream the downloaded update to - // we do this first because if the caller specified a non-empty dlpath - // we need to determine how large it is in order to resume the download - if d.Path == "" { - // no dlpath specified, use a random tempfile - fp, err = ioutil.TempFile("", "update") - if err != nil { - return - } - defer fp.Close() - - // remember the path - d.Path = fp.Name() - } else { - fp, err = os.OpenFile(d.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0600) - if err != nil { - return - } - defer fp.Close() - - // determine the file size so we can resume the download, if possible - var fi os.FileInfo - fi, err = fp.Stat() - if err != nil { - return - } - - offset = fi.Size() - } - - // start downloading the file - resp, err := d.sharedHttp(offset) - if err != nil { - return - } - defer resp.Body.Close() - - switch resp.StatusCode { - // ok - case 200, 206: - d.Available = true - - // no update available - case 204: - return - - // server error - default: - err = fmt.Errorf("Non 2XX response when downloading update: %s", resp.Status) - return - } - - // Determine how much we have to download - // net/http sets this to -1 when it is unknown - clength := resp.ContentLength - - // Read the content from the response body - rd := resp.Body - - // meter the rate at which we download content for - // progress reporting if we know how much to expect - if clength > 0 { - rd = &MeteredReader{rd: rd, totalSize: clength, progress: d.Progress} - } - - // Decompress the content if necessary - if resp.Header.Get("Content-Encoding") == "gzip" { - rd, err = gzip.NewReader(rd) - if err != nil { - return - } - } - - // Download the update - _, err = io.Copy(fp, rd) - if err != nil { - return - } - - return -} - -func (d *Download) GetAndUpdate() (err error, errRecover error) { - // check before we download if this will work - if err = SanityCheck(); err != nil { - // keep the contract that d.Progress will close whenever Get() terminates - close(d.Progress) - return - } - - // download the update - if err = d.Get(); err != nil || !d.Available { - return - } - - // apply the update - if err, errRecover = FromFile(d.Path); err != nil || errRecover != nil { - return - } - - // remove the temporary file - os.Remove(d.Path) - return -} - -// FromUrl downloads the contents of the given url and uses them to update -// the current program's executable file. It is a convenience function which is equivalent to -// -// NewDownload(url).GetAndUpdate() -// -// See Download.Get() for more details. -func FromUrl(url string) (err error, errRecover error) { - return NewDownload(url).GetAndUpdate() -} - -// FromFile reads the contents of the given file and uses them -// to update the current program's executable file by calling FromStream(). -func FromFile(filepath string) (err error, errRecover error) { - // open the new binary - fp, err := os.Open(filepath) - if err != nil { - return - } - defer fp.Close() - - // do the update - return FromStream(fp) -} - -// FromStream reads the contents of the supplied io.Reader newBinary -// and uses them to update the current program's executable file. -// -// FromStream performs the following actions to ensure a cross-platform safe -// update: -// -// - Creates a new file, /path/to/.program-name.new with mode 0755 and copies -// the contents of newBinary into the file -// -// - Renames the current program's executable file from /path/to/program-name -// to /path/to/.program-name.old -// -// - Renames /path/to/.program-name.new to /path/to/program-name -// -// - If the rename is successful, it erases /path/to/.program.old. If this operation -// fails, no error is reported. -// -// - If the rename is unsuccessful, it attempts to rename /path/to/.program-name.old -// back to /path/to/program-name. If this operation fails, the error is not reported -// in order to not mask the error that caused the rename recovery attempt. -func FromStream(newBinary io.Reader) (err error, errRecover error) { - // get the path to the executable - thisExecPath, err := osext.Executable() - if err != nil { - return - } - - // get the directory the executable exists in - execDir := filepath.Dir(thisExecPath) - execName := filepath.Base(thisExecPath) - - // Copy the contents of of newbinary to a the new executable file - newExecPath := filepath.Join(execDir, fmt.Sprintf(".%s.new", execName)) - fp, err := os.OpenFile(newExecPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) - if err != nil { - return - } - defer fp.Close() - _, err = io.Copy(fp, newBinary) - - // if we don't call fp.Close(), windows won't let us move the new executable - // because the file will still be "in use" - fp.Close() - - // this is where we'll move the executable to so that we can swap in the updated replacement - oldExecPath := filepath.Join(execDir, fmt.Sprintf(".%s.old", execName)) - - // delete any existing old exec file - this is necessary on Windows for two reasons: - // 1. after a successful update, windows can't remove the .old file because the process is still running - // 2. windows rename operations fail if the destination file already exists - _ = os.Remove(oldExecPath) - - // move the existing executable to a new file in the same directory - err = os.Rename(thisExecPath, oldExecPath) - if err != nil { - return - } - - // move the new exectuable in to become the new program - err = os.Rename(newExecPath, thisExecPath) - - if err != nil { - // copy unsuccessful - errRecover = os.Rename(oldExecPath, thisExecPath) - } else { - // copy successful, remove the old binary - _ = os.Remove(oldExecPath) - } - - return -} - -// SanityCheck() attempts to determine whether an in-place executable update could -// succeed by performing preliminary checks (to establish valid permissions, etc). -// This helps avoid downloading updates when we know the update can't be successfully -// applied later. -func SanityCheck() (err error) { - // get the path to the executable - thisExecPath, err := osext.Executable() - if err != nil { - return - } - - // get the directory the executable exists in - execDir := filepath.Dir(thisExecPath) - execName := filepath.Base(thisExecPath) - - // attempt to open a file in the executable's directory - newExecPath := filepath.Join(execDir, fmt.Sprintf(".%s.new", execName)) - fp, err := os.OpenFile(newExecPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) - if err != nil { - return - } - fp.Close() - - _ = os.Remove(newExecPath) - return -} diff --git a/README.md b/README.md index 0d05a71..8cabec6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ go-selfupdate ============= +[![GoDoc](https://godoc.org/github.com/sanbornm/go-selfupdate/selfupdate?status.svg)](https://godoc.org/github.com/sanbornm/go-selfupdate/selfupdate) +[![Build Status](https://travis-ci.org/sanbornm/go-selfupdate.svg?branch=master)](https://travis-ci.org/sanbornm/go-selfupdate) + Enable your Golang applications to self update. Inspired by Chrome based on Heroku's [hk](https://github.com/heroku/hk). ## Features