Imported Upstream version 2.6.1 upstream/2.6.1
authorhyokeun <hyokeun.jeon@samsung.com>
Fri, 21 Dec 2018 05:52:55 +0000 (14:52 +0900)
committerhyokeun <hyokeun.jeon@samsung.com>
Fri, 21 Dec 2018 05:52:55 +0000 (14:52 +0900)
27 files changed:
CHANGELOG.md
Makefile
commands/command_status.go
config/version.go
debian/changelog
docker/run_dockers.bsh
git/object_scanner.go
go.mod
go.sum
lfs/gitscanner_tree.go
rpm/SPECS/git-lfs.spec
t/t-fetch.sh
vendor/github.com/davecgh/go-spew/LICENSE [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/bypass.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/common.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/config.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/doc.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/dump.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/format.go [new file with mode: 0644]
vendor/github.com/davecgh/go-spew/spew/spew.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/backend.go
vendor/github.com/git-lfs/gitobj/object_db.go
vendor/github.com/pmezard/go-difflib/LICENSE [new file with mode: 0644]
vendor/github.com/pmezard/go-difflib/difflib/difflib.go [new file with mode: 0644]
vendor/modules.txt
versioninfo.json

index aabb17b..48edfb8 100644 (file)
@@ -1,5 +1,17 @@
 # Git LFS Changelog
 
+## 2.6.1 (3 December 2018)
+
+This release contains miscellaneous bug fixes since v2.6.0. Most notably,
+release v2.6.1 restores support for alternate repositories, which was
+accidentally broken in v2.6.0.
+
+### Bugs
+
+* git: close blob objects when finished #3379 (@bk2204)
+* Avoid hang in repos cloned with --shared or --reference #3383 (@bk2204)
+* vendor: don't remove necessary dependencies #3356 (@ttaylorr)
+
 ## 2.6.0 (1 November, 2018)
 
 This release adds better support for redirecting network calls from a Git LFS
index 826389b..6fbd383 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -48,8 +48,6 @@ RONN_EXTRA_ARGS ?=
 # GREP is the name of the program used for regular expression matching, or
 # 'grep' if unset.
 GREP ?= grep
-# RM is the name of the program used removing files, or 'rm -f' if unset.
-RM ?= rm -f
 # XARGS is the name of the program used to turn stdin into program arguments, or
 # 'xargs' if unset.
 XARGS ?= xargs
@@ -328,9 +326,6 @@ go.sum : go.mod
 .PHONY : vendor
 vendor : go.mod
        $(GO) mod vendor -v
-       $(RM) -r vendor/github.com/ThomsonReutersEikon/go-ntlm/utils
-       $(RM) -r vendor/github.com/davecgh/go-spew
-       $(RM) -r vendor/github.com/pmezard/go-difflib
 
 # fmt runs goimports over all files in Git LFS (as defined by $(SOURCES) above),
 # and replaces their contents with a formatted one in-place.
index 47bec0c..0b0484f 100644 (file)
@@ -33,8 +33,6 @@ func statusCommand(cmd *cobra.Command, args []string) {
 
        scanner, err := lfs.NewPointerScanner()
        if err != nil {
-               scanner.Close()
-
                ExitWithError(err)
        }
 
index 5b59ad7..0290268 100644 (file)
@@ -12,7 +12,7 @@ var (
 )
 
 const (
-       Version = "2.6.0"
+       Version = "2.6.1"
 )
 
 func init() {
index b8ac0ee..b7e171b 100644 (file)
@@ -1,3 +1,9 @@
+git-lfs (2.6.1) stable; urgency=low
+
+  * New upstream version
+
+ -- brian m. carlson <bk2204@github.com>  Mon, 3 Dec 2018 14:29:00 +0000
+
 git-lfs (2.6.0) stable; urgency=low
 
   * New upstream version
index b197ea9..ef9e1eb 100755 (executable)
@@ -95,6 +95,7 @@ for IMAGE_NAME in "${IMAGES[@]}"; do
   echo Compiling LFS in docker image ${IMAGE_NAME}
   IMAGE_REPO_DIR="${PACKAGE_DIR}"/"${IMAGE_INFO[0]}"/"${IMAGE_INFO[1]}"
   $SUDO docker run "${OTHER_OPTIONS[@]}" ${DOCKER_OTHER_OPTIONS-} \
+                   -e USER=root \
                    -e REPO_HOSTNAME=${REPO_HOSTNAME:-git-lfs.github.com} \
                    -e FINAL_UID=${FINAL_UID} \
                    -e FINAL_GID=${FINAL_GID} \
index 3d531ea..2bbb037 100644 (file)
@@ -20,6 +20,8 @@ type object struct {
        Size int64
        // Type is the type of the object being held.
        Type string
+       // object is the gitobj object being handled.
+       object gitobj.Object
 }
 
 // ObjectScanner is a scanner type that scans for Git objects reference-able in
@@ -68,6 +70,11 @@ func NewObjectScannerFrom(db *gitobj.ObjectDatabase) *ObjectScanner {
 // Scan() returns whether the scan was successful, or in other words, whether or
 // not the scanner can continue to progress.
 func (s *ObjectScanner) Scan(oid string) bool {
+       if err := s.reset(); err != nil {
+               s.err = err
+               return false
+       }
+
        obj, err := s.scan(oid)
        s.object = obj
 
@@ -88,6 +95,8 @@ func (s *ObjectScanner) Close() error {
                return nil
        }
 
+       s.reset()
+
        return nil
 }
 
@@ -116,6 +125,21 @@ func (s *ObjectScanner) Type() string {
 // operation.
 func (s *ObjectScanner) Err() error { return s.err }
 
+func (s *ObjectScanner) reset() error {
+       if s.object != nil {
+               if c, ok := s.object.object.(interface {
+                       Close() error
+               }); ok && c != nil {
+                       if err := c.Close(); err != nil {
+                               return err
+                       }
+               }
+       }
+
+       s.object, s.err = nil, nil
+       return nil
+}
+
 type missingErr struct {
        oid string
 }
@@ -162,5 +186,6 @@ func (s *ObjectScanner) scan(oid string) (*object, error) {
                Oid:      oid,
                Size:     size,
                Type:     obj.Type().String(),
+               object:   obj,
        }, nil
 }
diff --git a/go.mod b/go.mod
index 7f11ff3..19fb824 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/git-lfs/git-lfs
 require (
        github.com/ThomsonReutersEikon/go-ntlm v0.0.0-20151030004737-b00ec39bbdd0
        github.com/alexbrainman/sspi v0.0.0-20180125232955-4729b3d4d858
-       github.com/git-lfs/gitobj v1.0.0
+       github.com/git-lfs/gitobj v1.1.0
        github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18
        github.com/git-lfs/wildmatch v1.0.0
        github.com/inconshreveable/mousetrap v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 21ced97..d7d0b09 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,11 @@
 github.com/ThomsonReutersEikon/go-ntlm v0.0.0-20151030004737-b00ec39bbdd0 h1:iBnLwXNz+Mz2K6MndIM9a4sLBb+TouHB8s0tvx16s4s=
 github.com/ThomsonReutersEikon/go-ntlm v0.0.0-20151030004737-b00ec39bbdd0/go.mod h1:0eFwySJYxbNw/r8cJ01IeztpJfwrgrmiLtYig80Yvrc=
+github.com/alexbrainman/sspi v0.0.0-20180125232955-4729b3d4d858 h1:OZQyEhf4BviydsRdmK4ryeJHotDLd7vL1X8+nnxXkfk=
 github.com/alexbrainman/sspi v0.0.0-20180125232955-4729b3d4d858/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/git-lfs/gitobj v1.0.0 h1:+tZj++WOWMNTMP3aMJrKel8ogWkN+hRRCGNVUE+UXio=
-github.com/git-lfs/gitobj v1.0.0/go.mod h1:EdPNGHVxXe1jTuNXzZT1+CdJCuASoDSLPQuvNOo9nGM=
+github.com/git-lfs/gitobj v1.1.0 h1:XRUyk5nKYTWiO8U4cokO5QeoNUNBL8LKS+jXxXZdCTA=
+github.com/git-lfs/gitobj v1.1.0/go.mod h1:EdPNGHVxXe1jTuNXzZT1+CdJCuASoDSLPQuvNOo9nGM=
 github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18 h1:7Th0eBA4rT8WJNiM1vppjaIv9W5WJinhpbCJvRJxloI=
 github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18/go.mod h1:70O4NAtvWn1jW8V8V+OKrJJYcxDLTmIozfi2fmSz5SI=
 github.com/git-lfs/wildmatch v1.0.0 h1:TKsxqSrEXWj73N4xGcN/ISal8/JJOiAcOv9LH6Zprxw=
@@ -33,4 +34,5 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
 github.com/xeipuuv/gojsonschema v0.0.0-20170210233622-6b67b3fab74d h1:BJPiQVOMMtJsJIkrF4T6K3RKbzqr7rkaybMk33dlGUo=
 github.com/xeipuuv/gojsonschema v0.0.0-20170210233622-6b67b3fab74d/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+golang.org/x/sys v0.0.0-20180831094639-fa5fdf94c789 h1:T8D7l6WB3tLu+VpKvw06ieD/OhBi1XpJmG1U/FtttZg=
 golang.org/x/sys v0.0.0-20180831094639-fa5fdf94c789/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
index 63a4cb4..a841328 100644 (file)
@@ -49,8 +49,6 @@ func runScanTree(cb GitScannerFoundPointer, ref string, filter *filepathfilter.F
 func catFileBatchTree(treeblobs *TreeBlobChannelWrapper) (*PointerChannelWrapper, error) {
        scanner, err := NewPointerScanner()
        if err != nil {
-               scanner.Close()
-
                return nil, err
        }
 
@@ -58,8 +56,10 @@ func catFileBatchTree(treeblobs *TreeBlobChannelWrapper) (*PointerChannelWrapper
        errchan := make(chan error, 10) // Multiple errors possible
 
        go func() {
+               hasNext := true
                for t := range treeblobs.Results {
-                       hasNext := scanner.Scan(t.Sha1)
+                       hasNext = scanner.Scan(t.Sha1)
+
                        if p := scanner.Pointer(); p != nil {
                                p.Name = t.Filename
                                pointers <- p
@@ -74,10 +74,14 @@ func catFileBatchTree(treeblobs *TreeBlobChannelWrapper) (*PointerChannelWrapper
                        }
                }
 
-               // Deal with nested error from incoming treeblobs
-               err := treeblobs.Wait()
-               if err != nil {
-                       errchan <- err
+               // If the scanner quit early, we may still have treeblobs to
+               // read, so waiting for it to close will cause a deadlock.
+               if hasNext {
+                       // Deal with nested error from incoming treeblobs
+                       err := treeblobs.Wait()
+                       if err != nil {
+                               errchan <- err
+                       }
                }
 
                if err = scanner.Close(); err != nil {
index 6fc913e..2e0d53d 100644 (file)
@@ -1,5 +1,5 @@
 Name:           git-lfs
-Version:        2.6.0
+Version:        2.6.1
 Release:        1%{?dist}
 Summary:        Git extension for versioning large files
 
index b65d1fd..9d88cbc 100755 (executable)
@@ -51,8 +51,9 @@ begin_test "init for fetch tests"
   git push origin newbranch
   assert_server_object "$reponame" "$b_oid"
 
-  # This clone is used for subsequent tests
+  # These clones are used for subsequent tests
   clone_repo "$reponame" clone
+  git clone --shared "$TRASHDIR/clone" "$TRASHDIR/shared"
 )
 end_test
 
@@ -70,6 +71,21 @@ begin_test "fetch"
 )
 end_test
 
+begin_test "fetch (shared repository)"
+(
+  set -e
+  cd shared
+  rm -rf .git/lfs/objects
+
+  git lfs fetch 2>&1 | tee fetch.log
+  ! grep "Could not scan" fetch.log
+  assert_local_object "$contents_oid" 1
+
+  git lfs fsck 2>&1 | tee fsck.log
+  grep "Git LFS fsck OK" fsck.log
+)
+end_test
+
 begin_test "fetch with remote"
 (
   set -e
diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644 (file)
index 0000000..bc52e96
--- /dev/null
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644 (file)
index 0000000..7929947
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is not running on Google App Engine, compiled by GopherJS, and
+// "-tags safe" is not added to the go build command line.  The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// Go versions prior to 1.4 are disabled because they use a different layout
+// for interfaces which make the implementation of unsafeReflectValue more complex.
+// +build !js,!appengine,!safe,!disableunsafe,go1.4
+
+package spew
+
+import (
+       "reflect"
+       "unsafe"
+)
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = false
+
+       // ptrSize is the size of a pointer on the current arch.
+       ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+type flag uintptr
+
+var (
+       // flagRO indicates whether the value field of a reflect.Value
+       // is read-only.
+       flagRO flag
+
+       // flagAddr indicates whether the address of the reflect.Value's
+       // value may be taken.
+       flagAddr flag
+)
+
+// flagKindMask holds the bits that make up the kind
+// part of the flags field. In all the supported versions,
+// it is in the lower 5 bits.
+const flagKindMask = flag(0x1f)
+
+// Different versions of Go have used different
+// bit layouts for the flags type. This table
+// records the known combinations.
+var okFlags = []struct {
+       ro, addr flag
+}{{
+       // From Go 1.4 to 1.5
+       ro:   1 << 5,
+       addr: 1 << 7,
+}, {
+       // Up to Go tip.
+       ro:   1<<5 | 1<<6,
+       addr: 1 << 8,
+}}
+
+var flagValOffset = func() uintptr {
+       field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+       if !ok {
+               panic("reflect.Value has no flag field")
+       }
+       return field.Offset
+}()
+
+// flagField returns a pointer to the flag field of a reflect.Value.
+func flagField(v *reflect.Value) *flag {
+       return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data.  It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+       if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
+               return v
+       }
+       flagFieldPtr := flagField(&v)
+       *flagFieldPtr &^= flagRO
+       *flagFieldPtr |= flagAddr
+       return v
+}
+
+// Sanity checks against future reflect package changes
+// to the type or semantics of the Value.flag field.
+func init() {
+       field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+       if !ok {
+               panic("reflect.Value has no flag field")
+       }
+       if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
+               panic("reflect.Value flag field has changed kind")
+       }
+       type t0 int
+       var t struct {
+               A t0
+               // t0 will have flagEmbedRO set.
+               t0
+               // a will have flagStickyRO set
+               a t0
+       }
+       vA := reflect.ValueOf(t).FieldByName("A")
+       va := reflect.ValueOf(t).FieldByName("a")
+       vt0 := reflect.ValueOf(t).FieldByName("t0")
+
+       // Infer flagRO from the difference between the flags
+       // for the (otherwise identical) fields in t.
+       flagPublic := *flagField(&vA)
+       flagWithRO := *flagField(&va) | *flagField(&vt0)
+       flagRO = flagPublic ^ flagWithRO
+
+       // Infer flagAddr from the difference between a value
+       // taken from a pointer and not.
+       vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
+       flagNoPtr := *flagField(&vA)
+       flagPtr := *flagField(&vPtrA)
+       flagAddr = flagNoPtr ^ flagPtr
+
+       // Check that the inferred flags tally with one of the known versions.
+       for _, f := range okFlags {
+               if flagRO == f.ro && flagAddr == f.addr {
+                       return
+               }
+       }
+       panic("reflect.Value read-only flag has changed semantics")
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644 (file)
index 0000000..205c28d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is running on Google App Engine, compiled by GopherJS, or
+// "-tags safe" is added to the go build command line.  The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// +build js appengine safe disableunsafe !go1.4
+
+package spew
+
+import "reflect"
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data.  However, doing this relies on access to
+// the unsafe package.  This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+       return v
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644 (file)
index 0000000..1be8ce9
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "reflect"
+       "sort"
+       "strconv"
+)
+
+// Some constants in the form of bytes to avoid string overhead.  This mirrors
+// the technique used in the fmt package.
+var (
+       panicBytes            = []byte("(PANIC=")
+       plusBytes             = []byte("+")
+       iBytes                = []byte("i")
+       trueBytes             = []byte("true")
+       falseBytes            = []byte("false")
+       interfaceBytes        = []byte("(interface {})")
+       commaNewlineBytes     = []byte(",\n")
+       newlineBytes          = []byte("\n")
+       openBraceBytes        = []byte("{")
+       openBraceNewlineBytes = []byte("{\n")
+       closeBraceBytes       = []byte("}")
+       asteriskBytes         = []byte("*")
+       colonBytes            = []byte(":")
+       colonSpaceBytes       = []byte(": ")
+       openParenBytes        = []byte("(")
+       closeParenBytes       = []byte(")")
+       spaceBytes            = []byte(" ")
+       pointerChainBytes     = []byte("->")
+       nilAngleBytes         = []byte("<nil>")
+       maxNewlineBytes       = []byte("<max depth reached>\n")
+       maxShortBytes         = []byte("<max>")
+       circularBytes         = []byte("<already shown>")
+       circularShortBytes    = []byte("<shown>")
+       invalidAngleBytes     = []byte("<invalid>")
+       openBracketBytes      = []byte("[")
+       closeBracketBytes     = []byte("]")
+       percentBytes          = []byte("%")
+       precisionBytes        = []byte(".")
+       openAngleBytes        = []byte("<")
+       closeAngleBytes       = []byte(">")
+       openMapBytes          = []byte("map[")
+       closeMapBytes         = []byte("]")
+       lenEqualsBytes        = []byte("len=")
+       capEqualsBytes        = []byte("cap=")
+)
+
+// hexDigits is used to map a decimal value to a hex digit.
+var hexDigits = "0123456789abcdef"
+
+// catchPanic handles any panics that might occur during the handleMethods
+// calls.
+func catchPanic(w io.Writer, v reflect.Value) {
+       if err := recover(); err != nil {
+               w.Write(panicBytes)
+               fmt.Fprintf(w, "%v", err)
+               w.Write(closeParenBytes)
+       }
+}
+
+// handleMethods attempts to call the Error and String methods on the underlying
+// type the passed reflect.Value represents and outputes the result to Writer w.
+//
+// It handles panics in any called methods by catching and displaying the error
+// as the formatted value.
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
+       // We need an interface to check if the type implements the error or
+       // Stringer interface.  However, the reflect package won't give us an
+       // interface on certain things like unexported struct fields in order
+       // to enforce visibility rules.  We use unsafe, when it's available,
+       // to bypass these restrictions since this package does not mutate the
+       // values.
+       if !v.CanInterface() {
+               if UnsafeDisabled {
+                       return false
+               }
+
+               v = unsafeReflectValue(v)
+       }
+
+       // Choose whether or not to do error and Stringer interface lookups against
+       // the base type or a pointer to the base type depending on settings.
+       // Technically calling one of these methods with a pointer receiver can
+       // mutate the value, however, types which choose to satisify an error or
+       // Stringer interface with a pointer receiver should not be mutating their
+       // state inside these interface methods.
+       if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+               v = unsafeReflectValue(v)
+       }
+       if v.CanAddr() {
+               v = v.Addr()
+       }
+
+       // Is it an error or Stringer?
+       switch iface := v.Interface().(type) {
+       case error:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.Error()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+
+               w.Write([]byte(iface.Error()))
+               return true
+
+       case fmt.Stringer:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.String()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+               w.Write([]byte(iface.String()))
+               return true
+       }
+       return false
+}
+
+// printBool outputs a boolean value as true or false to Writer w.
+func printBool(w io.Writer, val bool) {
+       if val {
+               w.Write(trueBytes)
+       } else {
+               w.Write(falseBytes)
+       }
+}
+
+// printInt outputs a signed integer value to Writer w.
+func printInt(w io.Writer, val int64, base int) {
+       w.Write([]byte(strconv.FormatInt(val, base)))
+}
+
+// printUint outputs an unsigned integer value to Writer w.
+func printUint(w io.Writer, val uint64, base int) {
+       w.Write([]byte(strconv.FormatUint(val, base)))
+}
+
+// printFloat outputs a floating point value using the specified precision,
+// which is expected to be 32 or 64bit, to Writer w.
+func printFloat(w io.Writer, val float64, precision int) {
+       w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
+}
+
+// printComplex outputs a complex value using the specified float precision
+// for the real and imaginary parts to Writer w.
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
+       r := real(c)
+       w.Write(openParenBytes)
+       w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
+       i := imag(c)
+       if i >= 0 {
+               w.Write(plusBytes)
+       }
+       w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
+       w.Write(iBytes)
+       w.Write(closeParenBytes)
+}
+
+// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
+// prefix to Writer w.
+func printHexPtr(w io.Writer, p uintptr) {
+       // Null pointer.
+       num := uint64(p)
+       if num == 0 {
+               w.Write(nilAngleBytes)
+               return
+       }
+
+       // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
+       buf := make([]byte, 18)
+
+       // It's simpler to construct the hex string right to left.
+       base := uint64(16)
+       i := len(buf) - 1
+       for num >= base {
+               buf[i] = hexDigits[num%base]
+               num /= base
+               i--
+       }
+       buf[i] = hexDigits[num]
+
+       // Add '0x' prefix.
+       i--
+       buf[i] = 'x'
+       i--
+       buf[i] = '0'
+
+       // Strip unused leading bytes.
+       buf = buf[i:]
+       w.Write(buf)
+}
+
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
+// elements to be sorted.
+type valuesSorter struct {
+       values  []reflect.Value
+       strings []string // either nil or same len and values
+       cs      *ConfigState
+}
+
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
+// surrogate keys on which the data should be sorted.  It uses flags in
+// ConfigState to decide if and how to populate those surrogate keys.
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
+       vs := &valuesSorter{values: values, cs: cs}
+       if canSortSimply(vs.values[0].Kind()) {
+               return vs
+       }
+       if !cs.DisableMethods {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       b := bytes.Buffer{}
+                       if !handleMethods(cs, &b, vs.values[i]) {
+                               vs.strings = nil
+                               break
+                       }
+                       vs.strings[i] = b.String()
+               }
+       }
+       if vs.strings == nil && cs.SpewKeys {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
+               }
+       }
+       return vs
+}
+
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
+// directly, or whether it should be considered for sorting by surrogate keys
+// (if the ConfigState allows it).
+func canSortSimply(kind reflect.Kind) bool {
+       // This switch parallels valueSortLess, except for the default case.
+       switch kind {
+       case reflect.Bool:
+               return true
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return true
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return true
+       case reflect.Float32, reflect.Float64:
+               return true
+       case reflect.String:
+               return true
+       case reflect.Uintptr:
+               return true
+       case reflect.Array:
+               return true
+       }
+       return false
+}
+
+// Len returns the number of values in the slice.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Len() int {
+       return len(s.values)
+}
+
+// Swap swaps the values at the passed indices.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Swap(i, j int) {
+       s.values[i], s.values[j] = s.values[j], s.values[i]
+       if s.strings != nil {
+               s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
+       }
+}
+
+// valueSortLess returns whether the first value should sort before the second
+// value.  It is used by valueSorter.Less as part of the sort.Interface
+// implementation.
+func valueSortLess(a, b reflect.Value) bool {
+       switch a.Kind() {
+       case reflect.Bool:
+               return !a.Bool() && b.Bool()
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return a.Int() < b.Int()
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return a.Uint() < b.Uint()
+       case reflect.Float32, reflect.Float64:
+               return a.Float() < b.Float()
+       case reflect.String:
+               return a.String() < b.String()
+       case reflect.Uintptr:
+               return a.Uint() < b.Uint()
+       case reflect.Array:
+               // Compare the contents of both arrays.
+               l := a.Len()
+               for i := 0; i < l; i++ {
+                       av := a.Index(i)
+                       bv := b.Index(i)
+                       if av.Interface() == bv.Interface() {
+                               continue
+                       }
+                       return valueSortLess(av, bv)
+               }
+       }
+       return a.String() < b.String()
+}
+
+// Less returns whether the value at index i should sort before the
+// value at index j.  It is part of the sort.Interface implementation.
+func (s *valuesSorter) Less(i, j int) bool {
+       if s.strings == nil {
+               return valueSortLess(s.values[i], s.values[j])
+       }
+       return s.strings[i] < s.strings[j]
+}
+
+// sortValues is a sort function that handles both native types and any type that
+// can be converted to error or Stringer.  Other inputs are sorted according to
+// their Value.String() value to ensure display stability.
+func sortValues(values []reflect.Value, cs *ConfigState) {
+       if len(values) == 0 {
+               return
+       }
+       sort.Sort(newValuesSorter(values, cs))
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644 (file)
index 0000000..2e3d22f
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+)
+
+// ConfigState houses the configuration options used by spew to format and
+// display values.  There is a global instance, Config, that is used to control
+// all top-level Formatter and Dump functionality.  Each ConfigState instance
+// provides methods equivalent to the top-level functions.
+//
+// The zero value for ConfigState provides no indentation.  You would typically
+// want to set it to a space or a tab.
+//
+// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
+// with default settings.  See the documentation of NewDefaultConfig for default
+// values.
+type ConfigState struct {
+       // Indent specifies the string to use for each indentation level.  The
+       // global config instance that all top-level functions use set this to a
+       // single space by default.  If you would like more indentation, you might
+       // set this to a tab with "\t" or perhaps two spaces with "  ".
+       Indent string
+
+       // MaxDepth controls the maximum number of levels to descend into nested
+       // data structures.  The default, 0, means there is no limit.
+       //
+       // NOTE: Circular data structures are properly detected, so it is not
+       // necessary to set this value unless you specifically want to limit deeply
+       // nested data structures.
+       MaxDepth int
+
+       // DisableMethods specifies whether or not error and Stringer interfaces are
+       // invoked for types that implement them.
+       DisableMethods bool
+
+       // DisablePointerMethods specifies whether or not to check for and invoke
+       // error and Stringer interfaces on types which only accept a pointer
+       // receiver when the current type is not a pointer.
+       //
+       // NOTE: This might be an unsafe action since calling one of these methods
+       // with a pointer receiver could technically mutate the value, however,
+       // in practice, types which choose to satisify an error or Stringer
+       // interface with a pointer receiver should not be mutating their state
+       // inside these interface methods.  As a result, this option relies on
+       // access to the unsafe package, so it will not have any effect when
+       // running in environments without access to the unsafe package such as
+       // Google App Engine or with the "safe" build tag specified.
+       DisablePointerMethods bool
+
+       // DisablePointerAddresses specifies whether to disable the printing of
+       // pointer addresses. This is useful when diffing data structures in tests.
+       DisablePointerAddresses bool
+
+       // DisableCapacities specifies whether to disable the printing of capacities
+       // for arrays, slices, maps and channels. This is useful when diffing
+       // data structures in tests.
+       DisableCapacities bool
+
+       // ContinueOnMethod specifies whether or not recursion should continue once
+       // a custom error or Stringer interface is invoked.  The default, false,
+       // means it will print the results of invoking the custom error or Stringer
+       // interface and return immediately instead of continuing to recurse into
+       // the internals of the data type.
+       //
+       // NOTE: This flag does not have any effect if method invocation is disabled
+       // via the DisableMethods or DisablePointerMethods options.
+       ContinueOnMethod bool
+
+       // SortKeys specifies map keys should be sorted before being printed. Use
+       // this to have a more deterministic, diffable output.  Note that only
+       // native types (bool, int, uint, floats, uintptr and string) and types
+       // that support the error or Stringer interfaces (if methods are
+       // enabled) are supported, with other types sorted according to the
+       // reflect.Value.String() output which guarantees display stability.
+       SortKeys bool
+
+       // SpewKeys specifies that, as a last resort attempt, map keys should
+       // be spewed to strings and sorted by those strings.  This is only
+       // considered if SortKeys is true.
+       SpewKeys bool
+}
+
+// Config is the active configuration of the top-level functions.
+// The configuration can be changed by modifying the contents of spew.Config.
+var Config = ConfigState{Indent: " "}
+
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the formatted string as a value that satisfies error.  See NewFormatter
+// for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
+       return fmt.Errorf(format, c.convertArgs(a)...)
+}
+
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+       return fmt.Fprint(w, c.convertArgs(a)...)
+}
+
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+       return fmt.Fprintf(w, format, c.convertArgs(a)...)
+}
+
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
+// passed with a Formatter interface returned by c.NewFormatter.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+       return fmt.Fprintln(w, c.convertArgs(a)...)
+}
+
+// Print is a wrapper for fmt.Print that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
+       return fmt.Print(c.convertArgs(a)...)
+}
+
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
+       return fmt.Printf(format, c.convertArgs(a)...)
+}
+
+// Println is a wrapper for fmt.Println that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
+       return fmt.Println(c.convertArgs(a)...)
+}
+
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprint(a ...interface{}) string {
+       return fmt.Sprint(c.convertArgs(a)...)
+}
+
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter.  It returns
+// the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
+       return fmt.Sprintf(format, c.convertArgs(a)...)
+}
+
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
+// were passed with a Formatter interface returned by c.NewFormatter.  It
+// returns the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintln(a ...interface{}) string {
+       return fmt.Sprintln(c.convertArgs(a)...)
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface.  As a result, it integrates cleanly with standard fmt package
+printing functions.  The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
+combinations.  Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting.  In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly.  It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+c.Printf, c.Println, or c.Printf.
+*/
+func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
+       return newFormatter(c, v)
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w.  It formats
+// exactly the same as Dump.
+func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
+       fdump(c, w, a...)
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value.  It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+       * Pointers are dereferenced and followed
+       * Circular data structures are detected and handled properly
+       * Custom Stringer/error interfaces are optionally invoked, including
+         on unexported types
+       * Custom types which only implement the Stringer/error interfaces via
+         a pointer receiver are optionally invoked when passing non-pointer
+         variables
+       * Byte arrays and slices are dumped like the hexdump -C command which
+         includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by modifying the public members
+of c.  See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func (c *ConfigState) Dump(a ...interface{}) {
+       fdump(c, os.Stdout, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func (c *ConfigState) Sdump(a ...interface{}) string {
+       var buf bytes.Buffer
+       fdump(c, &buf, a...)
+       return buf.String()
+}
+
+// convertArgs accepts a slice of arguments and returns a slice of the same
+// length with each argument converted to a spew Formatter interface using
+// the ConfigState associated with s.
+func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
+       formatters = make([]interface{}, len(args))
+       for index, arg := range args {
+               formatters[index] = newFormatter(c, arg)
+       }
+       return formatters
+}
+
+// NewDefaultConfig returns a ConfigState with the following default settings.
+//
+//     Indent: " "
+//     MaxDepth: 0
+//     DisableMethods: false
+//     DisablePointerMethods: false
+//     ContinueOnMethod: false
+//     SortKeys: false
+func NewDefaultConfig() *ConfigState {
+       return &ConfigState{Indent: " "}
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644 (file)
index 0000000..aacaac6
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Package spew implements a deep pretty printer for Go data structures to aid in
+debugging.
+
+A quick overview of the additional features spew provides over the built-in
+printing facilities for Go data types are as follows:
+
+       * Pointers are dereferenced and followed
+       * Circular data structures are detected and handled properly
+       * Custom Stringer/error interfaces are optionally invoked, including
+         on unexported types
+       * Custom types which only implement the Stringer/error interfaces via
+         a pointer receiver are optionally invoked when passing non-pointer
+         variables
+       * Byte arrays and slices are dumped like the hexdump -C command which
+         includes offsets, byte values in hex, and ASCII output (only when using
+         Dump style)
+
+There are two different approaches spew allows for dumping Go data structures:
+
+       * Dump style which prints with newlines, customizable indentation,
+         and additional debug information such as types and all pointer addresses
+         used to indirect to the final value
+       * A custom Formatter interface that integrates cleanly with the standard fmt
+         package and replaces %v, %+v, %#v, and %#+v to provide inline printing
+         similar to the default %v while providing the additional functionality
+         outlined above and passing unsupported format verbs such as %x and %q
+         along to fmt
+
+Quick Start
+
+This section demonstrates how to quickly get started with spew.  See the
+sections below for further details on formatting and configuration options.
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+       spew.Dump(myVar1, myVar2, ...)
+       spew.Fdump(someWriter, myVar1, myVar2, ...)
+       str := spew.Sdump(myVar1, myVar2, ...)
+
+Alternatively, if you would prefer to use format strings with a compacted inline
+printing style, use the convenience wrappers Printf, Fprintf, etc with
+%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
+%#+v (adds types and pointer addresses):
+       spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+       spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+       spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+       spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+Configuration Options
+
+Configuration of spew is handled by fields in the ConfigState type.  For
+convenience, all of the top-level functions use a global state available
+via the spew.Config global.
+
+It is also possible to create a ConfigState instance that provides methods
+equivalent to the top-level functions.  This allows concurrent configuration
+options.  See the ConfigState documentation for more details.
+
+The following configuration options are available:
+       * Indent
+               String to use for each indentation level for Dump functions.
+               It is a single space by default.  A popular alternative is "\t".
+
+       * MaxDepth
+               Maximum number of levels to descend into nested data structures.
+               There is no limit by default.
+
+       * DisableMethods
+               Disables invocation of error and Stringer interface methods.
+               Method invocation is enabled by default.
+
+       * DisablePointerMethods
+               Disables invocation of error and Stringer interface methods on types
+               which only accept pointer receivers from non-pointer variables.
+               Pointer method invocation is enabled by default.
+
+       * DisablePointerAddresses
+               DisablePointerAddresses specifies whether to disable the printing of
+               pointer addresses. This is useful when diffing data structures in tests.
+
+       * DisableCapacities
+               DisableCapacities specifies whether to disable the printing of
+               capacities for arrays, slices, maps and channels. This is useful when
+               diffing data structures in tests.
+
+       * ContinueOnMethod
+               Enables recursion into types after invoking error and Stringer interface
+               methods. Recursion after method invocation is disabled by default.
+
+       * SortKeys
+               Specifies map keys should be sorted before being printed. Use
+               this to have a more deterministic, diffable output.  Note that
+               only native types (bool, int, uint, floats, uintptr and string)
+               and types which implement error or Stringer interfaces are
+               supported with other types sorted according to the
+               reflect.Value.String() output which guarantees display
+               stability.  Natural map order is used by default.
+
+       * SpewKeys
+               Specifies that, as a last resort attempt, map keys should be
+               spewed to strings and sorted by those strings.  This is only
+               considered if SortKeys is true.
+
+Dump Usage
+
+Simply call spew.Dump with a list of variables you want to dump:
+
+       spew.Dump(myVar1, myVar2, ...)
+
+You may also call spew.Fdump if you would prefer to output to an arbitrary
+io.Writer.  For example, to dump to standard error:
+
+       spew.Fdump(os.Stderr, myVar1, myVar2, ...)
+
+A third option is to call spew.Sdump to get the formatted output as a string:
+
+       str := spew.Sdump(myVar1, myVar2, ...)
+
+Sample Dump Output
+
+See the Dump example for details on the setup of the types and variables being
+shown here.
+
+       (main.Foo) {
+        unexportedField: (*main.Bar)(0xf84002e210)({
+         flag: (main.Flag) flagTwo,
+         data: (uintptr) <nil>
+        }),
+        ExportedField: (map[interface {}]interface {}) (len=1) {
+         (string) (len=3) "one": (bool) true
+        }
+       }
+
+Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
+command as shown.
+       ([]uint8) (len=32 cap=32) {
+        00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
+        00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
+        00000020  31 32                                             |12|
+       }
+
+Custom Formatter
+
+Spew provides a custom formatter that implements the fmt.Formatter interface
+so that it integrates cleanly with standard fmt package printing functions. The
+formatter is useful for inline printing of smaller data types similar to the
+standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations.  Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting.  In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Custom Formatter Usage
+
+The simplest way to make use of the spew custom formatter is to call one of the
+convenience functions such as spew.Printf, spew.Println, or spew.Printf.  The
+functions have syntax you are most likely already familiar with:
+
+       spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+       spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+       spew.Println(myVar, myVar2)
+       spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+       spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+See the Index for the full list convenience functions.
+
+Sample Formatter Output
+
+Double pointer to a uint8:
+         %v: <**>5
+        %+v: <**>(0xf8400420d0->0xf8400420c8)5
+        %#v: (**uint8)5
+       %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
+
+Pointer to circular struct with a uint8 field and a pointer to itself:
+         %v: <*>{1 <*><shown>}
+        %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
+        %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
+       %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
+
+See the Printf example for details on the setup of variables being shown
+here.
+
+Errors
+
+Since it is possible for custom Stringer/error interfaces to panic, spew
+detects them and handles them internally by printing the panic information
+inline with the output.  Since spew is intended to provide deep pretty printing
+capabilities on structures, it intentionally does not return any errors.
+*/
+package spew
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644 (file)
index 0000000..f78d89f
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "encoding/hex"
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "regexp"
+       "strconv"
+       "strings"
+)
+
+var (
+       // uint8Type is a reflect.Type representing a uint8.  It is used to
+       // convert cgo types to uint8 slices for hexdumping.
+       uint8Type = reflect.TypeOf(uint8(0))
+
+       // cCharRE is a regular expression that matches a cgo char.
+       // It is used to detect character arrays to hexdump them.
+       cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
+
+       // cUnsignedCharRE is a regular expression that matches a cgo unsigned
+       // char.  It is used to detect unsigned character arrays to hexdump
+       // them.
+       cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
+
+       // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
+       // It is used to detect uint8_t arrays to hexdump them.
+       cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
+)
+
+// dumpState contains information about the state of a dump operation.
+type dumpState struct {
+       w                io.Writer
+       depth            int
+       pointers         map[uintptr]int
+       ignoreNextType   bool
+       ignoreNextIndent bool
+       cs               *ConfigState
+}
+
+// indent performs indentation according to the depth level and cs.Indent
+// option.
+func (d *dumpState) indent() {
+       if d.ignoreNextIndent {
+               d.ignoreNextIndent = false
+               return
+       }
+       d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
+       if v.Kind() == reflect.Interface && !v.IsNil() {
+               v = v.Elem()
+       }
+       return v
+}
+
+// dumpPtr handles formatting of pointers by indirecting them as necessary.
+func (d *dumpState) dumpPtr(v reflect.Value) {
+       // Remove pointers at or below the current depth from map used to detect
+       // circular refs.
+       for k, depth := range d.pointers {
+               if depth >= d.depth {
+                       delete(d.pointers, k)
+               }
+       }
+
+       // Keep list of all dereferenced pointers to show later.
+       pointerChain := make([]uintptr, 0)
+
+       // Figure out how many levels of indirection there are by dereferencing
+       // pointers and unpacking interfaces down the chain while detecting circular
+       // references.
+       nilFound := false
+       cycleFound := false
+       indirects := 0
+       ve := v
+       for ve.Kind() == reflect.Ptr {
+               if ve.IsNil() {
+                       nilFound = true
+                       break
+               }
+               indirects++
+               addr := ve.Pointer()
+               pointerChain = append(pointerChain, addr)
+               if pd, ok := d.pointers[addr]; ok && pd < d.depth {
+                       cycleFound = true
+                       indirects--
+                       break
+               }
+               d.pointers[addr] = d.depth
+
+               ve = ve.Elem()
+               if ve.Kind() == reflect.Interface {
+                       if ve.IsNil() {
+                               nilFound = true
+                               break
+                       }
+                       ve = ve.Elem()
+               }
+       }
+
+       // Display type information.
+       d.w.Write(openParenBytes)
+       d.w.Write(bytes.Repeat(asteriskBytes, indirects))
+       d.w.Write([]byte(ve.Type().String()))
+       d.w.Write(closeParenBytes)
+
+       // Display pointer information.
+       if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
+               d.w.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               d.w.Write(pointerChainBytes)
+                       }
+                       printHexPtr(d.w, addr)
+               }
+               d.w.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       d.w.Write(openParenBytes)
+       switch {
+       case nilFound:
+               d.w.Write(nilAngleBytes)
+
+       case cycleFound:
+               d.w.Write(circularBytes)
+
+       default:
+               d.ignoreNextType = true
+               d.dump(ve)
+       }
+       d.w.Write(closeParenBytes)
+}
+
+// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
+// reflection) arrays and slices are dumped in hexdump -C fashion.
+func (d *dumpState) dumpSlice(v reflect.Value) {
+       // Determine whether this type should be hex dumped or not.  Also,
+       // for types which should be hexdumped, try to use the underlying data
+       // first, then fall back to trying to convert them to a uint8 slice.
+       var buf []uint8
+       doConvert := false
+       doHexDump := false
+       numEntries := v.Len()
+       if numEntries > 0 {
+               vt := v.Index(0).Type()
+               vts := vt.String()
+               switch {
+               // C types that need to be converted.
+               case cCharRE.MatchString(vts):
+                       fallthrough
+               case cUnsignedCharRE.MatchString(vts):
+                       fallthrough
+               case cUint8tCharRE.MatchString(vts):
+                       doConvert = true
+
+               // Try to use existing uint8 slices and fall back to converting
+               // and copying if that fails.
+               case vt.Kind() == reflect.Uint8:
+                       // We need an addressable interface to convert the type
+                       // to a byte slice.  However, the reflect package won't
+                       // give us an interface on certain things like
+                       // unexported struct fields in order to enforce
+                       // visibility rules.  We use unsafe, when available, to
+                       // bypass these restrictions since this package does not
+                       // mutate the values.
+                       vs := v
+                       if !vs.CanInterface() || !vs.CanAddr() {
+                               vs = unsafeReflectValue(vs)
+                       }
+                       if !UnsafeDisabled {
+                               vs = vs.Slice(0, numEntries)
+
+                               // Use the existing uint8 slice if it can be
+                               // type asserted.
+                               iface := vs.Interface()
+                               if slice, ok := iface.([]uint8); ok {
+                                       buf = slice
+                                       doHexDump = true
+                                       break
+                               }
+                       }
+
+                       // The underlying data needs to be converted if it can't
+                       // be type asserted to a uint8 slice.
+                       doConvert = true
+               }
+
+               // Copy and convert the underlying type if needed.
+               if doConvert && vt.ConvertibleTo(uint8Type) {
+                       // Convert and copy each element into a uint8 byte
+                       // slice.
+                       buf = make([]uint8, numEntries)
+                       for i := 0; i < numEntries; i++ {
+                               vv := v.Index(i)
+                               buf[i] = uint8(vv.Convert(uint8Type).Uint())
+                       }
+                       doHexDump = true
+               }
+       }
+
+       // Hexdump the entire slice as needed.
+       if doHexDump {
+               indent := strings.Repeat(d.cs.Indent, d.depth)
+               str := indent + hex.Dump(buf)
+               str = strings.Replace(str, "\n", "\n"+indent, -1)
+               str = strings.TrimRight(str, d.cs.Indent)
+               d.w.Write([]byte(str))
+               return
+       }
+
+       // Recursively call dump for each item.
+       for i := 0; i < numEntries; i++ {
+               d.dump(d.unpackValue(v.Index(i)))
+               if i < (numEntries - 1) {
+                       d.w.Write(commaNewlineBytes)
+               } else {
+                       d.w.Write(newlineBytes)
+               }
+       }
+}
+
+// dump is the main workhorse for dumping a value.  It uses the passed reflect
+// value to figure out what kind of object we are dealing with and formats it
+// appropriately.  It is a recursive function, however circular data structures
+// are detected and handled properly.
+func (d *dumpState) dump(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               d.w.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               d.indent()
+               d.dumpPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !d.ignoreNextType {
+               d.indent()
+               d.w.Write(openParenBytes)
+               d.w.Write([]byte(v.Type().String()))
+               d.w.Write(closeParenBytes)
+               d.w.Write(spaceBytes)
+       }
+       d.ignoreNextType = false
+
+       // Display length and capacity if the built-in len and cap functions
+       // work with the value's kind and the len/cap itself is non-zero.
+       valueLen, valueCap := 0, 0
+       switch v.Kind() {
+       case reflect.Array, reflect.Slice, reflect.Chan:
+               valueLen, valueCap = v.Len(), v.Cap()
+       case reflect.Map, reflect.String:
+               valueLen = v.Len()
+       }
+       if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
+               d.w.Write(openParenBytes)
+               if valueLen != 0 {
+                       d.w.Write(lenEqualsBytes)
+                       printInt(d.w, int64(valueLen), 10)
+               }
+               if !d.cs.DisableCapacities && valueCap != 0 {
+                       if valueLen != 0 {
+                               d.w.Write(spaceBytes)
+                       }
+                       d.w.Write(capEqualsBytes)
+                       printInt(d.w, int64(valueCap), 10)
+               }
+               d.w.Write(closeParenBytes)
+               d.w.Write(spaceBytes)
+       }
+
+       // Call Stringer/error interfaces if they exist and the handle methods flag
+       // is enabled
+       if !d.cs.DisableMethods {
+               if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+                       if handled := handleMethods(d.cs, d.w, v); handled {
+                               return
+                       }
+               }
+       }
+
+       switch kind {
+       case reflect.Invalid:
+               // Do nothing.  We should never get here since invalid has already
+               // been handled above.
+
+       case reflect.Bool:
+               printBool(d.w, v.Bool())
+
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               printInt(d.w, v.Int(), 10)
+
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               printUint(d.w, v.Uint(), 10)
+
+       case reflect.Float32:
+               printFloat(d.w, v.Float(), 32)
+
+       case reflect.Float64:
+               printFloat(d.w, v.Float(), 64)
+
+       case reflect.Complex64:
+               printComplex(d.w, v.Complex(), 32)
+
+       case reflect.Complex128:
+               printComplex(d.w, v.Complex(), 64)
+
+       case reflect.Slice:
+               if v.IsNil() {
+                       d.w.Write(nilAngleBytes)
+                       break
+               }
+               fallthrough
+
+       case reflect.Array:
+               d.w.Write(openBraceNewlineBytes)
+               d.depth++
+               if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+                       d.indent()
+                       d.w.Write(maxNewlineBytes)
+               } else {
+                       d.dumpSlice(v)
+               }
+               d.depth--
+               d.indent()
+               d.w.Write(closeBraceBytes)
+
+       case reflect.String:
+               d.w.Write([]byte(strconv.Quote(v.String())))
+
+       case reflect.Interface:
+               // The only time we should get here is for nil interfaces due to
+               // unpackValue calls.
+               if v.IsNil() {
+                       d.w.Write(nilAngleBytes)
+               }
+
+       case reflect.Ptr:
+               // Do nothing.  We should never get here since pointers have already
+               // been handled above.
+
+       case reflect.Map:
+               // nil maps should be indicated as different than empty maps
+               if v.IsNil() {
+                       d.w.Write(nilAngleBytes)
+                       break
+               }
+
+               d.w.Write(openBraceNewlineBytes)
+               d.depth++
+               if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+                       d.indent()
+                       d.w.Write(maxNewlineBytes)
+               } else {
+                       numEntries := v.Len()
+                       keys := v.MapKeys()
+                       if d.cs.SortKeys {
+                               sortValues(keys, d.cs)
+                       }
+                       for i, key := range keys {
+                               d.dump(d.unpackValue(key))
+                               d.w.Write(colonSpaceBytes)
+                               d.ignoreNextIndent = true
+                               d.dump(d.unpackValue(v.MapIndex(key)))
+                               if i < (numEntries - 1) {
+                                       d.w.Write(commaNewlineBytes)
+                               } else {
+                                       d.w.Write(newlineBytes)
+                               }
+                       }
+               }
+               d.depth--
+               d.indent()
+               d.w.Write(closeBraceBytes)
+
+       case reflect.Struct:
+               d.w.Write(openBraceNewlineBytes)
+               d.depth++
+               if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+                       d.indent()
+                       d.w.Write(maxNewlineBytes)
+               } else {
+                       vt := v.Type()
+                       numFields := v.NumField()
+                       for i := 0; i < numFields; i++ {
+                               d.indent()
+                               vtf := vt.Field(i)
+                               d.w.Write([]byte(vtf.Name))
+                               d.w.Write(colonSpaceBytes)
+                               d.ignoreNextIndent = true
+                               d.dump(d.unpackValue(v.Field(i)))
+                               if i < (numFields - 1) {
+                                       d.w.Write(commaNewlineBytes)
+                               } else {
+                                       d.w.Write(newlineBytes)
+                               }
+                       }
+               }
+               d.depth--
+               d.indent()
+               d.w.Write(closeBraceBytes)
+
+       case reflect.Uintptr:
+               printHexPtr(d.w, uintptr(v.Uint()))
+
+       case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+               printHexPtr(d.w, v.Pointer())
+
+       // There were not any other types at the time this code was written, but
+       // fall back to letting the default fmt package handle it in case any new
+       // types are added.
+       default:
+               if v.CanInterface() {
+                       fmt.Fprintf(d.w, "%v", v.Interface())
+               } else {
+                       fmt.Fprintf(d.w, "%v", v.String())
+               }
+       }
+}
+
+// fdump is a helper function to consolidate the logic from the various public
+// methods which take varying writers and config states.
+func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
+       for _, arg := range a {
+               if arg == nil {
+                       w.Write(interfaceBytes)
+                       w.Write(spaceBytes)
+                       w.Write(nilAngleBytes)
+                       w.Write(newlineBytes)
+                       continue
+               }
+
+               d := dumpState{w: w, cs: cs}
+               d.pointers = make(map[uintptr]int)
+               d.dump(reflect.ValueOf(arg))
+               d.w.Write(newlineBytes)
+       }
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w.  It formats
+// exactly the same as Dump.
+func Fdump(w io.Writer, a ...interface{}) {
+       fdump(&Config, w, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func Sdump(a ...interface{}) string {
+       var buf bytes.Buffer
+       fdump(&Config, &buf, a...)
+       return buf.String()
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value.  It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+       * Pointers are dereferenced and followed
+       * Circular data structures are detected and handled properly
+       * Custom Stringer/error interfaces are optionally invoked, including
+         on unexported types
+       * Custom types which only implement the Stringer/error interfaces via
+         a pointer receiver are optionally invoked when passing non-pointer
+         variables
+       * Byte arrays and slices are dumped like the hexdump -C command which
+         includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by an exported package global,
+spew.Config.  See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func Dump(a ...interface{}) {
+       fdump(&Config, os.Stdout, a...)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644 (file)
index 0000000..b04edb7
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "reflect"
+       "strconv"
+       "strings"
+)
+
+// supportedFlags is a list of all the character flags supported by fmt package.
+const supportedFlags = "0-+# "
+
+// formatState implements the fmt.Formatter interface and contains information
+// about the state of a formatting operation.  The NewFormatter function can
+// be used to get a new Formatter which can be used directly as arguments
+// in standard fmt package printing calls.
+type formatState struct {
+       value          interface{}
+       fs             fmt.State
+       depth          int
+       pointers       map[uintptr]int
+       ignoreNextType bool
+       cs             *ConfigState
+}
+
+// buildDefaultFormat recreates the original format string without precision
+// and width information to pass in to fmt.Sprintf in the case of an
+// unrecognized type.  Unless new types are added to the language, this
+// function won't ever be called.
+func (f *formatState) buildDefaultFormat() (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       buf.WriteRune('v')
+
+       format = buf.String()
+       return format
+}
+
+// constructOrigFormat recreates the original format string including precision
+// and width information to pass along to the standard fmt package.  This allows
+// automatic deferral of all format strings this package doesn't support.
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       if width, ok := f.fs.Width(); ok {
+               buf.WriteString(strconv.Itoa(width))
+       }
+
+       if precision, ok := f.fs.Precision(); ok {
+               buf.Write(precisionBytes)
+               buf.WriteString(strconv.Itoa(precision))
+       }
+
+       buf.WriteRune(verb)
+
+       format = buf.String()
+       return format
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible and
+// ensures that types for values which have been unpacked from an interface
+// are displayed when the show types flag is also set.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
+       if v.Kind() == reflect.Interface {
+               f.ignoreNextType = false
+               if !v.IsNil() {
+                       v = v.Elem()
+               }
+       }
+       return v
+}
+
+// formatPtr handles formatting of pointers by indirecting them as necessary.
+func (f *formatState) formatPtr(v reflect.Value) {
+       // Display nil if top level pointer is nil.
+       showTypes := f.fs.Flag('#')
+       if v.IsNil() && (!showTypes || f.ignoreNextType) {
+               f.fs.Write(nilAngleBytes)
+               return
+       }
+
+       // Remove pointers at or below the current depth from map used to detect
+       // circular refs.
+       for k, depth := range f.pointers {
+               if depth >= f.depth {
+                       delete(f.pointers, k)
+               }
+       }
+
+       // Keep list of all dereferenced pointers to possibly show later.
+       pointerChain := make([]uintptr, 0)
+
+       // Figure out how many levels of indirection there are by derferencing
+       // pointers and unpacking interfaces down the chain while detecting circular
+       // references.
+       nilFound := false
+       cycleFound := false
+       indirects := 0
+       ve := v
+       for ve.Kind() == reflect.Ptr {
+               if ve.IsNil() {
+                       nilFound = true
+                       break
+               }
+               indirects++
+               addr := ve.Pointer()
+               pointerChain = append(pointerChain, addr)
+               if pd, ok := f.pointers[addr]; ok && pd < f.depth {
+                       cycleFound = true
+                       indirects--
+                       break
+               }
+               f.pointers[addr] = f.depth
+
+               ve = ve.Elem()
+               if ve.Kind() == reflect.Interface {
+                       if ve.IsNil() {
+                               nilFound = true
+                               break
+                       }
+                       ve = ve.Elem()
+               }
+       }
+
+       // Display type or indirection level depending on flags.
+       if showTypes && !f.ignoreNextType {
+               f.fs.Write(openParenBytes)
+               f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
+               f.fs.Write([]byte(ve.Type().String()))
+               f.fs.Write(closeParenBytes)
+       } else {
+               if nilFound || cycleFound {
+                       indirects += strings.Count(ve.Type().String(), "*")
+               }
+               f.fs.Write(openAngleBytes)
+               f.fs.Write([]byte(strings.Repeat("*", indirects)))
+               f.fs.Write(closeAngleBytes)
+       }
+
+       // Display pointer information depending on flags.
+       if f.fs.Flag('+') && (len(pointerChain) > 0) {
+               f.fs.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               f.fs.Write(pointerChainBytes)
+                       }
+                       printHexPtr(f.fs, addr)
+               }
+               f.fs.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       switch {
+       case nilFound:
+               f.fs.Write(nilAngleBytes)
+
+       case cycleFound:
+               f.fs.Write(circularShortBytes)
+
+       default:
+               f.ignoreNextType = true
+               f.format(ve)
+       }
+}
+
+// format is the main workhorse for providing the Formatter interface.  It
+// uses the passed reflect value to figure out what kind of object we are
+// dealing with and formats it appropriately.  It is a recursive function,
+// however circular data structures are detected and handled properly.
+func (f *formatState) format(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               f.fs.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               f.formatPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !f.ignoreNextType && f.fs.Flag('#') {
+               f.fs.Write(openParenBytes)
+               f.fs.Write([]byte(v.Type().String()))
+               f.fs.Write(closeParenBytes)
+       }
+       f.ignoreNextType = false
+
+       // Call Stringer/error interfaces if they exist and the handle methods
+       // flag is enabled.
+       if !f.cs.DisableMethods {
+               if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+                       if handled := handleMethods(f.cs, f.fs, v); handled {
+                               return
+                       }
+               }
+       }
+
+       switch kind {
+       case reflect.Invalid:
+               // Do nothing.  We should never get here since invalid has already
+               // been handled above.
+
+       case reflect.Bool:
+               printBool(f.fs, v.Bool())
+
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               printInt(f.fs, v.Int(), 10)
+
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               printUint(f.fs, v.Uint(), 10)
+
+       case reflect.Float32:
+               printFloat(f.fs, v.Float(), 32)
+
+       case reflect.Float64:
+               printFloat(f.fs, v.Float(), 64)
+
+       case reflect.Complex64:
+               printComplex(f.fs, v.Complex(), 32)
+
+       case reflect.Complex128:
+               printComplex(f.fs, v.Complex(), 64)
+
+       case reflect.Slice:
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+               fallthrough
+
+       case reflect.Array:
+               f.fs.Write(openBracketBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       numEntries := v.Len()
+                       for i := 0; i < numEntries; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.Index(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBracketBytes)
+
+       case reflect.String:
+               f.fs.Write([]byte(v.String()))
+
+       case reflect.Interface:
+               // The only time we should get here is for nil interfaces due to
+               // unpackValue calls.
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+               }
+
+       case reflect.Ptr:
+               // Do nothing.  We should never get here since pointers have already
+               // been handled above.
+
+       case reflect.Map:
+               // nil maps should be indicated as different than empty maps
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+
+               f.fs.Write(openMapBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       keys := v.MapKeys()
+                       if f.cs.SortKeys {
+                               sortValues(keys, f.cs)
+                       }
+                       for i, key := range keys {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(key))
+                               f.fs.Write(colonBytes)
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.MapIndex(key)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeMapBytes)
+
+       case reflect.Struct:
+               numFields := v.NumField()
+               f.fs.Write(openBraceBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       vt := v.Type()
+                       for i := 0; i < numFields; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               vtf := vt.Field(i)
+                               if f.fs.Flag('+') || f.fs.Flag('#') {
+                                       f.fs.Write([]byte(vtf.Name))
+                                       f.fs.Write(colonBytes)
+                               }
+                               f.format(f.unpackValue(v.Field(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBraceBytes)
+
+       case reflect.Uintptr:
+               printHexPtr(f.fs, uintptr(v.Uint()))
+
+       case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+               printHexPtr(f.fs, v.Pointer())
+
+       // There were not any other types at the time this code was written, but
+       // fall back to letting the default fmt package handle it if any get added.
+       default:
+               format := f.buildDefaultFormat()
+               if v.CanInterface() {
+                       fmt.Fprintf(f.fs, format, v.Interface())
+               } else {
+                       fmt.Fprintf(f.fs, format, v.String())
+               }
+       }
+}
+
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
+// details.
+func (f *formatState) Format(fs fmt.State, verb rune) {
+       f.fs = fs
+
+       // Use standard formatting for verbs that are not v.
+       if verb != 'v' {
+               format := f.constructOrigFormat(verb)
+               fmt.Fprintf(fs, format, f.value)
+               return
+       }
+
+       if f.value == nil {
+               if fs.Flag('#') {
+                       fs.Write(interfaceBytes)
+               }
+               fs.Write(nilAngleBytes)
+               return
+       }
+
+       f.format(reflect.ValueOf(f.value))
+}
+
+// newFormatter is a helper function to consolidate the logic from the various
+// public methods which take varying config states.
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
+       fs := &formatState{value: v, cs: cs}
+       fs.pointers = make(map[uintptr]int)
+       return fs
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface.  As a result, it integrates cleanly with standard fmt package
+printing functions.  The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations.  Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting.  In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly.  It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+Printf, Println, or Fprintf.
+*/
+func NewFormatter(v interface{}) fmt.Formatter {
+       return newFormatter(&Config, v)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go
new file mode 100644 (file)
index 0000000..32c0e33
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "fmt"
+       "io"
+)
+
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the formatted string as a value that satisfies error.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Errorf(format string, a ...interface{}) (err error) {
+       return fmt.Errorf(format, convertArgs(a)...)
+}
+
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+       return fmt.Fprint(w, convertArgs(a)...)
+}
+
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+       return fmt.Fprintf(w, format, convertArgs(a)...)
+}
+
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
+// passed with a default Formatter interface returned by NewFormatter.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+       return fmt.Fprintln(w, convertArgs(a)...)
+}
+
+// Print is a wrapper for fmt.Print that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
+func Print(a ...interface{}) (n int, err error) {
+       return fmt.Print(convertArgs(a)...)
+}
+
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Printf(format string, a ...interface{}) (n int, err error) {
+       return fmt.Printf(format, convertArgs(a)...)
+}
+
+// Println is a wrapper for fmt.Println that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the number of bytes written and any write error encountered.  See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
+func Println(a ...interface{}) (n int, err error) {
+       return fmt.Println(convertArgs(a)...)
+}
+
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprint(a ...interface{}) string {
+       return fmt.Sprint(convertArgs(a)...)
+}
+
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter.  It
+// returns the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprintf(format string, a ...interface{}) string {
+       return fmt.Sprintf(format, convertArgs(a)...)
+}
+
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
+// were passed with a default Formatter interface returned by NewFormatter.  It
+// returns the resulting string.  See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+//     fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprintln(a ...interface{}) string {
+       return fmt.Sprintln(convertArgs(a)...)
+}
+
+// convertArgs accepts a slice of arguments and returns a slice of the same
+// length with each argument converted to a default spew Formatter interface.
+func convertArgs(args []interface{}) (formatters []interface{}) {
+       formatters = make([]interface{}, len(args))
+       for index, arg := range args {
+               formatters[index] = NewFormatter(arg)
+       }
+       return formatters
+}
index 052e6f0..fea385c 100644 (file)
@@ -1,7 +1,10 @@
 package gitobj
 
 import (
+       "bufio"
        "io"
+       "os"
+       "path"
 
        "github.com/git-lfs/gitobj/pack"
        "github.com/git-lfs/gitobj/storage"
@@ -15,7 +18,46 @@ func NewFilesystemBackend(root, tmp string) (storage.Backend, error) {
                return nil, err
        }
 
-       return &filesystemBackend{fs: fsobj, packs: packs}, nil
+       storage, err := findAllBackends(fsobj, packs, root)
+       if err != nil {
+               return nil, err
+       }
+
+       return &filesystemBackend{
+               fs:       fsobj,
+               backends: storage,
+       }, nil
+}
+
+func findAllBackends(mainLoose *fileStorer, mainPacked *pack.Storage, root string) ([]storage.Storage, error) {
+       storage := make([]storage.Storage, 2)
+       storage[0] = mainLoose
+       storage[1] = mainPacked
+       f, err := os.Open(path.Join(root, "info", "alternates"))
+       if err != nil {
+               // No alternates file, no problem.
+               if err != os.ErrNotExist {
+                       return storage, nil
+               }
+               return nil, err
+       }
+       defer f.Close()
+
+       scanner := bufio.NewScanner(f)
+       for scanner.Scan() {
+               storage = append(storage, newFileStorer(scanner.Text(), ""))
+               pack, err := pack.NewStorage(scanner.Text())
+               if err != nil {
+                       return nil, err
+               }
+               storage = append(storage, pack)
+       }
+
+       if err := scanner.Err(); err != nil {
+               return nil, err
+       }
+
+       return storage, nil
 }
 
 // NewMemoryBackend initializes a new memory-based backend.
