diff --git a/Godeps/Readme b/Godeps/Readme
new file mode 100644
index 0000000..4cdaa53
--- /dev/null
+++ b/Godeps/Readme
@@ -0,0 +1,5 @@
+This directory tree is generated automatically by godep.
+
+Please do not edit.
+
+See https://github.com/tools/godep for more information.
diff --git a/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore
new file mode 100644
index 0000000..f037d68
--- /dev/null
+++ b/Godeps/_workspace/.gitignore
@@ -0,0 +1,2 @@
+/pkg
+/bin
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
new file mode 100644
index 0000000..18527a2
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 0000000..37efbb2
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
@@ -0,0 +1,32 @@
+// 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
new file mode 100644
index 0000000..4468a73
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
@@ -0,0 +1,20 @@
+// 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
new file mode 100644
index 0000000..546fec9
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
@@ -0,0 +1,25 @@
+// 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
new file mode 100644
index 0000000..b66cac8
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
@@ -0,0 +1,79 @@
+// 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
new file mode 100644
index 0000000..dc661db
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
@@ -0,0 +1,79 @@
+// 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
new file mode 100644
index 0000000..72d282c
--- /dev/null
+++ b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
@@ -0,0 +1,34 @@
+// 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
new file mode 100644
index 0000000..467def8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/inconshreveable/go-update/README
@@ -0,0 +1,137 @@
+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
new file mode 100644
index 0000000..eee72e2
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go
@@ -0,0 +1,455 @@
+/*
+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/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore b/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore
new file mode 100644
index 0000000..653f160
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore
@@ -0,0 +1 @@
+test.*
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/License b/Godeps/_workspace/src/github.com/kr/binarydist/License
new file mode 100644
index 0000000..183c389
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/License
@@ -0,0 +1,22 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md b/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md
new file mode 100644
index 0000000..dadc368
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md
@@ -0,0 +1,7 @@
+# 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/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go b/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go
new file mode 100644
index 0000000..a2516b8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go
@@ -0,0 +1,40 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go b/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go
new file mode 100644
index 0000000..af51616
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go
@@ -0,0 +1,93 @@
+package binarydist
+
+import (
+ "crypto/rand"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+func mustOpen(path string) *os.File {
+ f, err := os.Open(path)
+ if err != nil {
+ panic(err)
+ }
+
+ return f
+}
+
+func mustReadAll(r io.Reader) []byte {
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func fileCmp(a, b *os.File) int64 {
+ sa, err := a.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ sb, err := b.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ if sa != sb {
+ return sa
+ }
+
+ _, err = a.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = b.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ pa, err := ioutil.ReadAll(a)
+ if err != nil {
+ panic(err)
+ }
+
+ pb, err := ioutil.ReadAll(b)
+ if err != nil {
+ panic(err)
+ }
+
+ for i := range pa {
+ if pa[i] != pb[i] {
+ return int64(i)
+ }
+ }
+ return -1
+}
+
+func mustWriteRandFile(path string, size int) *os.File {
+ p := make([]byte, size)
+ _, err := rand.Read(p)
+ if err != nil {
+ panic(err)
+ }
+
+ f, err := os.Create(path)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = f.Write(p)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = f.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ return f
+}
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/diff.go b/Godeps/_workspace/src/github.com/kr/binarydist/diff.go
new file mode 100644
index 0000000..1d2d951
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/diff.go
@@ -0,0 +1,408 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go b/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go
new file mode 100644
index 0000000..9baa492
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go
@@ -0,0 +1,67 @@
+package binarydist
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+var diffT = []struct {
+ old *os.File
+ new *os.File
+}{
+ {
+ old: mustWriteRandFile("test.old", 1e3),
+ new: mustWriteRandFile("test.new", 1e3),
+ },
+ {
+ old: mustOpen("testdata/sample.old"),
+ new: mustOpen("testdata/sample.new"),
+ },
+}
+
+func TestDiff(t *testing.T) {
+ for _, s := range diffT {
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ exp, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+
+ cmd := exec.Command("bsdiff", s.old.Name(), s.new.Name(), exp.Name())
+ cmd.Stdout = os.Stdout
+ err = cmd.Run()
+ os.Remove(exp.Name())
+ if err != nil {
+ panic(err)
+ }
+
+ err = Diff(s.old, s.new, got)
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ _, err = got.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+ gotBuf := mustReadAll(got)
+ expBuf := mustReadAll(exp)
+
+ if !bytes.Equal(gotBuf, expBuf) {
+ t.Fail()
+ t.Logf("diff %s %s", s.old.Name(), s.new.Name())
+ t.Logf("%s: len(got) = %d", got.Name(), len(gotBuf))
+ t.Logf("%s: len(exp) = %d", exp.Name(), len(expBuf))
+ i := matchlen(gotBuf, expBuf)
+ t.Logf("produced different output at pos %d; %d != %d", i, gotBuf[i], expBuf[i])
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/doc.go b/Godeps/_workspace/src/github.com/kr/binarydist/doc.go
new file mode 100644
index 0000000..3c92d87
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/doc.go
@@ -0,0 +1,24 @@
+// 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/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go b/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go
new file mode 100644
index 0000000..75ba585
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go
@@ -0,0 +1,53 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/patch.go b/Godeps/_workspace/src/github.com/kr/binarydist/patch.go
new file mode 100644
index 0000000..eb03225
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/patch.go
@@ -0,0 +1,109 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go b/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go
new file mode 100644
index 0000000..840a919
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go
@@ -0,0 +1,62 @@
+package binarydist
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+func TestPatch(t *testing.T) {
+ mustWriteRandFile("test.old", 1e3)
+ mustWriteRandFile("test.new", 1e3)
+
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ err = exec.Command("bsdiff", "test.old", "test.new", "test.patch").Run()
+ if err != nil {
+ panic(err)
+ }
+
+ err = Patch(mustOpen("test.old"), got, mustOpen("test.patch"))
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ ref, err := got.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ t.Logf("got %d bytes", ref)
+ if n := fileCmp(got, mustOpen("test.new")); n > -1 {
+ t.Fatalf("produced different output at pos %d", n)
+ }
+}
+
+func TestPatchHk(t *testing.T) {
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ err = Patch(mustOpen("testdata/sample.old"), got, mustOpen("testdata/sample.patch"))
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ ref, err := got.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ t.Logf("got %d bytes", ref)
+ if n := fileCmp(got, mustOpen("testdata/sample.new")); n > -1 {
+ t.Fatalf("produced different output at pos %d", n)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/seek.go b/Godeps/_workspace/src/github.com/kr/binarydist/seek.go
new file mode 100644
index 0000000..96c0346
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/seek.go
@@ -0,0 +1,43 @@
+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/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go b/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go
new file mode 100644
index 0000000..be483c3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go
@@ -0,0 +1,33 @@
+package binarydist
+
+import (
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+var sortT = [][]byte{
+ mustRandBytes(1000),
+ mustReadAll(mustOpen("test.old")),
+ []byte("abcdefabcdef"),
+}
+
+func TestQsufsort(t *testing.T) {
+ for _, s := range sortT {
+ I := qsufsort(s)
+ for i := 1; i < len(I); i++ {
+ if bytes.Compare(s[I[i-1]:], s[I[i]:]) > 0 {
+ t.Fatalf("unsorted at %d", i)
+ }
+ }
+ }
+}
+
+func mustRandBytes(n int) []byte {
+ b := make([]byte, n)
+ _, err := rand.Read(b)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new
new file mode 100644
index 0000000..592cdbe
Binary files /dev/null and b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new differ
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old
new file mode 100644
index 0000000..7bc64da
Binary files /dev/null and b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old differ
diff --git a/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch
new file mode 100644
index 0000000..516a3a9
Binary files /dev/null and b/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch differ
diff --git a/selfupdate/Godeps/Godeps.json b/selfupdate/Godeps/Godeps.json
new file mode 100644
index 0000000..29e6ec2
--- /dev/null
+++ b/selfupdate/Godeps/Godeps.json
@@ -0,0 +1,19 @@
+{
+ "ImportPath": "github.com/sanbornm/go-selfupdate/selfupdate",
+ "GoVersion": "go1.3",
+ "Deps": [
+ {
+ "ImportPath": "bitbucket.org/kardianos/osext",
+ "Comment": "null-13",
+ "Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e"
+ },
+ {
+ "ImportPath": "github.com/inconshreveable/go-update",
+ "Rev": "3f0466666779bd2143f368a207b0641f0ed536e8"
+ },
+ {
+ "ImportPath": "github.com/kr/binarydist",
+ "Rev": "9955b0ab8708602d411341e55fffd7e0700f86bd"
+ }
+ ]
+}
diff --git a/selfupdate/Godeps/Readme b/selfupdate/Godeps/Readme
new file mode 100644
index 0000000..4cdaa53
--- /dev/null
+++ b/selfupdate/Godeps/Readme
@@ -0,0 +1,5 @@
+This directory tree is generated automatically by godep.
+
+Please do not edit.
+
+See https://github.com/tools/godep for more information.
diff --git a/selfupdate/Godeps/_workspace/.gitignore b/selfupdate/Godeps/_workspace/.gitignore
new file mode 100644
index 0000000..f037d68
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/.gitignore
@@ -0,0 +1,2 @@
+/pkg
+/bin
diff --git a/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
new file mode 100644
index 0000000..18527a2
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
@@ -0,0 +1,20 @@
+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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
new file mode 100644
index 0000000..37efbb2
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
@@ -0,0 +1,32 @@
+// 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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
new file mode 100644
index 0000000..4468a73
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
@@ -0,0 +1,20 @@
+// 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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
new file mode 100644
index 0000000..546fec9
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
@@ -0,0 +1,25 @@
+// 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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
new file mode 100644
index 0000000..b66cac8
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
@@ -0,0 +1,79 @@
+// 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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
new file mode 100644
index 0000000..dc661db
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
@@ -0,0 +1,79 @@
+// 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/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
new file mode 100644
index 0000000..72d282c
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
@@ -0,0 +1,34 @@
+// 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/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/README b/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/README
new file mode 100644
index 0000000..467def8
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/README
@@ -0,0 +1,137 @@
+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/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go b/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go
new file mode 100644
index 0000000..eee72e2
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/inconshreveable/go-update/update.go
@@ -0,0 +1,455 @@
+/*
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore
new file mode 100644
index 0000000..653f160
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/.gitignore
@@ -0,0 +1 @@
+test.*
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/License b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/License
new file mode 100644
index 0000000..183c389
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/License
@@ -0,0 +1,22 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md
new file mode 100644
index 0000000..dadc368
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/Readme.md
@@ -0,0 +1,7 @@
+# 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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go
new file mode 100644
index 0000000..a2516b8
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/bzip2.go
@@ -0,0 +1,40 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go
new file mode 100644
index 0000000..af51616
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/common_test.go
@@ -0,0 +1,93 @@
+package binarydist
+
+import (
+ "crypto/rand"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+func mustOpen(path string) *os.File {
+ f, err := os.Open(path)
+ if err != nil {
+ panic(err)
+ }
+
+ return f
+}
+
+func mustReadAll(r io.Reader) []byte {
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func fileCmp(a, b *os.File) int64 {
+ sa, err := a.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ sb, err := b.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ if sa != sb {
+ return sa
+ }
+
+ _, err = a.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = b.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ pa, err := ioutil.ReadAll(a)
+ if err != nil {
+ panic(err)
+ }
+
+ pb, err := ioutil.ReadAll(b)
+ if err != nil {
+ panic(err)
+ }
+
+ for i := range pa {
+ if pa[i] != pb[i] {
+ return int64(i)
+ }
+ }
+ return -1
+}
+
+func mustWriteRandFile(path string, size int) *os.File {
+ p := make([]byte, size)
+ _, err := rand.Read(p)
+ if err != nil {
+ panic(err)
+ }
+
+ f, err := os.Create(path)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = f.Write(p)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = f.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ return f
+}
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff.go
new file mode 100644
index 0000000..1d2d951
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff.go
@@ -0,0 +1,408 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go
new file mode 100644
index 0000000..9baa492
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/diff_test.go
@@ -0,0 +1,67 @@
+package binarydist
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+var diffT = []struct {
+ old *os.File
+ new *os.File
+}{
+ {
+ old: mustWriteRandFile("test.old", 1e3),
+ new: mustWriteRandFile("test.new", 1e3),
+ },
+ {
+ old: mustOpen("testdata/sample.old"),
+ new: mustOpen("testdata/sample.new"),
+ },
+}
+
+func TestDiff(t *testing.T) {
+ for _, s := range diffT {
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ exp, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+
+ cmd := exec.Command("bsdiff", s.old.Name(), s.new.Name(), exp.Name())
+ cmd.Stdout = os.Stdout
+ err = cmd.Run()
+ os.Remove(exp.Name())
+ if err != nil {
+ panic(err)
+ }
+
+ err = Diff(s.old, s.new, got)
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ _, err = got.Seek(0, 0)
+ if err != nil {
+ panic(err)
+ }
+ gotBuf := mustReadAll(got)
+ expBuf := mustReadAll(exp)
+
+ if !bytes.Equal(gotBuf, expBuf) {
+ t.Fail()
+ t.Logf("diff %s %s", s.old.Name(), s.new.Name())
+ t.Logf("%s: len(got) = %d", got.Name(), len(gotBuf))
+ t.Logf("%s: len(exp) = %d", exp.Name(), len(expBuf))
+ i := matchlen(gotBuf, expBuf)
+ t.Logf("produced different output at pos %d; %d != %d", i, gotBuf[i], expBuf[i])
+ }
+ }
+}
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/doc.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/doc.go
new file mode 100644
index 0000000..3c92d87
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/doc.go
@@ -0,0 +1,24 @@
+// 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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go
new file mode 100644
index 0000000..75ba585
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/encoding.go
@@ -0,0 +1,53 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch.go
new file mode 100644
index 0000000..eb03225
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch.go
@@ -0,0 +1,109 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go
new file mode 100644
index 0000000..840a919
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/patch_test.go
@@ -0,0 +1,62 @@
+package binarydist
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+func TestPatch(t *testing.T) {
+ mustWriteRandFile("test.old", 1e3)
+ mustWriteRandFile("test.new", 1e3)
+
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ err = exec.Command("bsdiff", "test.old", "test.new", "test.patch").Run()
+ if err != nil {
+ panic(err)
+ }
+
+ err = Patch(mustOpen("test.old"), got, mustOpen("test.patch"))
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ ref, err := got.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ t.Logf("got %d bytes", ref)
+ if n := fileCmp(got, mustOpen("test.new")); n > -1 {
+ t.Fatalf("produced different output at pos %d", n)
+ }
+}
+
+func TestPatchHk(t *testing.T) {
+ got, err := ioutil.TempFile("/tmp", "bspatch.")
+ if err != nil {
+ panic(err)
+ }
+ os.Remove(got.Name())
+
+ err = Patch(mustOpen("testdata/sample.old"), got, mustOpen("testdata/sample.patch"))
+ if err != nil {
+ t.Fatal("err", err)
+ }
+
+ ref, err := got.Seek(0, 2)
+ if err != nil {
+ panic(err)
+ }
+
+ t.Logf("got %d bytes", ref)
+ if n := fileCmp(got, mustOpen("testdata/sample.new")); n > -1 {
+ t.Fatalf("produced different output at pos %d", n)
+ }
+}
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/seek.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/seek.go
new file mode 100644
index 0000000..96c0346
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/seek.go
@@ -0,0 +1,43 @@
+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/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go
new file mode 100644
index 0000000..be483c3
--- /dev/null
+++ b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/sort_test.go
@@ -0,0 +1,33 @@
+package binarydist
+
+import (
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+var sortT = [][]byte{
+ mustRandBytes(1000),
+ mustReadAll(mustOpen("test.old")),
+ []byte("abcdefabcdef"),
+}
+
+func TestQsufsort(t *testing.T) {
+ for _, s := range sortT {
+ I := qsufsort(s)
+ for i := 1; i < len(I); i++ {
+ if bytes.Compare(s[I[i-1]:], s[I[i]:]) > 0 {
+ t.Fatalf("unsorted at %d", i)
+ }
+ }
+ }
+}
+
+func mustRandBytes(n int) []byte {
+ b := make([]byte, n)
+ _, err := rand.Read(b)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new
new file mode 100644
index 0000000..592cdbe
Binary files /dev/null and b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.new differ
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old
new file mode 100644
index 0000000..7bc64da
Binary files /dev/null and b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.old differ
diff --git a/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch
new file mode 100644
index 0000000..516a3a9
Binary files /dev/null and b/selfupdate/Godeps/_workspace/src/github.com/kr/binarydist/testdata/sample.patch differ