From f247155ad657df9541ca9202545e2048c8eae30d Mon Sep 17 00:00:00 2001 From: Kyle Williams Date: Tue, 8 Dec 2020 20:38:04 -0700 Subject: [PATCH] Update to go mod and parameterize check time and randomize time --- Gopkg.lock | 28 - Gopkg.toml | 34 -- go.mod | 9 + go.sum | 6 + selfupdate/selfupdate.go | 51 +- selfupdate/selfupdate_test.go | 47 ++ selfupdate/update/cktime | 1 + vendor/github.com/kardianos/osext/LICENSE | 27 - vendor/github.com/kardianos/osext/README.md | 16 - vendor/github.com/kardianos/osext/osext.go | 27 - .../github.com/kardianos/osext/osext_plan9.go | 20 - .../kardianos/osext/osext_procfs.go | 36 -- .../kardianos/osext/osext_sysctl.go | 79 --- .../kardianos/osext/osext_windows.go | 34 -- vendor/github.com/kr/binarydist/.gitignore | 1 - vendor/github.com/kr/binarydist/License | 22 - vendor/github.com/kr/binarydist/Readme.md | 7 - vendor/github.com/kr/binarydist/bzip2.go | 40 -- vendor/github.com/kr/binarydist/diff.go | 408 --------------- vendor/github.com/kr/binarydist/doc.go | 24 - vendor/github.com/kr/binarydist/encoding.go | 53 -- vendor/github.com/kr/binarydist/patch.go | 109 ---- vendor/github.com/kr/binarydist/seek.go | 43 -- .../inconshreveable/go-update.v0/LICENSE | 13 - .../inconshreveable/go-update.v0/README.md | 37 -- .../go-update.v0/download/download.go | 235 --------- .../inconshreveable/go-update.v0/hide_noop.go | 7 - .../go-update.v0/hide_windows.go | 19 - .../inconshreveable/go-update.v0/update.go | 491 ------------------ 29 files changed, 101 insertions(+), 1823 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 selfupdate/update/cktime delete mode 100644 vendor/github.com/kardianos/osext/LICENSE delete mode 100644 vendor/github.com/kardianos/osext/README.md delete mode 100644 vendor/github.com/kardianos/osext/osext.go delete mode 100644 vendor/github.com/kardianos/osext/osext_plan9.go delete mode 100644 vendor/github.com/kardianos/osext/osext_procfs.go delete mode 100644 vendor/github.com/kardianos/osext/osext_sysctl.go delete mode 100644 vendor/github.com/kardianos/osext/osext_windows.go delete mode 100644 vendor/github.com/kr/binarydist/.gitignore delete mode 100644 vendor/github.com/kr/binarydist/License delete mode 100644 vendor/github.com/kr/binarydist/Readme.md delete mode 100644 vendor/github.com/kr/binarydist/bzip2.go delete mode 100644 vendor/github.com/kr/binarydist/diff.go delete mode 100644 vendor/github.com/kr/binarydist/doc.go delete mode 100644 vendor/github.com/kr/binarydist/encoding.go delete mode 100644 vendor/github.com/kr/binarydist/patch.go delete mode 100644 vendor/github.com/kr/binarydist/seek.go delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/LICENSE delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/README.md delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/download/download.go delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/hide_noop.go delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/hide_windows.go delete mode 100644 vendor/gopkg.in/inconshreveable/go-update.v0/update.go diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 99184b3..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,28 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/kardianos/osext" - packages = ["."] - revision = "6e7f843663477789fac7c02def0d0909e969b4e5" - -[[projects]] - name = "github.com/kr/binarydist" - packages = ["."] - revision = "9955b0ab8708602d411341e55fffd7e0700f86bd" - -[[projects]] - branch = "v0" - name = "gopkg.in/inconshreveable/go-update.v0" - packages = [ - ".", - "download" - ] - revision = "d8b0b1d421aa1cbf392c05869f8abbc669bb7066" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "2dc15c6a0e0dda650516ca1c04eb3ce579602cb928acda004089b48b0dce8a9d" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index 245f040..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,34 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - branch = "v0" - name = "gopkg.in/inconshreveable/go-update.v0" - -[prune] - go-tests = true - unused-packages = true diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9604122 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/sanbornm/go-selfupdate + +go 1.15 + +require ( + github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 + github.com/kr/binarydist v0.1.0 + gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b51589b --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo= +github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM= +gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa h1:drvf2JoUL1fz3ttkGNkw+rf3kZa2//7XkYGpSO4NHNA= +gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa/go.mod h1:tuNm0ntQ7IH9VSA39XxzLMpee5c2DwgIbjD4x3ydo8Y= diff --git a/selfupdate/selfupdate.go b/selfupdate/selfupdate.go index 6cd4590..414d3a2 100644 --- a/selfupdate/selfupdate.go +++ b/selfupdate/selfupdate.go @@ -83,6 +83,8 @@ type Updater struct { DiffURL string // Base URL for diff downloads. Dir string // Directory to store selfupdate state. ForceCheck bool // Check for update regardless of cktime timestamp + CheckTime int // Time in hours before next check + RandomizeTime int // Time in hours to randomize with CheckTime Requester Requester //Optional parameter to override existing http request handler Info struct { Version string @@ -102,34 +104,62 @@ func (u *Updater) BackgroundRun() error { // fail return err } - if u.wantUpdate() { + if u.WantUpdate() { if err := up.CanUpdate(); err != nil { // fail return err } + + u.SetUpdateTime() + //self, err := osext.Executable() //if err != nil { // fail update, couldn't figure out path to self //return //} // TODO(bgentry): logger isn't on Windows. Replace w/ proper error reports. - if err := u.update(); err != nil { + if err := u.Update(); err != nil { return err } } return nil } -func (u *Updater) wantUpdate() bool { - path := u.getExecRelativeDir(u.Dir + upcktimePath) - if u.CurrentVersion == "dev" || (!u.ForceCheck && readTime(path).After(time.Now())) { +// WantUpdate returns boolean designating if an update is desired +func (u *Updater) WantUpdate() bool { + if u.CurrentVersion == "dev" || (!u.ForceCheck && u.NextUpdate().After(time.Now())) { return false } - wait := 24*time.Hour + randDuration(24*time.Hour) - return writeTime(path, time.Now().Add(wait)) + + return true } -func (u *Updater) update() error { +// NextUpdate returns the next time update should be checked +func (u *Updater) NextUpdate() time.Time { + path := u.getExecRelativeDir(u.Dir + upcktimePath) + nextTime := readTime(path) + + return nextTime +} + +// SetUpdateTime writes the next update time to the state file +func (u *Updater) SetUpdateTime() bool { + path := u.getExecRelativeDir(u.Dir + upcktimePath) + wait := time.Duration(u.CheckTime) * time.Hour + // Add 1 to random time since max is not included + waitrand := time.Duration(rand.Intn(u.RandomizeTime+1)) * time.Hour + + return writeTime(path, time.Now().Add(wait+waitrand)) +} + +// ClearUpdateState writes current time to state file +func (u *Updater) ClearUpdateState() { + path := u.getExecRelativeDir(u.Dir + upcktimePath) + os.Remove(path) +} + +// Update initiates the self update process +func (u *Updater) Update() error { path, err := osext.Executable() if err != nil { return err @@ -250,11 +280,6 @@ func (u *Updater) fetchBin() ([]byte, error) { return buf.Bytes(), nil } -// returns a random duration in [0,n). -func randDuration(n time.Duration) time.Duration { - return time.Duration(rand.Int63n(int64(n))) -} - func (u *Updater) fetch(url string) (io.ReadCloser, error) { if u.Requester == nil { return defaultHTTPRequester.Fetch(url) diff --git a/selfupdate/selfupdate_test.go b/selfupdate/selfupdate_test.go index 6def191..e71cb81 100644 --- a/selfupdate/selfupdate_test.go +++ b/selfupdate/selfupdate_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "testing" + "time" ) var testHash = sha256.New() @@ -17,7 +18,11 @@ func TestUpdaterFetchMustReturnNonNilReaderCloser(t *testing.T) { return nil, nil }) updater := createUpdater(mr) + updater.CheckTime = 24 + updater.RandomizeTime = 24 + err := updater.BackgroundRun() + if err != nil { equals(t, "Fetch was expected to return non-nil ReadCloser", err.Error()) } else { @@ -34,6 +39,8 @@ func TestUpdaterWithEmptyPayloadNoErrorNoUpdate(t *testing.T) { return newTestReaderCloser("{}"), nil }) updater := createUpdater(mr) + updater.CheckTime = 24 + updater.RandomizeTime = 24 err := updater.BackgroundRun() if err != nil { @@ -41,6 +48,46 @@ func TestUpdaterWithEmptyPayloadNoErrorNoUpdate(t *testing.T) { } } +func TestUpdaterCheckTime(t *testing.T) { + mr := &mockRequester{} + mr.handleRequest( + func(url string) (io.ReadCloser, error) { + equals(t, "http://updates.yourdomain.com/myapp/darwin-amd64.json", url) + return newTestReaderCloser("{}"), nil + }) + + // Run test with various time + runTestTimeChecks(t, mr, 0, 0, false) + runTestTimeChecks(t, mr, 0, 5, true) + runTestTimeChecks(t, mr, 1, 0, true) + runTestTimeChecks(t, mr, 100, 100, true) +} + +// Helper function to run check time tests +func runTestTimeChecks(t *testing.T, mr *mockRequester, checkTime int, randomizeTime int, expectUpdate bool) { + updater := createUpdater(mr) + updater.ClearUpdateState() + updater.CheckTime = checkTime + updater.RandomizeTime = randomizeTime + + updater.BackgroundRun() + + if updater.WantUpdate() == expectUpdate { + t.Errorf("WantUpdate returned %v; want %v", updater.WantUpdate(), expectUpdate) + } + + maxHrs := time.Duration(updater.CheckTime+updater.RandomizeTime) * time.Hour + maxTime := time.Now().Add(maxHrs) + + if !updater.NextUpdate().Before(maxTime) { + t.Errorf("NextUpdate should less than %s hrs (CheckTime + RandomizeTime) from now; now %s; next update %s", maxHrs, time.Now(), updater.NextUpdate()) + } + + if maxHrs > 0 && !updater.NextUpdate().After(time.Now()) { + t.Errorf("NextUpdate should be after now") + } +} + func TestUpdaterWithEmptyPayloadNoErrorNoUpdateEscapedPath(t *testing.T) { mr := &mockRequester{} mr.handleRequest( diff --git a/selfupdate/update/cktime b/selfupdate/update/cktime new file mode 100644 index 0000000..d88cca7 --- /dev/null +++ b/selfupdate/update/cktime @@ -0,0 +1 @@ +2020-12-08T21:11:49-07:00 \ No newline at end of file diff --git a/vendor/github.com/kardianos/osext/LICENSE b/vendor/github.com/kardianos/osext/LICENSE deleted file mode 100644 index 7448756..0000000 --- a/vendor/github.com/kardianos/osext/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/kardianos/osext/README.md b/vendor/github.com/kardianos/osext/README.md deleted file mode 100644 index 61350ba..0000000 --- a/vendor/github.com/kardianos/osext/README.md +++ /dev/null @@ -1,16 +0,0 @@ -### Extensions to the "os" package. - -## Find the current Executable and ExecutableFolder. - -There is sometimes utility in finding the current executable file -that is running. This can be used for upgrading the current executable -or finding resources located relative to the executable file. Both -working directory and the os.Args[0] value are arbitrary and cannot -be relied on; os.Args[0] can be "faked". - -Multi-platform and supports: - * Linux - * OS X - * Windows - * Plan 9 - * BSDs. diff --git a/vendor/github.com/kardianos/osext/osext.go b/vendor/github.com/kardianos/osext/osext.go deleted file mode 100644 index 0eca579..0000000 --- a/vendor/github.com/kardianos/osext/osext.go +++ /dev/null @@ -1,27 +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 "github.com/kardianos/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 and any trailing slash. -func ExecutableFolder() (string, error) { - p, err := Executable() - if err != nil { - return "", err - } - - return filepath.Dir(p), nil -} diff --git a/vendor/github.com/kardianos/osext/osext_plan9.go b/vendor/github.com/kardianos/osext/osext_plan9.go deleted file mode 100644 index 655750c..0000000 --- a/vendor/github.com/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 ( - "os" - "strconv" - "syscall" -) - -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/vendor/github.com/kardianos/osext/osext_procfs.go b/vendor/github.com/kardianos/osext/osext_procfs.go deleted file mode 100644 index b2598bc..0000000 --- a/vendor/github.com/kardianos/osext/osext_procfs.go +++ /dev/null @@ -1,36 +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 solaris dragonfly - -package osext - -import ( - "errors" - "fmt" - "os" - "runtime" - "strings" -) - -func executable() (string, error) { - switch runtime.GOOS { - case "linux": - const deletedTag = " (deleted)" - execpath, err := os.Readlink("/proc/self/exe") - if err != nil { - return execpath, err - } - execpath = strings.TrimSuffix(execpath, deletedTag) - execpath = strings.TrimPrefix(execpath, deletedTag) - return execpath, nil - case "netbsd": - return os.Readlink("/proc/curproc/exe") - case "openbsd", "dragonfly": - return os.Readlink("/proc/curproc/file") - case "solaris": - return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) - } - return "", errors.New("ExecPath not implemented for " + runtime.GOOS) -} diff --git a/vendor/github.com/kardianos/osext/osext_sysctl.go b/vendor/github.com/kardianos/osext/osext_sysctl.go deleted file mode 100644 index b66cac8..0000000 --- a/vendor/github.com/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/vendor/github.com/kardianos/osext/osext_windows.go b/vendor/github.com/kardianos/osext/osext_windows.go deleted file mode 100644 index 72d282c..0000000 --- a/vendor/github.com/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/vendor/github.com/kr/binarydist/.gitignore b/vendor/github.com/kr/binarydist/.gitignore deleted file mode 100644 index 653f160..0000000 --- a/vendor/github.com/kr/binarydist/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test.* diff --git a/vendor/github.com/kr/binarydist/License b/vendor/github.com/kr/binarydist/License deleted file mode 100644 index 183c389..0000000 --- a/vendor/github.com/kr/binarydist/License +++ /dev/null @@ -1,22 +0,0 @@ -Copyright 2012 Keith Rarick - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/kr/binarydist/Readme.md b/vendor/github.com/kr/binarydist/Readme.md deleted file mode 100644 index dadc368..0000000 --- a/vendor/github.com/kr/binarydist/Readme.md +++ /dev/null @@ -1,7 +0,0 @@ -# binarydist - -Package binarydist implements binary diff and patch as described on -. It reads and writes files -compatible with the tools there. - -Documentation at . diff --git a/vendor/github.com/kr/binarydist/bzip2.go b/vendor/github.com/kr/binarydist/bzip2.go deleted file mode 100644 index a2516b8..0000000 --- a/vendor/github.com/kr/binarydist/bzip2.go +++ /dev/null @@ -1,40 +0,0 @@ -package binarydist - -import ( - "io" - "os/exec" -) - -type bzip2Writer struct { - c *exec.Cmd - w io.WriteCloser -} - -func (w bzip2Writer) Write(b []byte) (int, error) { - return w.w.Write(b) -} - -func (w bzip2Writer) Close() error { - if err := w.w.Close(); err != nil { - return err - } - return w.c.Wait() -} - -// Package compress/bzip2 implements only decompression, -// so we'll fake it by running bzip2 in another process. -func newBzip2Writer(w io.Writer) (wc io.WriteCloser, err error) { - var bw bzip2Writer - bw.c = exec.Command("bzip2", "-c") - bw.c.Stdout = w - - if bw.w, err = bw.c.StdinPipe(); err != nil { - return nil, err - } - - if err = bw.c.Start(); err != nil { - return nil, err - } - - return bw, nil -} diff --git a/vendor/github.com/kr/binarydist/diff.go b/vendor/github.com/kr/binarydist/diff.go deleted file mode 100644 index 1d2d951..0000000 --- a/vendor/github.com/kr/binarydist/diff.go +++ /dev/null @@ -1,408 +0,0 @@ -package binarydist - -import ( - "bytes" - "encoding/binary" - "io" - "io/ioutil" -) - -func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] } - -func split(I, V []int, start, length, h int) { - var i, j, k, x, jj, kk int - - if length < 16 { - for k = start; k < start+length; k += j { - j = 1 - x = V[I[k]+h] - for i = 1; k+i < start+length; i++ { - if V[I[k+i]+h] < x { - x = V[I[k+i]+h] - j = 0 - } - if V[I[k+i]+h] == x { - swap(I, k+i, k+j) - j++ - } - } - for i = 0; i < j; i++ { - V[I[k+i]] = k + j - 1 - } - if j == 1 { - I[k] = -1 - } - } - return - } - - x = V[I[start+length/2]+h] - jj = 0 - kk = 0 - for i = start; i < start+length; i++ { - if V[I[i]+h] < x { - jj++ - } - if V[I[i]+h] == x { - kk++ - } - } - jj += start - kk += jj - - i = start - j = 0 - k = 0 - for i < jj { - if V[I[i]+h] < x { - i++ - } else if V[I[i]+h] == x { - swap(I, i, jj+j) - j++ - } else { - swap(I, i, kk+k) - k++ - } - } - - for jj+j < kk { - if V[I[jj+j]+h] == x { - j++ - } else { - swap(I, jj+j, kk+k) - k++ - } - } - - if jj > start { - split(I, V, start, jj-start, h) - } - - for i = 0; i < kk-jj; i++ { - V[I[jj+i]] = kk - 1 - } - if jj == kk-1 { - I[jj] = -1 - } - - if start+length > kk { - split(I, V, kk, start+length-kk, h) - } -} - -func qsufsort(obuf []byte) []int { - var buckets [256]int - var i, h int - I := make([]int, len(obuf)+1) - V := make([]int, len(obuf)+1) - - for _, c := range obuf { - buckets[c]++ - } - for i = 1; i < 256; i++ { - buckets[i] += buckets[i-1] - } - copy(buckets[1:], buckets[:]) - buckets[0] = 0 - - for i, c := range obuf { - buckets[c]++ - I[buckets[c]] = i - } - - I[0] = len(obuf) - for i, c := range obuf { - V[i] = buckets[c] - } - - V[len(obuf)] = 0 - for i = 1; i < 256; i++ { - if buckets[i] == buckets[i-1]+1 { - I[buckets[i]] = -1 - } - } - I[0] = -1 - - for h = 1; I[0] != -(len(obuf) + 1); h += h { - var n int - for i = 0; i < len(obuf)+1; { - if I[i] < 0 { - n -= I[i] - i -= I[i] - } else { - if n != 0 { - I[i-n] = -n - } - n = V[I[i]] + 1 - i - split(I, V, i, n, h) - i += n - n = 0 - } - } - if n != 0 { - I[i-n] = -n - } - } - - for i = 0; i < len(obuf)+1; i++ { - I[V[i]] = i - } - return I -} - -func matchlen(a, b []byte) (i int) { - for i < len(a) && i < len(b) && a[i] == b[i] { - i++ - } - return i -} - -func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) { - if en-st < 2 { - x := matchlen(obuf[I[st]:], nbuf) - y := matchlen(obuf[I[en]:], nbuf) - - if x > y { - return I[st], x - } else { - return I[en], y - } - } - - x := st + (en-st)/2 - if bytes.Compare(obuf[I[x]:], nbuf) < 0 { - return search(I, obuf, nbuf, x, en) - } else { - return search(I, obuf, nbuf, st, x) - } - panic("unreached") -} - -// Diff computes the difference between old and new, according to the bsdiff -// algorithm, and writes the result to patch. -func Diff(old, new io.Reader, patch io.Writer) error { - obuf, err := ioutil.ReadAll(old) - if err != nil { - return err - } - - nbuf, err := ioutil.ReadAll(new) - if err != nil { - return err - } - - pbuf, err := diffBytes(obuf, nbuf) - if err != nil { - return err - } - - _, err = patch.Write(pbuf) - return err -} - -func diffBytes(obuf, nbuf []byte) ([]byte, error) { - var patch seekBuffer - err := diff(obuf, nbuf, &patch) - if err != nil { - return nil, err - } - return patch.buf, nil -} - -func diff(obuf, nbuf []byte, patch io.WriteSeeker) error { - var lenf int - I := qsufsort(obuf) - db := make([]byte, len(nbuf)) - eb := make([]byte, len(nbuf)) - var dblen, eblen int - - var hdr header - hdr.Magic = magic - hdr.NewSize = int64(len(nbuf)) - err := binary.Write(patch, signMagLittleEndian{}, &hdr) - if err != nil { - return err - } - - // Compute the differences, writing ctrl as we go - pfbz2, err := newBzip2Writer(patch) - if err != nil { - return err - } - var scan, pos, length int - var lastscan, lastpos, lastoffset int - for scan < len(nbuf) { - var oldscore int - scan += length - for scsc := scan; scan < len(nbuf); scan++ { - pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf)) - - for ; scsc < scan+length; scsc++ { - if scsc+lastoffset < len(obuf) && - obuf[scsc+lastoffset] == nbuf[scsc] { - oldscore++ - } - } - - if (length == oldscore && length != 0) || length > oldscore+8 { - break - } - - if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] { - oldscore-- - } - } - - if length != oldscore || scan == len(nbuf) { - var s, Sf int - lenf = 0 - for i := 0; lastscan+i < scan && lastpos+i < len(obuf); { - if obuf[lastpos+i] == nbuf[lastscan+i] { - s++ - } - i++ - if s*2-i > Sf*2-lenf { - Sf = s - lenf = i - } - } - - lenb := 0 - if scan < len(nbuf) { - var s, Sb int - for i := 1; (scan >= lastscan+i) && (pos >= i); i++ { - if obuf[pos-i] == nbuf[scan-i] { - s++ - } - if s*2-i > Sb*2-lenb { - Sb = s - lenb = i - } - } - } - - if lastscan+lenf > scan-lenb { - overlap := (lastscan + lenf) - (scan - lenb) - s := 0 - Ss := 0 - lens := 0 - for i := 0; i < overlap; i++ { - if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] { - s++ - } - if nbuf[scan-lenb+i] == obuf[pos-lenb+i] { - s-- - } - if s > Ss { - Ss = s - lens = i + 1 - } - } - - lenf += lens - overlap - lenb -= lens - } - - for i := 0; i < lenf; i++ { - db[dblen+i] = nbuf[lastscan+i] - obuf[lastpos+i] - } - for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ { - eb[eblen+i] = nbuf[lastscan+lenf+i] - } - - dblen += lenf - eblen += (scan - lenb) - (lastscan + lenf) - - err = binary.Write(pfbz2, signMagLittleEndian{}, int64(lenf)) - if err != nil { - pfbz2.Close() - return err - } - - val := (scan - lenb) - (lastscan + lenf) - err = binary.Write(pfbz2, signMagLittleEndian{}, int64(val)) - if err != nil { - pfbz2.Close() - return err - } - - val = (pos - lenb) - (lastpos + lenf) - err = binary.Write(pfbz2, signMagLittleEndian{}, int64(val)) - if err != nil { - pfbz2.Close() - return err - } - - lastscan = scan - lenb - lastpos = pos - lenb - lastoffset = pos - scan - } - } - err = pfbz2.Close() - if err != nil { - return err - } - - // Compute size of compressed ctrl data - l64, err := patch.Seek(0, 1) - if err != nil { - return err - } - hdr.CtrlLen = int64(l64 - 32) - - // Write compressed diff data - pfbz2, err = newBzip2Writer(patch) - if err != nil { - return err - } - n, err := pfbz2.Write(db[:dblen]) - if err != nil { - pfbz2.Close() - return err - } - if n != dblen { - pfbz2.Close() - return io.ErrShortWrite - } - err = pfbz2.Close() - if err != nil { - return err - } - - // Compute size of compressed diff data - n64, err := patch.Seek(0, 1) - if err != nil { - return err - } - hdr.DiffLen = n64 - l64 - - // Write compressed extra data - pfbz2, err = newBzip2Writer(patch) - if err != nil { - return err - } - n, err = pfbz2.Write(eb[:eblen]) - if err != nil { - pfbz2.Close() - return err - } - if n != eblen { - pfbz2.Close() - return io.ErrShortWrite - } - err = pfbz2.Close() - if err != nil { - return err - } - - // Seek to the beginning, write the header, and close the file - _, err = patch.Seek(0, 0) - if err != nil { - return err - } - err = binary.Write(patch, signMagLittleEndian{}, &hdr) - if err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/kr/binarydist/doc.go b/vendor/github.com/kr/binarydist/doc.go deleted file mode 100644 index 3c92d87..0000000 --- a/vendor/github.com/kr/binarydist/doc.go +++ /dev/null @@ -1,24 +0,0 @@ -// Package binarydist implements binary diff and patch as described on -// http://www.daemonology.net/bsdiff/. It reads and writes files -// compatible with the tools there. -package binarydist - -var magic = [8]byte{'B', 'S', 'D', 'I', 'F', 'F', '4', '0'} - -// File format: -// 0 8 "BSDIFF40" -// 8 8 X -// 16 8 Y -// 24 8 sizeof(newfile) -// 32 X bzip2(control block) -// 32+X Y bzip2(diff block) -// 32+X+Y ??? bzip2(extra block) -// with control block a set of triples (x,y,z) meaning "add x bytes -// from oldfile to x bytes from the diff block; copy y bytes from the -// extra block; seek forwards in oldfile by z bytes". -type header struct { - Magic [8]byte - CtrlLen int64 - DiffLen int64 - NewSize int64 -} diff --git a/vendor/github.com/kr/binarydist/encoding.go b/vendor/github.com/kr/binarydist/encoding.go deleted file mode 100644 index 75ba585..0000000 --- a/vendor/github.com/kr/binarydist/encoding.go +++ /dev/null @@ -1,53 +0,0 @@ -package binarydist - -// SignMagLittleEndian is the numeric encoding used by the bsdiff tools. -// It implements binary.ByteOrder using a sign-magnitude format -// and little-endian byte order. Only methods Uint64 and String -// have been written; the rest panic. -type signMagLittleEndian struct{} - -func (signMagLittleEndian) Uint16(b []byte) uint16 { panic("unimplemented") } - -func (signMagLittleEndian) PutUint16(b []byte, v uint16) { panic("unimplemented") } - -func (signMagLittleEndian) Uint32(b []byte) uint32 { panic("unimplemented") } - -func (signMagLittleEndian) PutUint32(b []byte, v uint32) { panic("unimplemented") } - -func (signMagLittleEndian) Uint64(b []byte) uint64 { - y := int64(b[0]) | - int64(b[1])<<8 | - int64(b[2])<<16 | - int64(b[3])<<24 | - int64(b[4])<<32 | - int64(b[5])<<40 | - int64(b[6])<<48 | - int64(b[7]&0x7f)<<56 - - if b[7]&0x80 != 0 { - y = -y - } - return uint64(y) -} - -func (signMagLittleEndian) PutUint64(b []byte, v uint64) { - x := int64(v) - neg := x < 0 - if neg { - x = -x - } - - b[0] = byte(x) - b[1] = byte(x >> 8) - b[2] = byte(x >> 16) - b[3] = byte(x >> 24) - b[4] = byte(x >> 32) - b[5] = byte(x >> 40) - b[6] = byte(x >> 48) - b[7] = byte(x >> 56) - if neg { - b[7] |= 0x80 - } -} - -func (signMagLittleEndian) String() string { return "signMagLittleEndian" } diff --git a/vendor/github.com/kr/binarydist/patch.go b/vendor/github.com/kr/binarydist/patch.go deleted file mode 100644 index eb03225..0000000 --- a/vendor/github.com/kr/binarydist/patch.go +++ /dev/null @@ -1,109 +0,0 @@ -package binarydist - -import ( - "bytes" - "compress/bzip2" - "encoding/binary" - "errors" - "io" - "io/ioutil" -) - -var ErrCorrupt = errors.New("corrupt patch") - -// Patch applies patch to old, according to the bspatch algorithm, -// and writes the result to new. -func Patch(old io.Reader, new io.Writer, patch io.Reader) error { - var hdr header - err := binary.Read(patch, signMagLittleEndian{}, &hdr) - if err != nil { - return err - } - if hdr.Magic != magic { - return ErrCorrupt - } - if hdr.CtrlLen < 0 || hdr.DiffLen < 0 || hdr.NewSize < 0 { - return ErrCorrupt - } - - ctrlbuf := make([]byte, hdr.CtrlLen) - _, err = io.ReadFull(patch, ctrlbuf) - if err != nil { - return err - } - cpfbz2 := bzip2.NewReader(bytes.NewReader(ctrlbuf)) - - diffbuf := make([]byte, hdr.DiffLen) - _, err = io.ReadFull(patch, diffbuf) - if err != nil { - return err - } - dpfbz2 := bzip2.NewReader(bytes.NewReader(diffbuf)) - - // The entire rest of the file is the extra block. - epfbz2 := bzip2.NewReader(patch) - - obuf, err := ioutil.ReadAll(old) - if err != nil { - return err - } - - nbuf := make([]byte, hdr.NewSize) - - var oldpos, newpos int64 - for newpos < hdr.NewSize { - var ctrl struct{ Add, Copy, Seek int64 } - err = binary.Read(cpfbz2, signMagLittleEndian{}, &ctrl) - if err != nil { - return err - } - - // Sanity-check - if newpos+ctrl.Add > hdr.NewSize { - return ErrCorrupt - } - - // Read diff string - _, err = io.ReadFull(dpfbz2, nbuf[newpos:newpos+ctrl.Add]) - if err != nil { - return ErrCorrupt - } - - // Add old data to diff string - for i := int64(0); i < ctrl.Add; i++ { - if oldpos+i >= 0 && oldpos+i < int64(len(obuf)) { - nbuf[newpos+i] += obuf[oldpos+i] - } - } - - // Adjust pointers - newpos += ctrl.Add - oldpos += ctrl.Add - - // Sanity-check - if newpos+ctrl.Copy > hdr.NewSize { - return ErrCorrupt - } - - // Read extra string - _, err = io.ReadFull(epfbz2, nbuf[newpos:newpos+ctrl.Copy]) - if err != nil { - return ErrCorrupt - } - - // Adjust pointers - newpos += ctrl.Copy - oldpos += ctrl.Seek - } - - // Write the new file - for len(nbuf) > 0 { - n, err := new.Write(nbuf) - if err != nil { - return err - } - nbuf = nbuf[n:] - } - - return nil -} diff --git a/vendor/github.com/kr/binarydist/seek.go b/vendor/github.com/kr/binarydist/seek.go deleted file mode 100644 index 96c0346..0000000 --- a/vendor/github.com/kr/binarydist/seek.go +++ /dev/null @@ -1,43 +0,0 @@ -package binarydist - -import ( - "errors" -) - -type seekBuffer struct { - buf []byte - pos int -} - -func (b *seekBuffer) Write(p []byte) (n int, err error) { - n = copy(b.buf[b.pos:], p) - if n == len(p) { - b.pos += n - return n, nil - } - b.buf = append(b.buf, p[n:]...) - b.pos += len(p) - return len(p), nil -} - -func (b *seekBuffer) Seek(offset int64, whence int) (ret int64, err error) { - var abs int64 - switch whence { - case 0: - abs = offset - case 1: - abs = int64(b.pos) + offset - case 2: - abs = int64(len(b.buf)) + offset - default: - return 0, errors.New("binarydist: invalid whence") - } - if abs < 0 { - return 0, errors.New("binarydist: negative position") - } - if abs >= 1<<31 { - return 0, errors.New("binarydist: position out of range") - } - b.pos = int(abs) - return abs, nil -} diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/LICENSE b/vendor/gopkg.in/inconshreveable/go-update.v0/LICENSE deleted file mode 100644 index 5f0d1fb..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2014 Alan Shreve - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/README.md b/vendor/gopkg.in/inconshreveable/go-update.v0/README.md deleted file mode 100644 index f070062..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# go-update: Automatically update Go programs from the internet - -go-update allows a program to update itself by replacing its executable file -with a new version. It provides the flexibility to implement different updating user experiences -like auto-updating, or manual user-initiated updates. It also boasts -advanced features like binary patching and code signing verification. - -Updating your program to a new version is as easy as: - - err, errRecover := update.New().FromUrl("http://release.example.com/2.0/myprogram") - if err != nil { - fmt.Printf("Update failed: %v\n", err) - } - -## Documentation and API Reference - -Comprehensive API documentation and code examples are available in the code documentation available on godoc.org: - -[![GoDoc](https://godoc.org/github.com/inconshreveable/go-update?status.svg)](https://godoc.org/github.com/inconshreveable/go-update) - -## Features - -- Cross platform support (Windows too!) -- Binary patch application -- Checksum verification -- Code signing verification -- Support for updating arbitrary files - -## [equinox.io](https://equinox.io) -go-update provides the primitives for building self-updating applications, but there a number of other challenges -involved in a complete updating solution such as hosting, code signing, update channels, gradual rollout, -dynamically computing binary patches, tracking update metrics like versions and failures, plus more. - -I provide this service, a complete solution, free for open source projects, at [equinox.io](https://equinox.io). - -## License -Apache diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/download/download.go b/vendor/gopkg.in/inconshreveable/go-update.v0/download/download.go deleted file mode 100644 index 4552c93..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/download/download.go +++ /dev/null @@ -1,235 +0,0 @@ -package download - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "net/http" - "os" - "runtime" -) - -type roundTripper struct { - RoundTripFn func(*http.Request) (*http.Response, error) -} - -func (rt *roundTripper) RoundTrip(r *http.Request) (*http.Response, error) { - return rt.RoundTripFn(r) -} - -// Download encapsulates the state and parameters to download content -// from a URL which: -// -// - Publishes the percentage of the download completed to a channel. -// - May resume a previous download that was partially completed. -// -// Create an instance with the New() factory function. -type Download struct { - // net/http.Client to use when downloading the update. - // If nil, a default http.Client is used - HttpClient *http.Client - - // As bytes are downloaded, they are written to Target. - // Download also uses the Target's Seek method to determine - // the size of partial-downloads so that it may properly - // request the remaining bytes to resume the download. - Target Target - - // 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 -} - -// New initializes a new Download object which will download -// the content from url into target. -func New(url string, target Target, httpClient *http.Client) *Download { - return &Download{ - HttpClient: httpClient, - Progress: make(chan int), - Method: "GET", - Url: url, - Target: target, - } -} - -// Get() downloads the content of a url to a target destination. -// -// Only HTTP/1.1 servers that implement the Range header support resuming a -// partially completed download. -// -// On success, the server must return 200 and the content, or 206 when resuming a partial download. -// If the HTTP server returns a 3XX redirect, it will be followed according to d.HttpClient's redirect policy. -// -func (d *Download) Get() (err error) { - // Close the progress channel whenever this function completes - defer close(d.Progress) - - // determine the size of the download target to determine if we're resuming a partial download - offset, err := d.Target.Size() - if err != nil { - return - } - - // create the download request - req, err := http.NewRequest(d.Method, d.Url, nil) - if err != nil { - return - } - - // create an http client if one does not exist - if d.HttpClient == nil { - d.HttpClient = http.DefaultClient - } - - // 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 - resp, err := d.HttpClient.Do(req) - if err != nil { - return - } - defer resp.Body.Close() - - switch resp.StatusCode { - // ok - case 200, 206: - - // 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(d.Target, rd) - if err != nil { - return - } - - return -} - -// meteredReader wraps a ReadCloser. Calls to a meteredReader's Read() method -// publish updates to a progress channel with the percentage read so far. -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 -} - -// A Target is what you can supply to Download, -// it's just an io.Writer with a Size() method so that -// the a Download can "resume" an interrupted download -type Target interface { - io.Writer - Size() (int, error) -} - -type FileTarget struct { - *os.File -} - -func (t *FileTarget) Size() (int, error) { - if fi, err := t.File.Stat(); err != nil { - return 0, err - } else { - return int(fi.Size()), nil - } -} - -type MemoryTarget struct { - bytes.Buffer -} - -func (t *MemoryTarget) Size() (int, error) { - return t.Buffer.Len(), nil -} diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/hide_noop.go b/vendor/gopkg.in/inconshreveable/go-update.v0/hide_noop.go deleted file mode 100644 index 3707756..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/hide_noop.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !windows - -package update - -func hideFile(path string) error { - return nil -} diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/hide_windows.go b/vendor/gopkg.in/inconshreveable/go-update.v0/hide_windows.go deleted file mode 100644 index c368b9c..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/hide_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -package update - -import ( - "syscall" - "unsafe" -) - -func hideFile(path string) error { - kernel32 := syscall.NewLazyDLL("kernel32.dll") - setFileAttributes := kernel32.NewProc("SetFileAttributesW") - - r1, _, err := setFileAttributes.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), 2) - - if r1 == 0 { - return err - } else { - return nil - } -} diff --git a/vendor/gopkg.in/inconshreveable/go-update.v0/update.go b/vendor/gopkg.in/inconshreveable/go-update.v0/update.go deleted file mode 100644 index dcfc314..0000000 --- a/vendor/gopkg.in/inconshreveable/go-update.v0/update.go +++ /dev/null @@ -1,491 +0,0 @@ -/* -go-update allows a program to update itself by replacing its executable file -with a new version. It provides the flexibility to implement different updating user experiences -like auto-updating, or manual user-initiated updates. It also boasts -advanced features like binary patching and code signing verification. - -Updating your program to a new version is as easy as: - - err, errRecover := update.New().FromUrl("http://release.example.com/2.0/myprogram") - if err != nil { - fmt.Printf("Update failed: %v\n", err) - } - -You may also choose to update from other data sources such as a file or an io.Reader: - - err, errRecover := update.New().FromFile("/path/to/update") - -Binary Diff Patching - -Binary diff updates are supported and easy to use: - - up := update.New().ApplyPatch(update.PATCHTYPE_BSDIFF) - err, errRecover := up.FromUrl("http://release.example.com/2.0/mypatch") - -Checksum Verification - -You should also verify the checksum of new updates as well as verify -the digital signature of an update. Note that even when you choose to apply -a patch, the checksum is verified against the complete update after that patch -has been applied. - - up := update.New().ApplyPatch(update.PATCHTYPE_BSDIFF).VerifyChecksum(checksum) - err, errRecover := up.FromUrl("http://release.example.com/2.0/mypatch") - -Updating other files - -Updating arbitrary files is also supported. You may update files which are -not the currently running program: - - up := update.New().Target("/usr/local/bin/some-program") - err, errRecover := up.FromUrl("http://release.example.com/2.0/some-program") - -Code Signing - -Truly secure updates use code signing to verify that the update was issued by a trusted party. -To do this, you'll need to generate a public/private key pair. You can do this with openssl, -or the equinox.io client (https://equinox.io/client) can easily generate one for you: - - # with equinox client - equinox genkey --private-key=private.pem --public-key=public.pem - - # with openssl - openssl genrsa -out private.pem 2048 - openssl rsa -in private.pem -out public.pem -pubout - -Once you have your key pair, you can instruct your program to validate its updates -with the public key: - - const publicKey = `-----BEGIN PUBLIC KEY----- - ... - -----END PUBLIC KEY-----` - - up, err := update.New().VerifySignatureWithPEM(publicKey) - if err != nil { - return fmt.Errorf("Bad public key: '%v': %v", publicKey, err) - } - -Once you've configured your program this way, it will disallow all updates unless they -are properly signed. You must now pass in the signature to verify with: - - up.VerifySignature(signature).FromUrl("http://dl.example.com/update") - -Error Handling and Recovery - -To perform an update, the process must be able to read its executable file and to write -to the directory that contains its executable file. It can be useful to check whether the process -has the necessary permissions to perform an update before trying to apply one. Use the -CanUpdate call to provide a useful message to the user if the update can't proceed without -elevated permissions: - - up := update.New().Target("/etc/hosts") - err := up.CanUpdate() - if err != nil { - fmt.Printf("Can't update because: '%v'. Try as root or Administrator\n", err) - return - } - err, errRecover := up.FromUrl("https://example.com/new/hosts") - -Although exceedingly unlikely, the update operation itself is not atomic and can fail -in such a way that a user's computer is left in an inconsistent state. If that happens, -go-update attempts to recover to leave the system in a good state. If the recovery step -fails (even more unlikely), a second error, referred to as "errRecover" will be non-nil -so that you may inform your users of the bad news. You should handle this case as shown -here: - - err, errRecover := up.FromUrl("https://example.com/update") - if err != nil { - fmt.Printf("Update failed: %v\n", err) - if errRecover != nil { - fmt.Printf("Failed to recover bad update: %v!\n", errRecover) - fmt.Printf("Program exectuable may be missing!\n") - } - } - -Subpackages - -Sub-package check contains the client functionality for a simple protocol for negotiating -whether a new update is available, where it is, and the metadata needed for verifying it. - -Sub-package download contains functionality for downloading from an HTTP endpoint -while outputting a progress meter and supports resuming partial downloads. -*/ -package update - -import ( - "bytes" - "crypto" - "crypto/rsa" - "crypto/sha256" - _ "crypto/sha512" // for tls cipher support - "crypto/x509" - "encoding/pem" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - - "github.com/kardianos/osext" - "github.com/kr/binarydist" - "gopkg.in/inconshreveable/go-update.v0/download" -) - -// The type of a binary patch, if any. Only bsdiff is supported -type PatchType string - -const ( - PATCHTYPE_BSDIFF PatchType = "bsdiff" - PATCHTYPE_NONE = "" -) - -type Update struct { - // empty string means "path of the current executable" - TargetPath string - - // type of patch to apply. PATCHTYPE_NONE means "not a patch" - PatchType - - // sha256 checksum of the new binary to verify against - Checksum []byte - - // public key to use for signature verification - PublicKey *rsa.PublicKey - - // signature to use for signature verification - Signature []byte - - // configurable http client can be passed to download - HTTPClient *http.Client -} - -func (u *Update) getPath() (string, error) { - if u.TargetPath == "" { - return osext.Executable() - } else { - return u.TargetPath, nil - } -} - -// New creates a new Update object. -// A default update object assumes the complete binary -// content will be used for update (not a patch) and that -// the intended target is the running executable. -// -// Use this as the start of a chain of calls on the Update -// object to build up your configuration. Example: -// -// up := update.New().ApplyPatch(update.PATCHTYPE_BSDIFF).VerifyChecksum(checksum) -// -func New() *Update { - return &Update{ - TargetPath: "", - PatchType: PATCHTYPE_NONE, - } -} - -// Target configures the update to update the file at the given path. -// The emptry string means 'the executable file of the running program'. -func (u *Update) Target(path string) *Update { - u.TargetPath = path - return u -} - -// ApplyPatch configures the update to treat the contents of the update -// as a patch to apply to the existing to target. You must specify the -// format of the patch. Only PATCHTYPE_BSDIFF is supported at the moment. -func (u *Update) ApplyPatch(patchType PatchType) *Update { - u.PatchType = patchType - return u -} - -// VerifyChecksum configures the update to verify that the -// the update has the given sha256 checksum. -func (u *Update) VerifyChecksum(checksum []byte) *Update { - u.Checksum = checksum - return u -} - -// VerifySignature configures the update to verify the given -// signature of the update. You must also call one of the -// VerifySignatureWith* functions to specify a public key -// to use for verification. -func (u *Update) VerifySignature(signature []byte) *Update { - u.Signature = signature - return u -} - -// VerifySignatureWith configures the update to use the given RSA -// public key to verify the update's signature. You must also call -// VerifySignature() with a signature to check. -// -// You'll probably want to use VerifySignatureWithPEM instead of -// parsing the public key yourself. -func (u *Update) VerifySignatureWith(publicKey *rsa.PublicKey) *Update { - u.PublicKey = publicKey - return u -} - -// VerifySignatureWithPEM configures the update to use the given PEM-formatted -// RSA public key to verify the update's signature. You must also call -// VerifySignature() with a signature to check. -// -// A PEM formatted public key typically begins with -// -----BEGIN PUBLIC KEY----- -func (u *Update) VerifySignatureWithPEM(publicKeyPEM []byte) (*Update, error) { - block, _ := pem.Decode(publicKeyPEM) - if block == nil { - return u, fmt.Errorf("Couldn't parse PEM data") - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return u, err - } - - var ok bool - u.PublicKey, ok = pub.(*rsa.PublicKey) - if !ok { - return u, fmt.Errorf("Public key isn't an RSA public key") - } - - return u, nil -} - -// FromUrl updates the target with the contents of the given URL. -func (u *Update) FromUrl(url string) (err error, errRecover error) { - target := new(download.MemoryTarget) - err = download.New(url, target, u.HTTPClient).Get() - if err != nil { - return - } - - return u.FromStream(target) -} - -// FromFile updates the target the contents of the given file. -func (u *Update) FromFile(path string) (err error, errRecover error) { - // open the new updated contents - fp, err := os.Open(path) - if err != nil { - return - } - defer fp.Close() - - // do the update - return u.FromStream(fp) -} - -// FromStream updates the target file with the contents of the supplied io.Reader. -// -// FromStream performs the following actions to ensure a safe cross-platform update: -// -// 1. If configured, applies the contents of the io.Reader as a binary patch. -// -// 2. If configured, computes the sha256 checksum and verifies it matches. -// -// 3. If configured, verifies the RSA signature with a public key. -// -// 4. Creates a new file, /path/to/.target.new with mode 0755 with the contents of the updated file -// -// 5. Renames /path/to/target to /path/to/.target.old -// -// 6. Renames /path/to/.target.new to /path/to/target -// -// 7. If the rename is successful, deletes /path/to/.target.old, returns no error -// -// 8. If the rename fails, attempts to rename /path/to/.target.old back to /path/to/target -// If this operation fails, it is reported in the errRecover return value so as not to -// mask the original error that caused the recovery attempt. -// -// On Windows, the removal of /path/to/.target.old always fails, so instead, -// we just make the old file hidden instead. -func (u *Update) FromStream(updateWith io.Reader) (err error, errRecover error) { - updatePath, err := u.getPath() - if err != nil { - return - } - - var newBytes []byte - // apply a patch if requested - switch u.PatchType { - case PATCHTYPE_BSDIFF: - newBytes, err = applyPatch(updateWith, updatePath) - if err != nil { - return - } - case PATCHTYPE_NONE: - // no patch to apply, go on through - newBytes, err = ioutil.ReadAll(updateWith) - if err != nil { - return - } - default: - err = fmt.Errorf("Unrecognized patch type: %s", u.PatchType) - return - } - - // verify checksum if requested - if u.Checksum != nil { - if err = verifyChecksum(newBytes, u.Checksum); err != nil { - return - } - } - - // verify signature if requested - if u.Signature != nil || u.PublicKey != nil { - if u.Signature == nil { - err = fmt.Errorf("No public key specified to verify signature") - return - } - - if u.PublicKey == nil { - err = fmt.Errorf("No signature to verify!") - return - } - - if err = verifySignature(newBytes, u.Signature, u.PublicKey); err != nil { - return - } - } - - // get the directory the executable exists in - updateDir := filepath.Dir(updatePath) - filename := filepath.Base(updatePath) - - // Copy the contents of of newbinary to a the new executable file - newPath := filepath.Join(updateDir, fmt.Sprintf(".%s.new", filename)) - fp, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) - if err != nil { - return - } - defer fp.Close() - _, err = io.Copy(fp, bytes.NewReader(newBytes)) - - // 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 - oldPath := filepath.Join(updateDir, fmt.Sprintf(".%s.old", filename)) - - // 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(oldPath) - - // move the existing executable to a new file in the same directory - err = os.Rename(updatePath, oldPath) - if err != nil { - return - } - - // move the new exectuable in to become the new program - err = os.Rename(newPath, updatePath) - - if err != nil { - // copy unsuccessful - errRecover = os.Rename(oldPath, updatePath) - } else { - // copy successful, remove the old binary - errRemove := os.Remove(oldPath) - - // windows has trouble with removing old binaries, so hide it instead - if errRemove != nil { - _ = hideFile(oldPath) - } - } - - return -} - -// CanUpdate() determines whether the process has the correct permissions to -// perform the requested update. If the update can proceed, it returns nil, otherwise -// it returns the error that would occur if an update were attempted. -func (u *Update) CanUpdate() (err error) { - // get the directory the file exists in - path, err := u.getPath() - if err != nil { - return - } - - fileDir := filepath.Dir(path) - fileName := filepath.Base(path) - - // attempt to open a file in the file's directory - newPath := filepath.Join(fileDir, fmt.Sprintf(".%s.new", fileName)) - fp, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) - if err != nil { - return - } - fp.Close() - - _ = os.Remove(newPath) - return -} - -func applyPatch(patch io.Reader, updatePath string) ([]byte, error) { - // open the file to update - old, err := os.Open(updatePath) - if err != nil { - return nil, err - } - defer old.Close() - - // apply the patch - applied := new(bytes.Buffer) - if err = binarydist.Patch(old, applied, patch); err != nil { - return nil, err - } - - return applied.Bytes(), nil -} - -func verifyChecksum(updated []byte, expectedChecksum []byte) error { - checksum, err := ChecksumForBytes(updated) - if err != nil { - return err - } - - if !bytes.Equal(expectedChecksum, checksum) { - return fmt.Errorf("Updated file has wrong checksum. Expected: %x, got: %x", expectedChecksum, checksum) - } - - return nil -} - -// ChecksumForFile returns the sha256 checksum for the given file -func ChecksumForFile(path string) ([]byte, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - return ChecksumForReader(f) -} - -// ChecksumForReader returns the sha256 checksum for the entire -// contents of the given reader. -func ChecksumForReader(rd io.Reader) ([]byte, error) { - h := sha256.New() - if _, err := io.Copy(h, rd); err != nil { - return nil, err - } - return h.Sum(nil), nil -} - -// ChecksumForBytes returns the sha256 checksum for the given bytes -func ChecksumForBytes(source []byte) ([]byte, error) { - return ChecksumForReader(bytes.NewReader(source)) -} - -func verifySignature(source, signature []byte, publicKey *rsa.PublicKey) error { - checksum, err := ChecksumForBytes(source) - if err != nil { - return err - } - - return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, checksum, signature) -}