@@ -27,12 +69,12 @@ func NewMemoryBackend(m map[string]io.ReadWriter) (storage.Backend, error) {
 }
 
 type filesystemBackend struct {
-       fs    *fileStorer
-       packs *pack.Storage
+       fs       *fileStorer
+       backends []storage.Storage
 }
 
 func (b *filesystemBackend) Storage() (storage.Storage, storage.WritableStorage) {
-       return storage.MultiStorage(b.fs, b.packs), b.fs
+       return storage.MultiStorage(b.backends...), b.fs
 }
 
 type memoryBackend struct {
index 46dff32..c96b961 100644 (file)
@@ -285,7 +285,7 @@ func (o *ObjectDatabase) open(sha []byte) (*ObjectReader, error) {
        if o.ro.IsCompressed() {
                return NewObjectReadCloser(f)
        }
-       return NewUncompressedObjectReader(f)
+       return NewUncompressedObjectReadCloser(f)
 }
 
 // openDecode calls decode (see: below) on the object named "sha" after openin
diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/pmezard/go-difflib/LICENSE
new file mode 100644 (file)
index 0000000..c67dad6
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Patrick Mezard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+    The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
new file mode 100644 (file)
index 0000000..003e99f
--- /dev/null
@@ -0,0 +1,772 @@
+// Package difflib is a partial port of Python difflib module.
+//
+// It provides tools to compare sequences of strings and generate textual diffs.
+//
+// The following class and functions have been ported:
+//
+// - SequenceMatcher
+//
+// - unified_diff
+//
+// - context_diff
+//
+// Getting unified diffs was the main goal of the port. Keep in mind this code
+// is mostly suitable to output text differences in a human friendly way, there
+// are no guarantees generated diffs are consumable by patch(1).
+package difflib
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "strings"
+)
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func max(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func calculateRatio(matches, length int) float64 {
+       if length > 0 {
+               return 2.0 * float64(matches) / float64(length)
+       }
+       return 1.0
+}
+
+type Match struct {
+       A    int
+       B    int
+       Size int
+}
+
+type OpCode struct {
+       Tag byte
+       I1  int
+       I2  int
+       J1  int
+       J2  int
+}
+
+// SequenceMatcher compares sequence of strings. The basic
+// algorithm predates, and is a little fancier than, an algorithm
+// published in the late 1980's by Ratcliff and Obershelp under the
+// hyperbolic name "gestalt pattern matching".  The basic idea is to find
+// the longest contiguous matching subsequence that contains no "junk"
+// elements (R-O doesn't address junk).  The same idea is then applied
+// recursively to the pieces of the sequences to the left and to the right
+// of the matching subsequence.  This does not yield minimal edit
+// sequences, but does tend to yield matches that "look right" to people.
+//
+// SequenceMatcher tries to compute a "human-friendly diff" between two
+// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+// longest *contiguous* & junk-free matching subsequence.  That's what
+// catches peoples' eyes.  The Windows(tm) windiff has another interesting
+// notion, pairing up elements that appear uniquely in each sequence.
+// That, and the method here, appear to yield more intuitive difference
+// reports than does diff.  This method appears to be the least vulnerable
+// to synching up on blocks of "junk lines", though (like blank lines in
+// ordinary text files, or maybe "<P>" lines in HTML files).  That may be
+// because this is the only method of the 3 that has a *concept* of
+// "junk" <wink>.
+//
+// Timing:  Basic R-O is cubic time worst case and quadratic time expected
+// case.  SequenceMatcher is quadratic time for the worst case and has
+// expected-case behavior dependent in a complicated way on how many
+// elements the sequences have in common; best case time is linear.
+type SequenceMatcher struct {
+       a              []string
+       b              []string
+       b2j            map[string][]int
+       IsJunk         func(string) bool
+       autoJunk       bool
+       bJunk          map[string]struct{}
+       matchingBlocks []Match
+       fullBCount     map[string]int
+       bPopular       map[string]struct{}
+       opCodes        []OpCode
+}
+
+func NewMatcher(a, b []string) *SequenceMatcher {
+       m := SequenceMatcher{autoJunk: true}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+func NewMatcherWithJunk(a, b []string, autoJunk bool,
+       isJunk func(string) bool) *SequenceMatcher {
+
+       m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+// Set two sequences to be compared.
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
+       m.SetSeq1(a)
+       m.SetSeq2(b)
+}
+
+// Set the first sequence to be compared. The second sequence to be compared is
+// not changed.
+//
+// SequenceMatcher computes and caches detailed information about the second
+// sequence, so if you want to compare one sequence S against many sequences,
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
+// sequences.
+//
+// See also SetSeqs() and SetSeq2().
+func (m *SequenceMatcher) SetSeq1(a []string) {
+       if &a == &m.a {
+               return
+       }
+       m.a = a
+       m.matchingBlocks = nil
+       m.opCodes = nil
+}
+
+// Set the second sequence to be compared. The first sequence to be compared is
+// not changed.
+func (m *SequenceMatcher) SetSeq2(b []string) {
+       if &b == &m.b {
+               return
+       }
+       m.b = b
+       m.matchingBlocks = nil
+       m.opCodes = nil
+       m.fullBCount = nil
+       m.chainB()
+}
+
+func (m *SequenceMatcher) chainB() {
+       // Populate line -> index mapping
+       b2j := map[string][]int{}
+       for i, s := range m.b {
+               indices := b2j[s]
+               indices = append(indices, i)
+               b2j[s] = indices
+       }
+
+       // Purge junk elements
+       m.bJunk = map[string]struct{}{}
+       if m.IsJunk != nil {
+               junk := m.bJunk
+               for s, _ := range b2j {
+                       if m.IsJunk(s) {
+                               junk[s] = struct{}{}
+                       }
+               }
+               for s, _ := range junk {
+                       delete(b2j, s)
+               }
+       }
+
+       // Purge remaining popular elements
+       popular := map[string]struct{}{}
+       n := len(m.b)
+       if m.autoJunk && n >= 200 {
+               ntest := n/100 + 1
+               for s, indices := range b2j {
+                       if len(indices) > ntest {
+                               popular[s] = struct{}{}
+                       }
+               }
+               for s, _ := range popular {
+                       delete(b2j, s)
+               }
+       }
+       m.bPopular = popular
+       m.b2j = b2j
+}
+
+func (m *SequenceMatcher) isBJunk(s string) bool {
+       _, ok := m.bJunk[s]
+       return ok
+}
+
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
+//
+// If IsJunk is not defined:
+//
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+//     alo <= i <= i+k <= ahi
+//     blo <= j <= j+k <= bhi
+// and for all (i',j',k') meeting those conditions,
+//     k >= k'
+//     i <= i'
+//     and if i == i', j <= j'
+//
+// In other words, of all maximal matching blocks, return one that
+// starts earliest in a, and of all those maximal matching blocks that
+// start earliest in a, return the one that starts earliest in b.
+//
+// If IsJunk is defined, first the longest matching block is
+// determined as above, but with the additional restriction that no
+// junk element appears in the block.  Then that block is extended as
+// far as possible by matching (only) junk elements on both sides.  So
+// the resulting block never matches on junk except as identical junk
+// happens to be adjacent to an "interesting" match.
+//
+// If no blocks match, return (alo, blo, 0).
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
+       // CAUTION:  stripping common prefix or suffix would be incorrect.
+       // E.g.,
+       //    ab
+       //    acab
+       // Longest matching block is "ab", but if common prefix is
+       // stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
+       // strip, so ends up claiming that ab is changed to acab by
+       // inserting "ca" in the middle.  That's minimal but unintuitive:
+       // "it's obvious" that someone inserted "ac" at the front.
+       // Windiff ends up at the same place as diff, but by pairing up
+       // the unique 'b's and then matching the first two 'a's.
+       besti, bestj, bestsize := alo, blo, 0
+
+       // find longest junk-free match
+       // during an iteration of the loop, j2len[j] = length of longest
+       // junk-free match ending with a[i-1] and b[j]
+       j2len := map[int]int{}
+       for i := alo; i != ahi; i++ {
+               // look at all instances of a[i] in b; note that because
+               // b2j has no junk keys, the loop is skipped if a[i] is junk
+               newj2len := map[int]int{}
+               for _, j := range m.b2j[m.a[i]] {
+                       // a[i] matches b[j]
+                       if j < blo {
+                               continue
+                       }
+                       if j >= bhi {
+                               break
+                       }
+                       k := j2len[j-1] + 1
+                       newj2len[j] = k
+                       if k > bestsize {
+                               besti, bestj, bestsize = i-k+1, j-k+1, k
+                       }
+               }
+               j2len = newj2len
+       }
+
+       // Extend the best by non-junk elements on each end.  In particular,
+       // "popular" non-junk elements aren't in b2j, which greatly speeds
+       // the inner loop above, but also means "the best" match so far
+       // doesn't contain any junk *or* popular non-junk elements.
+       for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               !m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       // Now that we have a wholly interesting match (albeit possibly
+       // empty!), we may as well suck up the matching junk on each
+       // side of it too.  Can't think of a good reason not to, and it
+       // saves post-processing the (possibly considerable) expense of
+       // figuring out what to do with it.  In the case of an empty
+       // interesting match, this is clearly the right thing to do,
+       // because no other kind of match is possible in the regions.
+       for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       return Match{A: besti, B: bestj, Size: bestsize}
+}
+
+// Return list of triples describing matching subsequences.
+//
+// Each triple is of the form (i, j, n), and means that
+// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
+// adjacent triples in the list, and the second is not the last triple in the
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
+// adjacent equal blocks.
+//
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
+// triple with n==0.
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
+       if m.matchingBlocks != nil {
+               return m.matchingBlocks
+       }
+
+       var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
+       matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
+               match := m.findLongestMatch(alo, ahi, blo, bhi)
+               i, j, k := match.A, match.B, match.Size
+               if match.Size > 0 {
+                       if alo < i && blo < j {
+                               matched = matchBlocks(alo, i, blo, j, matched)
+                       }
+                       matched = append(matched, match)
+                       if i+k < ahi && j+k < bhi {
+                               matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
+                       }
+               }
+               return matched
+       }
+       matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
+
+       // It's possible that we have adjacent equal blocks in the
+       // matching_blocks list now.
+       nonAdjacent := []Match{}
+       i1, j1, k1 := 0, 0, 0
+       for _, b := range matched {
+               // Is this block adjacent to i1, j1, k1?
+               i2, j2, k2 := b.A, b.B, b.Size
+               if i1+k1 == i2 && j1+k1 == j2 {
+                       // Yes, so collapse them -- this just increases the length of
+                       // the first block by the length of the second, and the first
+                       // block so lengthened remains the block to compare against.
+                       k1 += k2
+               } else {
+                       // Not adjacent.  Remember the first block (k1==0 means it's
+                       // the dummy we started with), and make the second block the
+                       // new block to compare against.
+                       if k1 > 0 {
+                               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+                       }
+                       i1, j1, k1 = i2, j2, k2
+               }
+       }
+       if k1 > 0 {
+               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+       }
+
+       nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
+       m.matchingBlocks = nonAdjacent
+       return m.matchingBlocks
+}
+
+// Return list of 5-tuples describing how to turn a into b.
+//
+// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+// tuple preceding it, and likewise for j1 == the previous j2.
+//
+// The tags are characters, with these meanings:
+//
+// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]
+//
+// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.
+//
+// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
+//
+// 'e' (equal):    a[i1:i2] == b[j1:j2]
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
+       if m.opCodes != nil {
+               return m.opCodes
+       }
+       i, j := 0, 0
+       matching := m.GetMatchingBlocks()
+       opCodes := make([]OpCode, 0, len(matching))
+       for _, m := range matching {
+               //  invariant:  we've pumped out correct diffs to change
+               //  a[:i] into b[:j], and the next matching block is
+               //  a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+               //  out a diff to change a[i:ai] into b[j:bj], pump out
+               //  the matching block, and move (i,j) beyond the match
+               ai, bj, size := m.A, m.B, m.Size
+               tag := byte(0)
+               if i < ai && j < bj {
+                       tag = 'r'
+               } else if i < ai {
+                       tag = 'd'
+               } else if j < bj {
+                       tag = 'i'
+               }
+               if tag > 0 {
+                       opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
+               }
+               i, j = ai+size, bj+size
+               // the list of matching blocks is terminated by a
+               // sentinel with size 0
+               if size > 0 {
+                       opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
+               }
+       }
+       m.opCodes = opCodes
+       return m.opCodes
+}
+
+// Isolate change clusters by eliminating ranges with no changes.
+//
+// Return a generator of groups with up to n lines of context.
+// Each group is in the same format as returned by GetOpCodes().
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
+       if n < 0 {
+               n = 3
+       }
+       codes := m.GetOpCodes()
+       if len(codes) == 0 {
+               codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+       }
+       // Fixup leading and trailing groups if they show no changes.
+       if codes[0].Tag == 'e' {
+               c := codes[0]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
+       }
+       if codes[len(codes)-1].Tag == 'e' {
+               c := codes[len(codes)-1]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
+       }
+       nn := n + n
+       groups := [][]OpCode{}
+       group := []OpCode{}
+       for _, c := range codes {
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               // End the current group and start a new one whenever
+               // there is a large range with no changes.
+               if c.Tag == 'e' && i2-i1 > nn {
+                       group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
+                               j1, min(j2, j1+n)})
+                       groups = append(groups, group)
+                       group = []OpCode{}
+                       i1, j1 = max(i1, i2-n), max(j1, j2-n)
+               }
+               group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
+       }
+       if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
+               groups = append(groups, group)
+       }
+       return groups
+}
+
+// Return a measure of the sequences' similarity (float in [0,1]).
+//
+// Where T is the total number of elements in both sequences, and
+// M is the number of matches, this is 2.0*M / T.
+// Note that this is 1 if the sequences are identical, and 0 if
+// they have nothing in common.
+//
+// .Ratio() is expensive to compute if you haven't already computed
+// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
+// want to try .QuickRatio() or .RealQuickRation() first to get an
+// upper bound.
+func (m *SequenceMatcher) Ratio() float64 {
+       matches := 0
+       for _, m := range m.GetMatchingBlocks() {
+               matches += m.Size
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() relatively quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute.
+func (m *SequenceMatcher) QuickRatio() float64 {
+       // viewing a and b as multisets, set matches to the cardinality
+       // of their intersection; this counts the number of matches
+       // without regard to order, so is clearly an upper bound
+       if m.fullBCount == nil {
+               m.fullBCount = map[string]int{}
+               for _, s := range m.b {
+                       m.fullBCount[s] = m.fullBCount[s] + 1
+               }
+       }
+
+       // avail[x] is the number of times x appears in 'b' less the
+       // number of times we've seen it in 'a' so far ... kinda
+       avail := map[string]int{}
+       matches := 0
+       for _, s := range m.a {
+               n, ok := avail[s]
+               if !ok {
+                       n = m.fullBCount[s]
+               }
+               avail[s] = n - 1
+               if n > 0 {
+                       matches += 1
+               }
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() very quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute than either .Ratio() or .QuickRatio().
+func (m *SequenceMatcher) RealQuickRatio() float64 {
+       la, lb := len(m.a), len(m.b)
+       return calculateRatio(min(la, lb), la+lb)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+// Unified diff parameters
+type UnifiedDiff struct {
+       A        []string // First sequence lines
+       FromFile string   // First file name
+       FromDate string   // First file time
+       B        []string // Second sequence lines
+       ToFile   string   // Second file name
+       ToDate   string   // Second file time
+       Eol      string   // Headers end of line, defaults to LF
+       Context  int      // Number of context lines
+}
+
+// Compare two sequences of lines; generate the delta as a unified diff.
+//
+// Unified diffs are a compact way of showing line changes and a few
+// lines of context.  The number of context lines is set by 'n' which
+// defaults to three.
+//
+// By default, the diff control lines (those with ---, +++, or @@) are
+// created with a trailing newline.  This is helpful so that inputs
+// created from file.readlines() result in diffs that are suitable for
+// file.writelines() since both the inputs and outputs have trailing
+// newlines.
+//
+// For inputs that do not have trailing newlines, set the lineterm
+// argument to "" so that the output will be uniformly newline free.
+//
+// The unidiff format normally has a header for filenames and modification
+// times.  Any or all of these may be specified using strings for
+// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+// The modification times are normally expressed in the ISO 8601 format.
+func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       wf := func(format string, args ...interface{}) error {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               return err
+       }
+       ws := func(s string) error {
+               _, err := buf.WriteString(s)
+               return err
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       if diff.FromFile != "" || diff.ToFile != "" {
+                               err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                               if err != nil {
+                                       return err
+                               }
+                               err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
+                               if err != nil {
+                                       return err
+                               }
+                       }
+               }
+               first, last := g[0], g[len(g)-1]
+               range1 := formatRangeUnified(first.I1, last.I2)
+               range2 := formatRangeUnified(first.J1, last.J2)
+               if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
+                       return err
+               }
+               for _, c := range g {
+                       i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+                       if c.Tag == 'e' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := ws(" " + line); err != nil {
+                                               return err
+                                       }
+                               }
+                               continue
+                       }
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := ws("-" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, line := range diff.B[j1:j2] {
+                                       if err := ws("+" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+// Like WriteUnifiedDiff but returns the diff a string.
+func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteUnifiedDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Convert range to the "ed" format.
+func formatRangeContext(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       if length <= 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
+}
+
+type ContextDiff UnifiedDiff
+
+// Compare two sequences of lines; generate the delta as a context diff.
+//
+// Context diffs are a compact way of showing line changes and a few
+// lines of context. The number of context lines is set by diff.Context
+// which defaults to three.
+//
+// By default, the diff control lines (those with *** or ---) are
+// created with a trailing newline.
+//
+// For inputs that do not have trailing newlines, set the diff.Eol
+// argument to "" so that the output will be uniformly newline free.
+//
+// The context diff format normally has a header for filenames and
+// modification times.  Any or all of these may be specified using
+// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
+// The modification times are normally expressed in the ISO 8601 format.
+// If not specified, the strings default to blanks.
+func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       var diffErr error
+       wf := func(format string, args ...interface{}) {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               if diffErr == nil && err != nil {
+                       diffErr = err
+               }
+       }
+       ws := func(s string) {
+               _, err := buf.WriteString(s)
+               if diffErr == nil && err != nil {
+                       diffErr = err
+               }
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       prefix := map[byte]string{
+               'i': "+ ",
+               'd': "- ",
+               'r': "! ",
+               'e': "  ",
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       if diff.FromFile != "" || diff.ToFile != "" {
+                               wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                               wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
+                       }
+               }
+
+               first, last := g[0], g[len(g)-1]
+               ws("***************" + diff.Eol)
+
+               range1 := formatRangeContext(first.I1, last.I2)
+               wf("*** %s ****%s", range1, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'i' {
+                                               continue
+                                       }
+                                       for _, line := range diff.A[cc.I1:cc.I2] {
+                                               ws(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+
+               range2 := formatRangeContext(first.J1, last.J2)
+               wf("--- %s ----%s", range2, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'd' {
+                                               continue
+                                       }
+                                       for _, line := range diff.B[cc.J1:cc.J2] {
+                                               ws(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+       }
+       return diffErr
+}
+
+// Like WriteContextDiff but returns the diff a string.
+func GetContextDiffString(diff ContextDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteContextDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Split a string on "\n" while preserving them. The output can be used
+// as input for UnifiedDiff and ContextDiff structures.
+func SplitLines(s string) []string {
+       lines := strings.SplitAfter(s, "\n")
+       lines[len(lines)-1] += "\n"
+       return lines
+}
index 1119d6e..ba69d6d 100644 (file)
@@ -6,7 +6,7 @@ github.com/alexbrainman/sspi
 github.com/alexbrainman/sspi/ntlm
 # github.com/davecgh/go-spew v1.1.1
 github.com/davecgh/go-spew/spew
-# github.com/git-lfs/gitobj v1.0.0
+# github.com/git-lfs/gitobj v1.1.0
 github.com/git-lfs/gitobj
 github.com/git-lfs/gitobj/errors
 github.com/git-lfs/gitobj/pack
index 968814b..333408d 100644 (file)
@@ -4,7 +4,7 @@
                "FileVersion": {
                        "Major": 2,
                        "Minor": 6,
-                       "Patch": 0,
+                       "Patch": 1,
                        "Build": 0
                }
        },
@@ -13,7 +13,7 @@
                "FileDescription": "Git LFS",
                "LegalCopyright": "GitHub, Inc. and Git LFS contributors",
                "ProductName": "Git Large File Storage (LFS)",
-               "ProductVersion": "2.6.0"
+               "ProductVersion": "2.6.1"
        },
        "IconPath": "script/windows-installer/git-lfs-logo.ico"
 }