diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 5d7c337bed..38f88f9180 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -5,6 +5,7 @@ "Packages": [ "github.com/onsi/ginkgo/ginkgo", "github.com/jteeuwen/go-bindata/go-bindata", + "github.com/tools/godep", "./..." ], "Deps": [ @@ -1922,11 +1923,20 @@ "ImportPath": "github.com/kr/fs", "Rev": "2788f0dbd16903de03cb8186e5c7d97b69ad387b" }, + { + "ImportPath": "github.com/kr/pretty", + "Comment": "go.weekly.2011-12-22-24-gf31442d", + "Rev": "f31442d60e51465c69811e2107ae978868dbea5c" + }, { "ImportPath": "github.com/kr/pty", "Comment": "release.r56-29-gf7ee69f", "Rev": "f7ee69f31298ecbe5d2b349c711e2547a617d398" }, + { + "ImportPath": "github.com/kr/text", + "Rev": "6807e777504f54ad073ecef66747de158294b639" + }, { "ImportPath": "github.com/libopenstorage/openstorage/api", "Rev": "093a0c3888753c2056e7373183693d670c6bba01" @@ -2519,6 +2529,11 @@ "ImportPath": "github.com/syndtr/gocapability/capability", "Rev": "e7cb7fa329f456b3855136a2642b197bad7366ba" }, + { + "ImportPath": "github.com/tools/godep", + "Comment": "v79", + "Rev": "f15f6db5da33a4ac48be83e20b9dd838e14f117b" + }, { "ImportPath": "github.com/ugorji/go/codec", "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" @@ -2859,6 +2874,10 @@ "ImportPath": "golang.org/x/tools/container/intsets", "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" }, + { + "ImportPath": "golang.org/x/tools/go/vcs", + "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" + }, { "ImportPath": "google.golang.org/api/cloudkms/v1", "Rev": "654f863362977d69086620b5f72f13e911da2410" diff --git a/Godeps/LICENSES b/Godeps/LICENSES index 02d988bd3c..b92844bfd3 100644 --- a/Godeps/LICENSES +++ b/Godeps/LICENSES @@ -66824,6 +66824,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/github.com/kr/pretty licensed under: = + +The MIT License (MIT) + +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + += vendor/github.com/kr/pretty/License 9d305c2010c6891ee4f3cd42a562f78f +================================================================================ + + ================================================================================ = vendor/github.com/kr/pty licensed under: = @@ -66855,6 +66884,33 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ +================================================================================ += vendor/github.com/kr/text licensed under: = + +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + += vendor/github.com/kr/text/License 449bfedd81a372635934cf9ce004c0cf +================================================================================ + + ================================================================================ = vendor/github.com/libopenstorage/openstorage/api licensed under: = @@ -79402,6 +79458,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/github.com/tools/godep licensed under: = + +Copyright © 2013 Keith Rarick. +Portions Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + += vendor/github.com/tools/godep/License 71eb66e9b353dd06ca5a81ce0f469e1a +================================================================================ + + ================================================================================ = vendor/github.com/ugorji/go/codec licensed under: = @@ -86286,6 +86378,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/golang.org/x/tools/go/vcs licensed under: = + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + += vendor/golang.org/x/tools/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707 +================================================================================ + + ================================================================================ = vendor/google.golang.org/api/cloudkms/v1 licensed under: = diff --git a/hack/godep-save.sh b/hack/godep-save.sh index 4835b86974..7d154404ed 100755 --- a/hack/godep-save.sh +++ b/hack/godep-save.sh @@ -58,6 +58,7 @@ fi REQUIRED_BINS=( "github.com/onsi/ginkgo/ginkgo" "github.com/jteeuwen/go-bindata/go-bindata" + "github.com/tools/godep" "./..." ) diff --git a/hack/lib/util.sh b/hack/lib/util.sh index c9db31a229..4ddc7bbf99 100755 --- a/hack/lib/util.sh +++ b/hack/lib/util.sh @@ -521,20 +521,9 @@ kube::util::ensure_godep_version() { return fi - kube::log::status "Getting godep version ${GODEP_VERSION}" - kube::util::ensure-temp-dir - mkdir -p "${KUBE_TEMP}/go/src" + kube::log::status "Installing godep version ${GODEP_VERSION}" + go install ./vendor/github.com/tools/godep/ - GP="$(echo $GOPATH | cut -f1 -d:)" - rm -rf "${GP}/src/github.com/tools/godep" - go get -d -u github.com/tools/godep - pushd "${GP}/src/github.com/tools/godep" >/dev/null - git checkout -q "${GODEP_VERSION}" - go install . - popd >/dev/null - - hash -r # force bash to clear PATH cache - PATH="${PATH}:${GP}/bin" if [[ "$(godep version 2>/dev/null)" != *"godep ${GODEP_VERSION}"* ]]; then kube::log::error "Expected godep ${GODEP_VERSION}, got $(godep version)" return 1 diff --git a/vendor/BUILD b/vendor/BUILD index 25be206bf2..49b36c03af 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -258,7 +258,9 @@ filegroup( "//vendor/github.com/kardianos/osext:all-srcs", "//vendor/github.com/karlseguin/ccache:all-srcs", "//vendor/github.com/kr/fs:all-srcs", + "//vendor/github.com/kr/pretty:all-srcs", "//vendor/github.com/kr/pty:all-srcs", + "//vendor/github.com/kr/text:all-srcs", "//vendor/github.com/libopenstorage/openstorage/api:all-srcs", "//vendor/github.com/libopenstorage/openstorage/pkg/parser:all-srcs", "//vendor/github.com/libopenstorage/openstorage/pkg/units:all-srcs", @@ -323,6 +325,7 @@ filegroup( "//vendor/github.com/stretchr/testify/mock:all-srcs", "//vendor/github.com/stretchr/testify/require:all-srcs", "//vendor/github.com/syndtr/gocapability/capability:all-srcs", + "//vendor/github.com/tools/godep:all-srcs", "//vendor/github.com/ugorji/go/codec:all-srcs", "//vendor/github.com/vishvananda/netlink:all-srcs", "//vendor/github.com/vishvananda/netns:all-srcs", @@ -368,6 +371,7 @@ filegroup( "//vendor/golang.org/x/text/width:all-srcs", "//vendor/golang.org/x/time/rate:all-srcs", "//vendor/golang.org/x/tools/container/intsets:all-srcs", + "//vendor/golang.org/x/tools/go/vcs:all-srcs", "//vendor/google.golang.org/api/cloudkms/v1:all-srcs", "//vendor/google.golang.org/api/cloudmonitoring/v2beta2:all-srcs", "//vendor/google.golang.org/api/compute/v0.alpha:all-srcs", diff --git a/vendor/github.com/kr/pretty/.gitignore b/vendor/github.com/kr/pretty/.gitignore new file mode 100644 index 0000000000..1f0a99f2f2 --- /dev/null +++ b/vendor/github.com/kr/pretty/.gitignore @@ -0,0 +1,4 @@ +[568].out +_go* +_test* +_obj diff --git a/vendor/github.com/kr/pretty/BUILD b/vendor/github.com/kr/pretty/BUILD new file mode 100644 index 0000000000..fc56a2293c --- /dev/null +++ b/vendor/github.com/kr/pretty/BUILD @@ -0,0 +1,27 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "diff.go", + "formatter.go", + "pretty.go", + "zero.go", + ], + visibility = ["//visibility:public"], + deps = ["//vendor/github.com/kr/text:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/kr/pretty/License b/vendor/github.com/kr/pretty/License new file mode 100644 index 0000000000..05c783ccf6 --- /dev/null +++ b/vendor/github.com/kr/pretty/License @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/kr/pretty/Readme b/vendor/github.com/kr/pretty/Readme new file mode 100644 index 0000000000..c589fc622b --- /dev/null +++ b/vendor/github.com/kr/pretty/Readme @@ -0,0 +1,9 @@ +package pretty + + import "github.com/kr/pretty" + + Package pretty provides pretty-printing for Go values. + +Documentation + + http://godoc.org/github.com/kr/pretty diff --git a/vendor/github.com/kr/pretty/diff.go b/vendor/github.com/kr/pretty/diff.go new file mode 100644 index 0000000000..8fe8e2405a --- /dev/null +++ b/vendor/github.com/kr/pretty/diff.go @@ -0,0 +1,158 @@ +package pretty + +import ( + "fmt" + "io" + "reflect" +) + +type sbuf []string + +func (s *sbuf) Write(b []byte) (int, error) { + *s = append(*s, string(b)) + return len(b), nil +} + +// Diff returns a slice where each element describes +// a difference between a and b. +func Diff(a, b interface{}) (desc []string) { + Fdiff((*sbuf)(&desc), a, b) + return desc +} + +// Fdiff writes to w a description of the differences between a and b. +func Fdiff(w io.Writer, a, b interface{}) { + diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b)) +} + +type diffWriter struct { + w io.Writer + l string // label +} + +func (w diffWriter) printf(f string, a ...interface{}) { + var l string + if w.l != "" { + l = w.l + ": " + } + fmt.Fprintf(w.w, l+f, a...) +} + +func (w diffWriter) diff(av, bv reflect.Value) { + if !av.IsValid() && bv.IsValid() { + w.printf("nil != %#v", bv.Interface()) + return + } + if av.IsValid() && !bv.IsValid() { + w.printf("%#v != nil", av.Interface()) + return + } + if !av.IsValid() && !bv.IsValid() { + return + } + + at := av.Type() + bt := bv.Type() + if at != bt { + w.printf("%v != %v", at, bt) + return + } + + // numeric types, including bool + if at.Kind() < reflect.Array { + a, b := av.Interface(), bv.Interface() + if a != b { + w.printf("%#v != %#v", a, b) + } + return + } + + switch at.Kind() { + case reflect.String: + a, b := av.Interface(), bv.Interface() + if a != b { + w.printf("%q != %q", a, b) + } + case reflect.Ptr: + switch { + case av.IsNil() && !bv.IsNil(): + w.printf("nil != %v", bv.Interface()) + case !av.IsNil() && bv.IsNil(): + w.printf("%v != nil", av.Interface()) + case !av.IsNil() && !bv.IsNil(): + w.diff(av.Elem(), bv.Elem()) + } + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i)) + } + case reflect.Slice: + lenA := av.Len() + lenB := bv.Len() + if lenA != lenB { + w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) + break + } + for i := 0; i < lenA; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.Map: + ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys()) + for _, k := range ak { + w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) + w.printf("%q != (missing)", av.MapIndex(k)) + } + for _, k := range both { + w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) + w.diff(av.MapIndex(k), bv.MapIndex(k)) + } + for _, k := range bk { + w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) + w.printf("(missing) != %q", bv.MapIndex(k)) + } + case reflect.Interface: + w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface())) + default: + if !reflect.DeepEqual(av.Interface(), bv.Interface()) { + w.printf("%# v != %# v", Formatter(av.Interface()), Formatter(bv.Interface())) + } + } +} + +func (d diffWriter) relabel(name string) (d1 diffWriter) { + d1 = d + if d.l != "" && name[0] != '[' { + d1.l += "." + } + d1.l += name + return d1 +} + +func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) { + for _, av := range a { + inBoth := false + for _, bv := range b { + if reflect.DeepEqual(av.Interface(), bv.Interface()) { + inBoth = true + both = append(both, av) + break + } + } + if !inBoth { + ak = append(ak, av) + } + } + for _, bv := range b { + inBoth := false + for _, av := range a { + if reflect.DeepEqual(av.Interface(), bv.Interface()) { + inBoth = true + break + } + } + if !inBoth { + bk = append(bk, bv) + } + } + return +} diff --git a/vendor/github.com/kr/pretty/formatter.go b/vendor/github.com/kr/pretty/formatter.go new file mode 100644 index 0000000000..8dacda25fa --- /dev/null +++ b/vendor/github.com/kr/pretty/formatter.go @@ -0,0 +1,337 @@ +package pretty + +import ( + "fmt" + "io" + "reflect" + "strconv" + "text/tabwriter" + + "github.com/kr/text" +) + +const ( + limit = 50 +) + +type formatter struct { + x interface{} + force bool + quote bool +} + +// Formatter makes a wrapper, f, that will format x as go source with line +// breaks and tabs. Object f responds to the "%v" formatting verb when both the +// "#" and " " (space) flags are set, for example: +// +// fmt.Sprintf("%# v", Formatter(x)) +// +// If one of these two flags is not set, or any other verb is used, f will +// format x according to the usual rules of package fmt. +// In particular, if x satisfies fmt.Formatter, then x.Format will be called. +func Formatter(x interface{}) (f fmt.Formatter) { + return formatter{x: x, quote: true} +} + +func (fo formatter) String() string { + return fmt.Sprint(fo.x) // unwrap it +} + +func (fo formatter) passThrough(f fmt.State, c rune) { + s := "%" + for i := 0; i < 128; i++ { + if f.Flag(i) { + s += string(i) + } + } + if w, ok := f.Width(); ok { + s += fmt.Sprintf("%d", w) + } + if p, ok := f.Precision(); ok { + s += fmt.Sprintf(".%d", p) + } + s += string(c) + fmt.Fprintf(f, s, fo.x) +} + +func (fo formatter) Format(f fmt.State, c rune) { + if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') { + w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0) + p := &printer{tw: w, Writer: w, visited: make(map[visit]int)} + p.printValue(reflect.ValueOf(fo.x), true, fo.quote) + w.Flush() + return + } + fo.passThrough(f, c) +} + +type printer struct { + io.Writer + tw *tabwriter.Writer + visited map[visit]int + depth int +} + +func (p *printer) indent() *printer { + q := *p + q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0) + q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'}) + return &q +} + +func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) { + if showType { + io.WriteString(p, v.Type().String()) + fmt.Fprintf(p, "(%#v)", x) + } else { + fmt.Fprintf(p, "%#v", x) + } +} + +// printValue must keep track of already-printed pointer values to avoid +// infinite recursion. +type visit struct { + v uintptr + typ reflect.Type +} + +func (p *printer) printValue(v reflect.Value, showType, quote bool) { + if p.depth > 10 { + io.WriteString(p, "!%v(DEPTH EXCEEDED)") + return + } + + switch v.Kind() { + case reflect.Bool: + p.printInline(v, v.Bool(), showType) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p.printInline(v, v.Int(), showType) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p.printInline(v, v.Uint(), showType) + case reflect.Float32, reflect.Float64: + p.printInline(v, v.Float(), showType) + case reflect.Complex64, reflect.Complex128: + fmt.Fprintf(p, "%#v", v.Complex()) + case reflect.String: + p.fmtString(v.String(), quote) + case reflect.Map: + t := v.Type() + if showType { + io.WriteString(p, t.String()) + } + writeByte(p, '{') + if nonzero(v) { + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + keys := v.MapKeys() + for i := 0; i < v.Len(); i++ { + showTypeInStruct := true + k := keys[i] + mv := v.MapIndex(k) + pp.printValue(k, false, true) + writeByte(pp, ':') + if expand { + writeByte(pp, '\t') + } + showTypeInStruct = t.Elem().Kind() == reflect.Interface + pp.printValue(mv, showTypeInStruct, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.Len()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + } + writeByte(p, '}') + case reflect.Struct: + t := v.Type() + if v.CanAddr() { + addr := v.UnsafeAddr() + vis := visit{addr, t} + if vd, ok := p.visited[vis]; ok && vd < p.depth { + p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false) + break // don't print v again + } + p.visited[vis] = p.depth + } + + if showType { + io.WriteString(p, t.String()) + } + writeByte(p, '{') + if nonzero(v) { + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + for i := 0; i < v.NumField(); i++ { + showTypeInStruct := true + if f := t.Field(i); f.Name != "" { + io.WriteString(pp, f.Name) + writeByte(pp, ':') + if expand { + writeByte(pp, '\t') + } + showTypeInStruct = labelType(f.Type) + } + pp.printValue(getField(v, i), showTypeInStruct, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.NumField()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + } + writeByte(p, '}') + case reflect.Interface: + switch e := v.Elem(); { + case e.Kind() == reflect.Invalid: + io.WriteString(p, "nil") + case e.IsValid(): + pp := *p + pp.depth++ + pp.printValue(e, showType, true) + default: + io.WriteString(p, v.Type().String()) + io.WriteString(p, "(nil)") + } + case reflect.Array, reflect.Slice: + t := v.Type() + if showType { + io.WriteString(p, t.String()) + } + if v.Kind() == reflect.Slice && v.IsNil() && showType { + io.WriteString(p, "(nil)") + break + } + if v.Kind() == reflect.Slice && v.IsNil() { + io.WriteString(p, "nil") + break + } + writeByte(p, '{') + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + for i := 0; i < v.Len(); i++ { + showTypeInSlice := t.Elem().Kind() == reflect.Interface + pp.printValue(v.Index(i), showTypeInSlice, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.Len()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + writeByte(p, '}') + case reflect.Ptr: + e := v.Elem() + if !e.IsValid() { + writeByte(p, '(') + io.WriteString(p, v.Type().String()) + io.WriteString(p, ")(nil)") + } else { + pp := *p + pp.depth++ + writeByte(pp, '&') + pp.printValue(e, true, true) + } + case reflect.Chan: + x := v.Pointer() + if showType { + writeByte(p, '(') + io.WriteString(p, v.Type().String()) + fmt.Fprintf(p, ")(%#v)", x) + } else { + fmt.Fprintf(p, "%#v", x) + } + case reflect.Func: + io.WriteString(p, v.Type().String()) + io.WriteString(p, " {...}") + case reflect.UnsafePointer: + p.printInline(v, v.Pointer(), showType) + case reflect.Invalid: + io.WriteString(p, "nil") + } +} + +func canInline(t reflect.Type) bool { + switch t.Kind() { + case reflect.Map: + return !canExpand(t.Elem()) + case reflect.Struct: + for i := 0; i < t.NumField(); i++ { + if canExpand(t.Field(i).Type) { + return false + } + } + return true + case reflect.Interface: + return false + case reflect.Array, reflect.Slice: + return !canExpand(t.Elem()) + case reflect.Ptr: + return false + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + return false + } + return true +} + +func canExpand(t reflect.Type) bool { + switch t.Kind() { + case reflect.Map, reflect.Struct, + reflect.Interface, reflect.Array, reflect.Slice, + reflect.Ptr: + return true + } + return false +} + +func labelType(t reflect.Type) bool { + switch t.Kind() { + case reflect.Interface, reflect.Struct: + return true + } + return false +} + +func (p *printer) fmtString(s string, quote bool) { + if quote { + s = strconv.Quote(s) + } + io.WriteString(p, s) +} + +func tryDeepEqual(a, b interface{}) bool { + defer func() { recover() }() + return reflect.DeepEqual(a, b) +} + +func writeByte(w io.Writer, b byte) { + w.Write([]byte{b}) +} + +func getField(v reflect.Value, i int) reflect.Value { + val := v.Field(i) + if val.Kind() == reflect.Interface && !val.IsNil() { + val = val.Elem() + } + return val +} diff --git a/vendor/github.com/kr/pretty/pretty.go b/vendor/github.com/kr/pretty/pretty.go new file mode 100644 index 0000000000..d3df8686ce --- /dev/null +++ b/vendor/github.com/kr/pretty/pretty.go @@ -0,0 +1,98 @@ +// Package pretty provides pretty-printing for Go values. This is +// useful during debugging, to avoid wrapping long output lines in +// the terminal. +// +// It provides a function, Formatter, that can be used with any +// function that accepts a format string. It also provides +// convenience wrappers for functions in packages fmt and log. +package pretty + +import ( + "fmt" + "io" + "log" +) + +// Errorf is a convenience wrapper for fmt.Errorf. +// +// Calling Errorf(f, x, y) is equivalent to +// fmt.Errorf(f, Formatter(x), Formatter(y)). +func Errorf(format string, a ...interface{}) error { + return fmt.Errorf(format, wrap(a, false)...) +} + +// Fprintf is a convenience wrapper for fmt.Fprintf. +// +// Calling Fprintf(w, f, x, y) is equivalent to +// fmt.Fprintf(w, f, Formatter(x), Formatter(y)). +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) { + return fmt.Fprintf(w, format, wrap(a, false)...) +} + +// Log is a convenience wrapper for log.Printf. +// +// Calling Log(x, y) is equivalent to +// log.Print(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Log(a ...interface{}) { + log.Print(wrap(a, true)...) +} + +// Logf is a convenience wrapper for log.Printf. +// +// Calling Logf(f, x, y) is equivalent to +// log.Printf(f, Formatter(x), Formatter(y)). +func Logf(format string, a ...interface{}) { + log.Printf(format, wrap(a, false)...) +} + +// Logln is a convenience wrapper for log.Printf. +// +// Calling Logln(x, y) is equivalent to +// log.Println(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Logln(a ...interface{}) { + log.Println(wrap(a, true)...) +} + +// Print pretty-prints its operands and writes to standard output. +// +// Calling Print(x, y) is equivalent to +// fmt.Print(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Print(a ...interface{}) (n int, errno error) { + return fmt.Print(wrap(a, true)...) +} + +// Printf is a convenience wrapper for fmt.Printf. +// +// Calling Printf(f, x, y) is equivalent to +// fmt.Printf(f, Formatter(x), Formatter(y)). +func Printf(format string, a ...interface{}) (n int, errno error) { + return fmt.Printf(format, wrap(a, false)...) +} + +// Println pretty-prints its operands and writes to standard output. +// +// Calling Print(x, y) is equivalent to +// fmt.Println(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Println(a ...interface{}) (n int, errno error) { + return fmt.Println(wrap(a, true)...) +} + +// Sprintf is a convenience wrapper for fmt.Sprintf. +// +// Calling Sprintf(f, x, y) is equivalent to +// fmt.Sprintf(f, Formatter(x), Formatter(y)). +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, wrap(a, false)...) +} + +func wrap(a []interface{}, force bool) []interface{} { + w := make([]interface{}, len(a)) + for i, x := range a { + w[i] = formatter{x: x, force: force} + } + return w +} diff --git a/vendor/github.com/kr/pretty/zero.go b/vendor/github.com/kr/pretty/zero.go new file mode 100644 index 0000000000..abb5b6fc14 --- /dev/null +++ b/vendor/github.com/kr/pretty/zero.go @@ -0,0 +1,41 @@ +package pretty + +import ( + "reflect" +) + +func nonzero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() != 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() != 0 + case reflect.Float32, reflect.Float64: + return v.Float() != 0 + case reflect.Complex64, reflect.Complex128: + return v.Complex() != complex(0, 0) + case reflect.String: + return v.String() != "" + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if nonzero(getField(v, i)) { + return true + } + } + return false + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if nonzero(v.Index(i)) { + return true + } + } + return false + case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func: + return !v.IsNil() + case reflect.UnsafePointer: + return v.Pointer() != 0 + } + return true +} diff --git a/vendor/github.com/kr/text/BUILD b/vendor/github.com/kr/text/BUILD new file mode 100644 index 0000000000..d7791bc099 --- /dev/null +++ b/vendor/github.com/kr/text/BUILD @@ -0,0 +1,25 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "indent.go", + "wrap.go", + ], + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/kr/text/License b/vendor/github.com/kr/text/License new file mode 100644 index 0000000000..480a328059 --- /dev/null +++ b/vendor/github.com/kr/text/License @@ -0,0 +1,19 @@ +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/kr/text/Readme b/vendor/github.com/kr/text/Readme new file mode 100644 index 0000000000..7e6e7c0687 --- /dev/null +++ b/vendor/github.com/kr/text/Readme @@ -0,0 +1,3 @@ +This is a Go package for manipulating paragraphs of text. + +See http://go.pkgdoc.org/github.com/kr/text for full documentation. diff --git a/vendor/github.com/kr/text/doc.go b/vendor/github.com/kr/text/doc.go new file mode 100644 index 0000000000..cf4c198f95 --- /dev/null +++ b/vendor/github.com/kr/text/doc.go @@ -0,0 +1,3 @@ +// Package text provides rudimentary functions for manipulating text in +// paragraphs. +package text diff --git a/vendor/github.com/kr/text/indent.go b/vendor/github.com/kr/text/indent.go new file mode 100644 index 0000000000..4ebac45c09 --- /dev/null +++ b/vendor/github.com/kr/text/indent.go @@ -0,0 +1,74 @@ +package text + +import ( + "io" +) + +// Indent inserts prefix at the beginning of each non-empty line of s. The +// end-of-line marker is NL. +func Indent(s, prefix string) string { + return string(IndentBytes([]byte(s), []byte(prefix))) +} + +// IndentBytes inserts prefix at the beginning of each non-empty line of b. +// The end-of-line marker is NL. +func IndentBytes(b, prefix []byte) []byte { + var res []byte + bol := true + for _, c := range b { + if bol && c != '\n' { + res = append(res, prefix...) + } + res = append(res, c) + bol = c == '\n' + } + return res +} + +// Writer indents each line of its input. +type indentWriter struct { + w io.Writer + bol bool + pre [][]byte + sel int + off int +} + +// NewIndentWriter makes a new write filter that indents the input +// lines. Each line is prefixed in order with the corresponding +// element of pre. If there are more lines than elements, the last +// element of pre is repeated for each subsequent line. +func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer { + return &indentWriter{ + w: w, + pre: pre, + bol: true, + } +} + +// The only errors returned are from the underlying indentWriter. +func (w *indentWriter) Write(p []byte) (n int, err error) { + for _, c := range p { + if w.bol { + var i int + i, err = w.w.Write(w.pre[w.sel][w.off:]) + w.off += i + if err != nil { + return n, err + } + } + _, err = w.w.Write([]byte{c}) + if err != nil { + return n, err + } + n++ + w.bol = c == '\n' + if w.bol { + w.off = 0 + if w.sel < len(w.pre)-1 { + w.sel++ + } + } + } + return n, nil +} diff --git a/vendor/github.com/kr/text/wrap.go b/vendor/github.com/kr/text/wrap.go new file mode 100755 index 0000000000..ca8856515c --- /dev/null +++ b/vendor/github.com/kr/text/wrap.go @@ -0,0 +1,86 @@ +package text + +import ( + "bytes" + "math" +) + +var ( + nl = []byte{'\n'} + sp = []byte{' '} +) + +const defaultPenalty = 1e5 + +// Wrap wraps s into a paragraph of lines of length lim, with minimal +// raggedness. +func Wrap(s string, lim int) string { + return string(WrapBytes([]byte(s), lim)) +} + +// WrapBytes wraps b into a paragraph of lines of length lim, with minimal +// raggedness. +func WrapBytes(b []byte, lim int) []byte { + words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp) + var lines [][]byte + for _, line := range WrapWords(words, 1, lim, defaultPenalty) { + lines = append(lines, bytes.Join(line, sp)) + } + return bytes.Join(lines, nl) +} + +// WrapWords is the low-level line-breaking algorithm, useful if you need more +// control over the details of the text wrapping process. For most uses, either +// Wrap or WrapBytes will be sufficient and more convenient. +// +// WrapWords splits a list of words into lines with minimal "raggedness", +// treating each byte as one unit, accounting for spc units between adjacent +// words on each line, and attempting to limit lines to lim units. Raggedness +// is the total error over all lines, where error is the square of the +// difference of the length of the line and lim. Too-long lines (which only +// happen when a single word is longer than lim units) have pen penalty units +// added to the error. +func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte { + n := len(words) + + length := make([][]int, n) + for i := 0; i < n; i++ { + length[i] = make([]int, n) + length[i][i] = len(words[i]) + for j := i + 1; j < n; j++ { + length[i][j] = length[i][j-1] + spc + len(words[j]) + } + } + + nbrk := make([]int, n) + cost := make([]int, n) + for i := range cost { + cost[i] = math.MaxInt32 + } + for i := n - 1; i >= 0; i-- { + if length[i][n-1] <= lim { + cost[i] = 0 + nbrk[i] = n + } else { + for j := i + 1; j < n; j++ { + d := lim - length[i][j-1] + c := d*d + cost[j] + if length[i][j-1] > lim { + c += pen // too-long lines get a worse penalty + } + if c < cost[i] { + cost[i] = c + nbrk[i] = j + } + } + } + } + + var lines [][][]byte + i := 0 + for i < n { + lines = append(lines, words[i:nbrk[i]]) + i = nbrk[i] + } + return lines +} diff --git a/vendor/github.com/tools/godep/.gitignore b/vendor/github.com/tools/godep/.gitignore new file mode 100644 index 0000000000..6d5fec891c --- /dev/null +++ b/vendor/github.com/tools/godep/.gitignore @@ -0,0 +1 @@ +/godep diff --git a/vendor/github.com/tools/godep/.travis.yml b/vendor/github.com/tools/godep/.travis.yml new file mode 100644 index 0000000000..277ec2d81e --- /dev/null +++ b/vendor/github.com/tools/godep/.travis.yml @@ -0,0 +1,34 @@ +language: go +sudo: false +go: 1.6 +script: + # Godep's unit tests run git, and git complains + # if we don't set these config parameters. + # We put dummy values here because they don't matter. +- git config --global user.email "you@example.com" +- git config --global user.name "Your Name" +- test -z "$(go fmt)" +- go vet +- go test -v +- go test -v -race +- test -z "$(goimports -l .)" +before_install: +- go get golang.org/x/tools/cmd/goimports +before_deploy: +- export OS_TARGETS="linux darwin windows" +- export ARCH_TARGETS="386 amd64" +- go get github.com/mitchellh/gox +- gox -os "$OS_TARGETS" -arch="$ARCH_TARGETS" +deploy: + skip_cleanup: true + provider: releases + api_key: + secure: Q1JP8LziaXMTxFmNXiyC1YhS9e4M4WnI6UDjRTMf6mm1LZeJyUFOCCtXnifL7RyCIR1hpjp6s8M1aWE+NpuweF96IZI3Uk4ASx5C8FePC4qvhsCdtJ2sLD2GTIrp9b0MS9/+ao20AIbpVDSaLaF9IjqXpMxMyM0P8P5coRTkwItlGxmQbVJW3YuiYcPa8UojwM4EyafO2CIoUKapW8lwb9KcimBJV8PfF/XZjPVhMkn2ABhh5Hqbn2zBJtvPYMMzi0CnY50JQF5LwN3vGTMpTsRP+lOLCNbOWfkl+2hgG7VpKrtx+cX62knOodpF457sIJ31KUzmeLUVBejTGb1zuVeTojuyi8Huo8YBIBCcN+p3Dqd+n2ZK45mIrheGiEJIkf/vI4MI6A01Nu/o+xU0IPsVfAL/xU5j5nntEGfFWVoclPrl9qcfqf74xdRcARzcCJVmdc8iw49DBDHJfnPa3zxzVz//00+Rz6mZXmhk+Npk/HLLNW59vmJIjP+8XOtPor7dST9HrS1a9AcnmIjNuw9yfbwK5769SDVxCKgqNwXW/Dy5F39aIH5AL4I4y9hCEeeT8ctvSJHGOyiB9MWU5jnt5tluPtz5opG51tFXnIYP/XaWpTfO+eJ6x55pbwT+n3LfRS5l1POM+jGAFF1MFWwc14RY7qynEIEzm4Wb/UE= + file: + - godep_darwin_amd64 + - godep_linux_amd64 + - godep_windows_386.exe + - godep_windows_amd64.exe + on: + tags: true + repo: tools/godep diff --git a/vendor/github.com/tools/godep/BUILD b/vendor/github.com/tools/godep/BUILD new file mode 100644 index 0000000000..9faf3ec28f --- /dev/null +++ b/vendor/github.com/tools/godep/BUILD @@ -0,0 +1,54 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "dep.go", + "diff.go", + "doc.go", + "errors.go", + "get.go", + "go.go", + "godepfile.go", + "license.go", + "list.go", + "main.go", + "msg.go", + "path.go", + "pkg.go", + "restore.go", + "rewrite.go", + "save.go", + "update.go", + "util.go", + "vcs.go", + "version.go", + ], + visibility = ["//visibility:private"], + deps = [ + "//vendor/github.com/kr/fs:go_default_library", + "//vendor/github.com/kr/pretty:go_default_library", + "//vendor/github.com/pmezard/go-difflib/difflib:go_default_library", + "//vendor/golang.org/x/tools/go/vcs:go_default_library", + ], +) + +go_binary( + name = "godep", + library = ":go_default_library", + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/tools/godep/Changelog.md b/vendor/github.com/tools/godep/Changelog.md new file mode 100644 index 0000000000..b383379a5f --- /dev/null +++ b/vendor/github.com/tools/godep/Changelog.md @@ -0,0 +1,408 @@ +#v79 (2017/02/01) + +* Fixes #531: fullPackageInDir didn't capture the error from fillPackage() + +#v78 (2017/01/19) + +* Don't use build.ImportDir when discovering packages for the package spec. Fixes #529 + +#v77 (2017/01/13) + +* Don't include quotes around hg revisions + +#v76 (2017/01/10) + +* Default to vendor being on unless older go versions. + +#v75 (2016/11/02) + +* Add "AUTHORS" and "CONTRIBUTORS" to legal files list: https://github.com/tools/godep/pull/522 + +#v74 (2016/06/01) + +* Enable vendor/ on go1.7 +* No longer use a godep workspace, use vendor/ (yay!) +* Notify that support for Godep workspaces will be removed once go1.8 ships + +#v73 (2016/05/31) + +* Fix permission changes on Windows via @alexbrand. Closes #481. + +#v72 (2016/05/27) + +* Improve handling of git remote show origin. Should help in cases where remote HEAD is ambiguous. +* Add ISSUE_TEMPLATE + +#v71 (2016/05/24) + +* Preserve permissions on copied files. + +#v70 (2016/05/20) + +* Fix the May changelog dates +* No need to call build.Import, we already have the root of the dependency. Fixes an additional comment on #365 + +#v69 (2016/05/16) + +* Make sure `devel-` enabled `vendor/` unless there is a classic Godep _workspace already. + +#v68 (2016/05/16) + +* `devel-` is always considered newer than any released go version + +#v67 (2016/05/13) + +* Attempt to handle missing deps a little better. + +#v66 (2016/05/10) + +* Use `git remote show origin` to find the default branch when restoring a git based package repository that is in detached head state + +#v65 (2016/05/09) + +* Rewrite update so that it considers new transitive dependencies, both in the same repo and outside of it. + +#v64 (2016/05/09) + +* godep update golang.org/x/tools/go/vcs + +#v63 (2016/05/03) + +* Support recording devel- so development versions of Go can be matched + +#v62 (2016/04/07) + +* Note new go1.6+ behavior of not checking out master in README / restore help text. + +#v61 (2016/04/06) + +* Obey go version build tags based on recorded major go version. Fixes #448. + +#v60 (2016/03/18) + +* Make the $GOPATH check a warning. + +#v59 (2016/03/18) + +* Enforce requirement to be inside of a go src directory. A lot of time is usually spent +tracking down bug reports where people are doign stuff from outside of their $GOPATH. This +should help with that, at least until there it time to properly test godep use outside of a +$GOPATH and fix the issues. + +#v58 (2016/03/15) + +* Add GodepVersion to Godeps.json file so that as godep changes / adds features / fixes bugs we can know which version of godep most recently wrote out the file. + +#v57 (2016/03/07) + +* Don't use `git rev-parse --show-toplevel` to determine git repo roots as it resolves symlinks: https://github.com/tools/godep/pull/418 + +# v56 (2016/02/26) + +* replace path comparisons with case insensitive pathEqual() +* add versionString() to debug output +* Send log output to Stderr + +# v55 2016/02/22 + +* re-saved deps to clean out extra stuff (see v54; godep restore; godep save -r=false; rm -rf Godeps; godep save -r). We're still using a workspace with rewrites so users of older go version can still go get this tool. +* Replace simple == with strings.EqualFold in listFiles to avoid problems with case insensitive filesystems ("Code" != "code" when doing a byte by byte comparison) + +# v54 2016/02/22 + +* Update some docs around vendor/ +* More precise recording of dependencies. Removed recursive copying of sub directories of a package (precise vendoring). This should allow using `./...` with the go tool for compilation of project using `vendor/`. See https://github.com/tools/godep/pull/415 + +# v53 2016/02/11 + +* Disable VendorExperiment if a godep workspace already exists. + +# v52 2016/01/27 + +* Trim 'rc' out of go version strings when determining major version. + +# v51 2016/01/21 + +* Trim 'beta' out of go version strings when determining major version. + +# v50 2016/01/19 + +* More verbose output on save -v. + +# v49 2016/01/13 + +* Add UK spelling license/licence to the pile + fix up a bunch of typos +* Clarify tag handling in docs + +# v48 2016/01/13 + +* Abort restore if there is no $GOPATH set. + +# v47 2016/01/12 + +* Dev versions of go should honor the current meaning of GO15VENDOREXPERIMENT + +# v46 2016/01/03 + +* Record "devel" when the release is a devel release of go (compiled from git). + +# v45 2015/12/28 + +* Upcase windows drive letters before comparing. Fixes #383. + +# v44 2015/12/23 + +* Clean package roots when attempting to find a vendor directory so we don't loop forever. + * Fixes 382 + +# v43 2015/12/22 + +* Better error messages when parsing Godeps.json: Fixes #372 + +# v42 2015/12/22 + +* Fix a bunch of GO15VENDOREXPERIMENT issues + * Find package directories better. Previously we used build.FindOnly which didn't work the way I expected it to (any dir would work w/o error). + * Set the VendorExperiment bool based on go version as 1.6 defaults to on. + * A bunch of extra debugging for use while sanity checking myself. + * vendor flag for test structs. + * Some tests for vendor/ stuff: + * Basic Test + * Transitive + * Transitive, across GOPATHs + collapse vendor/ directories. +* Should Fix #358 + +# v41 2015/12/17 + +* Don't rewrite packages outside of the project. This would happen if you specified + an external package for vendoring when you ran `goodep save -r ./... github.com/some/other/package` + +# v40 2015/12/17 + +* When downloading a dependency, create the base directory if needed. + +# v39 2015/12/16 + +* Record only the major go version (ex. go1.5) instead of the complete string. + +# v38 2015/12/16 + +* Replace `go get`, further fix up restore error handling/reporting. + * Fixes #186 + * Don't bother restoring/downloading if already done. + +# v37 2015/12/15 + +* Change up how download/restore works a little + * Try to load the package after downloading/restoring. Previously + that was done too early in the process. + * make previous verbose output debug output + * report a typed error instead of a string from listPackage so it can + be asserted to provide a nicer error. + * Catch go get errors that say there are no go files found. See code + comment as to why. + * do *all* downloading during download phase. + +# v36 2015/12/14 + +* Fixes #358: Using wrong variable. Will add test after release. + +# v35 2015/12/11 + +* Fixes #356: Major performance regressions in v34 + * Enable cpu profiling via flag on save. + * Cache packages by dir + * Don't do a full import pass on deps for packages in the GOROOT + * create a bit less garbage at times +* Generalize -v & -d flags + +# v34 2015/12/08 + +* We now use build.Context to help locate packages only and do our own parsing (via go/ast). +* Fixes reported issues caused by v33 (Removal of `go list`): + * #345: Bug in godep restore + * #346: Fix loading a dot package + * #348: Godep save issue when importing lib/pq + * #350: undefined: build.MultiplePackageError + * #351: stow away helper files + * #353: cannot find package "appengine" + * Don't process imports of `.go` files tagged with the `appengine` build tag. + +# v33 2015/12/07 + +* Replace the use of `go list`. This is a large change although all existing tests pass. + * Don't process the imports of `.go` files with the `ignore` build tag. + +# v32 2015/12/02 + +* Eval Symlinks in Contains() check. + +# v31 2015/12/02 + +* In restore, mention which package had the problem -- @shurcool + +# v30 2015/11/25 + +* Add `-t` flag to the `godep get` command. + +# v29 2015/11/17 + +* Temp work around to fix issue with LICENSE files. + +# v28 2015/11/09 + +* Make `version` an actual command. + +# v27 2015/11/06 + +* run command once during restore -v + +# v26 2015/11/05 + +* Better fix for the issue fixed in v25: All update paths are now path.Clean()'d + +# v25 2015/11/05 + +* `godep update package/` == `godep update package`. Fixes #313 + +# v24 2015/11/05 + +* Honor -t during update. Fixes #312 + +# v23 2015/11/05 + +* Do not use --debug to find full revision name for mercurial repositories + +# v22 2015/11/14 + +* s/GOVENDOREXPERIMENT/GO15VENDOREXPERIMENT :-( + +# v21 2015/11/13 + +* Fix #310: Case insensitive fs issue + +# v20 2015/11/13 + +* Attempt to include license files when vendoring. (@client9) + +# v19 2015/11/3 + +* Fix conflict error message. Revisions were swapped. Also better selection of package that needs update. + +# v18 2015/10/16 + +* Improve error message when trying to save a conflicting revision. + +# v17 2015/10/15 + +* Fix for v16 bug. All vcs list commands now produce paths relative to the root of the vcs. + +# v16 2015/10/15 + +* Determine repo root using vcs commands and use that instead of dep.dir + +# v15 2015/10/14 + +* Update .travis.yml file to do releases to github + +# v14 2015/10/08 + +* Don't print out a workspace path when GO15VENDOREXPERIMENT is active. The vendor/ directory is not a valid workspace, so can't be added to your $GOPATH. + +# v13 2015/10/07 + +* Do restores in 2 separate steps, first download all deps and then check out the recorded revisions. +* Update Changelog date format + +# v12 2015/09/22 + +* Extract errors into separate file. + +# v11 2015/08/22 + +* Amend code to pass golint. + +# v10 2015/09/21 + +* Analyse vendored package test dependencies. +* Update documentation. + +# v9 2015/09/17 + +* Don't save test dependencies by default. + +# v8 2015/09/17 + +* Reorganize code. + +# v7 2015/09/09 + +* Add verbose flag. +* Skip untracked files. +* Add VCS list command. + +# v6 2015/09/04 + +* Revert ignoring testdata directories and instead ignore it while +processing Go files and copy the whole directory unmodified. + +# v5 2015/09/04 + +* Fix vcs selection in restore command to work as go get does + +# v4 2015/09/03 + +* Remove the deprecated copy option. + +# v3 2015/08/26 + +* Ignore testdata directories + +# v2 2015/08/11 + +* Include command line packages in the set to copy + +This is a simplification to how we define the behavior +of the save command. Now it has two distinct package +parameters, the "root set" and the "destination", and +they have clearer roles. The packages listed on the +command line form the root set; they and all their +dependencies will be copied into the Godeps directory. +Additionally, the destination (always ".") will form the +initial list of "seen" import paths to exclude from +copying. + +In the common case, the root set is equal to the +destination, so the effective behavior doesn't change. +This is primarily just a simpler definition. However, if +the user specifies a package on the command line that +lives outside of . then that package will be copied. + +As a side effect, there's a simplification to the way we +add packages to the initial "seen" set. Formerly, to +avoid copying dependencies unnecessarily, we would try +to find the root of the VCS repo for each package in the +root set, and mark the import path of the entire repo as +seen. This meant for a repo at path C, if destination +C/S imports C/T, we would not copy C/T into C/S/Godeps. +Now we don't treat the repo root specially, and as +mentioned above, the destination alone is considered +seen. + +This also means we don't require listed packages to be +in VCS unless they're outside of the destination. + +# v1 2015/07/20 + +* godep version command + +Output the version as well as some godep runtime information that is +useful for debugging user's issues. + +The version const would be bumped each time a PR is merged into master +to ensure that we'll be able to tell which version someone got when they +did a `go get github.com/tools/godep`. + +# Older changes + +Many and more, see `git log -p` diff --git a/vendor/github.com/tools/godep/FAQ.md b/vendor/github.com/tools/godep/FAQ.md new file mode 100644 index 0000000000..5e68465a7f --- /dev/null +++ b/vendor/github.com/tools/godep/FAQ.md @@ -0,0 +1,22 @@ +## Why do I need to check in `vendor/`? + +godep's primary concern is to allow you to repeatably build your project. Your +dependencies are part of that project. Without them it won't build. Not +committing `vendor/` adds additional external dependencies that are outside of +your control. In Go, fetching packages is tied to multiple external systems +(DNS, web servers, etc). Over time other developers or code hosting sites may +discontinue service, delete code, force push, or take any number of other +actions that may make a package unreachable. Therefore it's the opinion of the +godep authors that `vendor/` should always be checked in. + +## Should I use `godep restore`? + +Probably not, unless you **need** to. Situations where you would **need** to are: + +1. Using older Godep Workspaces (`Godeps/_workspace`) and not using `godep go + `. +1. Resetting the state of $GOPATH to what is in your `Godeps.json` file in order + to cleanly re-vendor everything w/o upgrading/changing any deps. This is + useful when [migrating](https://github.com/tools/godep#migrating-to-vendor) + from workspaces to `vendor` or when a bug is fixed in `godep` that cleans up + a previous vendoring error. diff --git a/vendor/github.com/tools/godep/License b/vendor/github.com/tools/godep/License new file mode 100644 index 0000000000..5c52e6867c --- /dev/null +++ b/vendor/github.com/tools/godep/License @@ -0,0 +1,28 @@ +Copyright © 2013 Keith Rarick. +Portions Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/tools/godep/Readme.md b/vendor/github.com/tools/godep/Readme.md new file mode 100644 index 0000000000..247688d83e --- /dev/null +++ b/vendor/github.com/tools/godep/Readme.md @@ -0,0 +1,199 @@ +## Godep + +[![Build Status](https://travis-ci.org/tools/godep.svg)](https://travis-ci.org/tools/godep) + +[![GoDoc](https://godoc.org/github.com/tools/godep?status.svg)](https://godoc.org/github.com/tools/godep) + +godep helps build packages reproducibly by fixing their dependencies. + +This tool assumes you are working in a standard Go workspace, as described in +http://golang.org/doc/code.html. We expect godep to build on Go 1.4* or newer, +but you can use it on any project that works with Go 1 or newer. + +Please check the [FAQ](FAQ.md) if you have a question. + +## Install + +```console +$ go get github.com/tools/godep +``` + +## How to use godep with a new project + +Assuming you've got everything working already, so you can build your project +with `go install` and test it with `go test`, it's one command to start using: + +```console +$ godep save +``` + +This will save a list of dependencies to the file `Godeps/Godeps.json` and copy +their source code into `vendor/` (or `Godeps/_workspace/` when using older +versions of Go). Godep does **not copy**: + +- files from source repositories that are not tracked in version control. +- `*_test.go` files. +- `testdata` directories. +- files outside of the go packages. + +Godep does not process the imports of `.go` files with either the `ignore` +or `appengine` build tags. + +Test files and testdata directories can be saved by adding `-t`. + +Read over the contents of `vendor/` and make sure it looks reasonable. Then +commit the `Godeps/` and `vendor/` directories to version control. + +## The deprecated `-r` flag + +For older versions of Go, the `-r` flag tells save to automatically rewrite +package import paths. This allows your code to refer directly to the copied +dependencies in `Godeps/_workspace`. So, a package C that depends on package +D will actually import `C/Godeps/_workspace/src/D`. This makes C's repo +self-contained and causes `go get` to build C with the right version of all +dependencies. + +If you don't use `-r`, when using older version of Go, then in order to use the +fixed dependencies and get reproducible builds, you must make sure that **every +time** you run a Go-related command, you wrap it in one of these two ways: + +- If the command you are running is just `go`, run it as `godep go ...`, e.g. + `godep go install -v ./...` +- When using a different command, set your `$GOPATH` using `godep path` as + described below. + +`-r` isn't necessary with go1.6+ and isn't allowed. + + +## Additional Operations + +### Restore + +The `godep restore` installs the +package versions specified in `Godeps/Godeps.json` to your `$GOPATH`. This +modifies the state of packages in your `$GOPATH`. NOTE: `godep restore` leaves +git repositories in a detached state. `go1.6`+ no longer checks out the master +branch when doing a `go get`, see [here](https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669). + +Please see the [FAQ](https://github.com/tools/godep/blob/master/FAQ.md#should-i-use-godep-restore) section about restore. + +### Edit-test Cycle + +1. Edit code +1. Run `godep go test` +1. (repeat) + +### Add a Dependency + +To add a new package foo/bar, do this: + +1. Run `go get foo/bar` +1. Edit your code to import foo/bar. +1. Run `godep save` (or `godep save ./...`). + +### Update a Dependency + +To update a package from your `$GOPATH`, do this: + +1. Run `go get -u foo/bar` +1. Run `godep update foo/bar`. (You can use the `...` wildcard, for example +`godep update foo/...`). + +Before comitting the change, you'll probably want to inspect the changes to +Godeps, for example with `git diff`, and make sure it looks reasonable. + +## Multiple Packages + +If your repository has more than one package, you're probably accustomed to +running commands like `go test ./...`, `go install ./...`, and `go fmt ./...`. +Similarly, you should run `godep save ./...` to capture the dependencies of all +packages in your application. + + +## File Format + +Godeps is a json file with the following structure: + +```go +type Godeps struct { + ImportPath string + GoVersion string // Abridged output of 'go version'. + GodepVersion string // Abridged output of 'godep version' + Packages []string // Arguments to godep save, if any. + Deps []struct { + ImportPath string + Comment string // Description of commit, if present. + Rev string // VCS-specific commit ID. + } +} +``` + +Example Godeps: + +```json +{ + "ImportPath": "github.com/kr/hk", + "GoVersion": "go1.6", + "Deps": [ + { + "ImportPath": "code.google.com/p/go-netrc/netrc", + "Rev": "28676070ab99" + }, + { + "ImportPath": "github.com/kr/binarydist", + "Rev": "3380ade90f8b0dfa3e363fd7d7e941fa857d0d13" + } + ] +} +``` + +## Migrating to vendor/ + +Godep supports the Go 1.5+ vendor/ +[experiment](https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff) +utilizing the same environment variable that the go tooling itself supports +(`GO15VENDOREXPERIMENT`). + +godep mostly works the same way as the `go` command line tool. If you have go +1.5.X and set `GO15VENDOREXPERIMENT=1` or have go1.6.X (or devel) `vendor/` +is enabled. **Unless** you already have a `Godeps/_workspace`. This is a safety +feature and godep warns you about this. + +When `vendor/` is enabled godep will write the vendored code into the top level +`./vendor/` directory. A `./Godeps/Godeps.json` file is created to track +the dependencies and revisions. `vendor/` is not compatible with rewrites. + +There is currently no automated migration between the old Godeps workspace and +the vendor directory, but the following steps should work: + +```term +# just to be safe +$ unset GO15VENDOREXPERIMENT + +# restore currently vendored deps to the $GOPATH +$ godep restore + +# The next line is only needed to automatically undo rewritten imports that were +# created with godep save -r. +$ godep save -r=false + +# Remove the old Godeps folder +$ rm -rf Godeps + +# If on go1.5.X to enable `vendor/` +$ export GO15VENDOREXPERIMENT=1 + +# re-analyze deps and save to `vendor/`. +$ godep save + +# Add the changes to your VCS +$ git add -A . ; git commit -am "Godep workspace -> vendor/" + +# You should see your Godeps/_workspace/src files "moved" to vendor/. +``` + +## Releasing + +1. Increment the version in `version.go`. +1. Tag the commit with the same version number. +1. Update `Changelog.md`. diff --git a/vendor/github.com/tools/godep/dep.go b/vendor/github.com/tools/godep/dep.go new file mode 100644 index 0000000000..a997603c5c --- /dev/null +++ b/vendor/github.com/tools/godep/dep.go @@ -0,0 +1,128 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "sort" + "strings" +) + +// A Dependency is a specific revision of a package. +type Dependency struct { + ImportPath string + Comment string `json:",omitempty"` // Description of commit, if present. + Rev string // VCS-specific commit ID. + + // used by command save & update + ws string // workspace + root string // import path to repo root + dir string // full path to package + + // used by command update + matched bool // selected for update by command line + pkg *Package + missing bool // packages is missing + + // used by command go + vcs *VCS +} + +func eqDeps(a, b []Dependency) bool { + ok := true + for _, da := range a { + for _, db := range b { + if da.ImportPath == db.ImportPath && da.Rev != db.Rev { + ok = false + } + } + } + return ok +} + +// containsPathPrefix returns whether any string in a +// is s or a directory containing s. +// For example, pattern ["a"] matches "a" and "a/b" +// (but not "ab"). +func containsPathPrefix(pats []string, s string) bool { + for _, pat := range pats { + if pat == s || strings.HasPrefix(s, pat+"/") { + return true + } + } + return false +} + +func uniq(a []string) []string { + var s string + var i int + if !sort.StringsAreSorted(a) { + sort.Strings(a) + } + for _, t := range a { + if t != s { + a[i] = t + i++ + s = t + } + } + return a[:i] +} + +// trimGoVersion and return the major version +func trimGoVersion(version string) (string, error) { + if version == "devel" { + return "devel", nil + } + if strings.HasPrefix(version, "devel+") || strings.HasPrefix(version, "devel-") { + return strings.Replace(version, "devel+", "devel-", 1), nil + } + p := strings.Split(version, ".") + if len(p) < 2 { + return "", fmt.Errorf("Error determining major go version from: %q", version) + } + var split string + switch { + case strings.Contains(p[1], "beta"): + split = "beta" + case strings.Contains(p[1], "rc"): + split = "rc" + } + if split != "" { + p[1] = strings.Split(p[1], split)[0] + } + return p[0] + "." + p[1], nil +} + +var goVersionTestOutput = "" + +func getGoVersion() (string, error) { + // For testing purposes only + if goVersionTestOutput != "" { + return goVersionTestOutput, nil + } + + // Godep might have been compiled with a different + // version, so we can't just use runtime.Version here. + cmd := exec.Command("go", "version") + cmd.Stderr = os.Stderr + out, err := cmd.Output() + return string(out), err +} + +// goVersion returns the major version string of the Go compiler +// currently installed, e.g. "go1.5". +func goVersion() (string, error) { + out, err := getGoVersion() + if err != nil { + return "", err + } + gv := strings.Split(out, " ") + if len(gv) < 4 { + return "", fmt.Errorf("Error splitting output of `go version`: Expected 4 or more elements, but there are < 4: %q", out) + } + if gv[2] == "devel" { + return trimGoVersion(gv[2] + gv[3]) + } + return trimGoVersion(gv[2]) +} diff --git a/vendor/github.com/tools/godep/diff.go b/vendor/github.com/tools/godep/diff.go new file mode 100644 index 0000000000..c43faa4090 --- /dev/null +++ b/vendor/github.com/tools/godep/diff.go @@ -0,0 +1,74 @@ +package main + +import ( + "bytes" + "fmt" + "log" + + "github.com/pmezard/go-difflib/difflib" +) + +var cmdDiff = &Command{ + Name: "diff", + Short: "shows the diff between current and previously saved set of dependencies", + Long: ` +Shows the difference, in a unified diff format, between the +current set of dependencies and those generated on a +previous 'go save' execution. +`, + Run: runDiff, + OnlyInGOPATH: true, +} + +func runDiff(cmd *Command, args []string) { + gold, err := loadDefaultGodepsFile() + if err != nil { + log.Fatalln(err) + } + + pkgs := []string{"."} + dot, err := LoadPackages(pkgs...) + if err != nil { + log.Fatalln(err) + } + + gnew := &Godeps{ + ImportPath: dot[0].ImportPath, + GoVersion: gold.GoVersion, + } + + err = gnew.fill(dot, dot[0].ImportPath) + if err != nil { + log.Fatalln(err) + } + + diff, err := diffStr(&gold, gnew) + if err != nil { + log.Fatalln(err) + } + fmt.Println(diff) +} + +// diffStr returns a unified diff string of two Godeps. +func diffStr(a, b *Godeps) (string, error) { + var ab, bb bytes.Buffer + + _, err := a.writeTo(&ab) + if err != nil { + log.Fatalln(err) + } + + _, err = b.writeTo(&bb) + if err != nil { + log.Fatalln(err) + } + + diff := difflib.UnifiedDiff{ + A: difflib.SplitLines(ab.String()), + B: difflib.SplitLines(bb.String()), + FromFile: b.file(), + ToFile: "$GOPATH", + Context: 10, + } + return difflib.GetUnifiedDiffString(diff) +} diff --git a/vendor/github.com/tools/godep/doc.go b/vendor/github.com/tools/godep/doc.go new file mode 100644 index 0000000000..5ff160285e --- /dev/null +++ b/vendor/github.com/tools/godep/doc.go @@ -0,0 +1,22 @@ +/* + +Command godep helps build packages reproducibly by fixing +their dependencies. + +Example Usage + +Save currently-used dependencies to file Godeps: + + $ godep save + +Build project using saved dependencies: + + $ godep go install + +or + + $ GOPATH=`godep path`:$GOPATH + $ go install + +*/ +package main diff --git a/vendor/github.com/tools/godep/errors.go b/vendor/github.com/tools/godep/errors.go new file mode 100644 index 0000000000..445682ceb9 --- /dev/null +++ b/vendor/github.com/tools/godep/errors.go @@ -0,0 +1,18 @@ +package main + +import "errors" + +var ( + errorLoadingDeps = errors.New("error loading dependencies") + errorLoadingPackages = errors.New("error loading packages") + errorCopyingSourceCode = errors.New("error copying source code") + errorNoPackagesUpdatable = errors.New("no packages can be updated") +) + +type errPackageNotFound struct { + path string +} + +func (e errPackageNotFound) Error() string { + return "Package (" + e.path + ") not found" +} diff --git a/vendor/github.com/tools/godep/get.go b/vendor/github.com/tools/godep/get.go new file mode 100644 index 0000000000..8b397a0027 --- /dev/null +++ b/vendor/github.com/tools/godep/get.go @@ -0,0 +1,96 @@ +package main + +import ( + "log" + "os" + "os/exec" +) + +var cmdGet = &Command{ + Name: "get", + Args: "[-t] [packages]", + Short: "download and install packages with specified dependencies", + Long: ` +Get downloads to GOPATH the packages named by the import paths, and installs +them with the dependencies specified in their Godeps files. + +If any of the packages do not have Godeps files, those are installed +as if by go get. + +If -t is given, dependencies of test files are also downloaded and installed. + +For more about specifying packages, see 'go help packages'. +`, + Run: runGet, + OnlyInGOPATH: true, +} + +var getT bool + +func init() { + cmdGet.Flag.BoolVar(&getT, "t", false, "get test dependencies") +} + +func runGet(cmd *Command, args []string) { + if len(args) == 0 { + args = []string{"."} + } + + cmdArgs := []interface{}{"get", "-d"} + if verbose { + cmdArgs = append(cmdArgs, "-v") + } + + if getT { + cmdArgs = append(cmdArgs, "-t") + } + + err := command("go", append(cmdArgs, args)...).Run() + if err != nil { + log.Fatalln(err) + } + + // group import paths by Godeps location + groups := make(map[string][]string) + ps, err := LoadPackages(args...) + if err != nil { + log.Fatalln(err) + } + for _, pkg := range ps { + if pkg.Error.Err != "" { + log.Fatalln(pkg.Error.Err) + } + dir, _ := findInParents(pkg.Dir, "Godeps") + groups[dir] = append(groups[dir], pkg.ImportPath) + } + for dir, packages := range groups { + var c *exec.Cmd + if dir == "" { + c = command("go", "install", packages) + } else { + c = command("godep", "go", "install", packages) + c.Dir = dir + } + if err := c.Run(); err != nil { + log.Fatalln(err) + } + } +} + +// command is like exec.Command, but the returned +// Cmd inherits stderr from the current process, and +// elements of args may be either string or []string. +func command(name string, args ...interface{}) *exec.Cmd { + var a []string + for _, arg := range args { + switch v := arg.(type) { + case string: + a = append(a, v) + case []string: + a = append(a, v...) + } + } + c := exec.Command(name, a...) + c.Stderr = os.Stderr + return c +} diff --git a/vendor/github.com/tools/godep/go.go b/vendor/github.com/tools/godep/go.go new file mode 100644 index 0000000000..97e361ae94 --- /dev/null +++ b/vendor/github.com/tools/godep/go.go @@ -0,0 +1,129 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strings" +) + +var cmdGo = &Command{ + Name: "go", + Args: "command [arguments]", + Short: "run the go tool with saved dependencies", + Long: ` +Go runs the go tool with a modified GOPATH giving access to +dependencies saved in Godeps. + +Any go tool command can run this way, but "godep go get" +is unnecessary and has been disabled. Instead, use +"godep go install". +`, + Run: runGo, + OnlyInGOPATH: true, +} + +// Find the godep GOPATH for this file tree and run the go tool. +func runGo(cmd *Command, args []string) { + gopath := prepareGopath() + if s := os.Getenv("GOPATH"); s != "" { + gopath += string(os.PathListSeparator) + os.Getenv("GOPATH") + } + if len(args) > 0 && args[0] == "get" { + log.Printf("invalid subcommand: %q", "go get") + fmt.Fprintln(os.Stderr, "Use 'godep go install' instead.") + fmt.Fprintln(os.Stderr, "Run 'godep help go' for usage.") + os.Exit(2) + } + c := exec.Command("go", args...) + c.Env = append(envNoGopath(), "GOPATH="+gopath) + c.Stdin = os.Stdin + c.Stdout = os.Stdout + c.Stderr = os.Stderr + err := c.Run() + if err != nil { + log.Fatalln("go", err) + } +} + +// prepareGopath reads dependency information from the filesystem +// entry name, fetches any necessary code, and returns a gopath +// causing the specified dependencies to be used. +func prepareGopath() (gopath string) { + dir, isDir := findGodeps() + if dir == "" { + log.Fatalln("No Godeps found (or in any parent directory)") + } + if !isDir { + log.Fatalln(strings.TrimSpace(needSource)) + } + return filepath.Join(dir, "Godeps", "_workspace") +} + +// findGodeps looks for a directory entry "Godeps" in the +// current directory or any parent, and returns the containing +// directory and whether the entry itself is a directory. +// If Godeps can't be found, findGodeps returns "". +// For any other error, it exits the program. +func findGodeps() (dir string, isDir bool) { + wd, err := os.Getwd() + if err != nil { + log.Fatalln(err) + } + return findInParents(wd, "Godeps") +} + +// isRoot returns true iff a path is a root. +// On Unix: "/". +// On Windows: "C:\", "D:\", ... +func isRoot(p string) bool { + p = filepath.Clean(p) + volume := filepath.VolumeName(p) + + p = strings.TrimPrefix(p, volume) + p = filepath.ToSlash(p) + + return p == "/" +} + +// findInParents returns the path to the directory containing name +// in dir or any ancestor, and whether name itself is a directory. +// If name cannot be found, findInParents returns the empty string. +func findInParents(dir, name string) (container string, isDir bool) { + for { + fi, err := os.Stat(filepath.Join(dir, name)) + if os.IsNotExist(err) && isRoot(dir) { + return "", false + } + if os.IsNotExist(err) { + dir = filepath.Dir(dir) + continue + } + if err != nil { + log.Fatalln(err) + } + return dir, fi.IsDir() + } +} + +func envNoGopath() (a []string) { + for _, s := range os.Environ() { + if !strings.HasPrefix(s, "GOPATH=") { + a = append(a, s) + } + } + return a +} + +const needSource = ` +outdated Godeps missing source code + +This dependency list was created with an old version of godep. + +To work around this, you have two options: +1. Run 'godep restore', and try again. +2. Ask the maintainer to switch to a newer version of godep, +then try again with the updated package. +` diff --git a/vendor/github.com/tools/godep/godepfile.go b/vendor/github.com/tools/godep/godepfile.go new file mode 100644 index 0000000000..b09d80acdf --- /dev/null +++ b/vendor/github.com/tools/godep/godepfile.go @@ -0,0 +1,224 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "log" + "os" + "path/filepath" +) + +var ( + godepsFile = filepath.Join("Godeps", "Godeps.json") + oldGodepsFile = filepath.Join("Godeps") +) + +// Godeps describes what a package needs to be rebuilt reproducibly. +// It's the same information stored in file Godeps. +type Godeps struct { + ImportPath string + GoVersion string + GodepVersion string + Packages []string `json:",omitempty"` // Arguments to save, if any. + Deps []Dependency + isOldFile bool +} + +func createGodepsFile() (*os.File, error) { + return os.Create(godepsFile) +} + +func loadGodepsFile(path string) (Godeps, error) { + var g Godeps + f, err := os.Open(path) + if err != nil { + return g, err + } + defer f.Close() + err = json.NewDecoder(f).Decode(&g) + if err != nil { + err = fmt.Errorf("Unable to parse %s: %s", path, err.Error()) + } + return g, err +} + +func loadDefaultGodepsFile() (Godeps, error) { + var g Godeps + var err error + g, err = loadGodepsFile(godepsFile) + if err != nil { + if os.IsNotExist(err) { + var err1 error + g, err1 = loadGodepsFile(oldGodepsFile) + if err1 != nil { + if os.IsNotExist(err1) { + return g, err + } + return g, err1 + } + g.isOldFile = true + return g, nil + } + } + return g, err +} + +// pkgs is the list of packages to read dependencies for +func (g *Godeps) fill(pkgs []*Package, destImportPath string) error { + debugln("fill", destImportPath) + ppln(pkgs) + var err1 error + var path, testImports []string + dipp := []string{destImportPath} + for _, p := range pkgs { + if p.Standard { + log.Println("ignoring stdlib package:", p.ImportPath) + continue + } + if p.Error.Err != "" { + log.Println(p.Error.Err) + err1 = errorLoadingPackages + continue + } + path = append(path, p.ImportPath) + path = append(path, p.Deps...) + testImports = append(testImports, p.TestImports...) + testImports = append(testImports, p.XTestImports...) + } + ps, err := LoadPackages(testImports...) + if err != nil { + return err + } + for _, p := range ps { + if p.Standard { + continue + } + if p.Error.Err != "" { + log.Println(p.Error.Err) + err1 = errorLoadingPackages + continue + } + path = append(path, p.ImportPath) + path = append(path, p.Deps...) + } + debugln("path", path) + for i, p := range path { + path[i] = unqualify(p) + } + path = uniq(path) + debugln("uniq, unqualify'd path", path) + ps, err = LoadPackages(path...) + if err != nil { + return err + } + for _, pkg := range ps { + if pkg.Error.Err != "" { + log.Println(pkg.Error.Err) + err1 = errorLoadingDeps + continue + } + if pkg.Standard || containsPathPrefix(dipp, pkg.ImportPath) { + debugln("standard or dest skipping", pkg.ImportPath) + continue + } + vcs, reporoot, err := VCSFromDir(pkg.Dir, filepath.Join(pkg.Root, "src")) + if err != nil { + log.Println(err) + err1 = errorLoadingDeps + continue + } + id, err := vcs.identify(pkg.Dir) + if err != nil { + log.Println(err) + err1 = errorLoadingDeps + continue + } + if vcs.isDirty(pkg.Dir, id) { + log.Println("dirty working tree (please commit changes):", pkg.Dir) + err1 = errorLoadingDeps + continue + } + comment := vcs.describe(pkg.Dir, id) + g.Deps = append(g.Deps, Dependency{ + ImportPath: pkg.ImportPath, + Rev: id, + Comment: comment, + dir: pkg.Dir, + ws: pkg.Root, + root: filepath.ToSlash(reporoot), + vcs: vcs, + }) + } + return err1 +} + +func (g *Godeps) copy() *Godeps { + h := *g + h.Deps = make([]Dependency, len(g.Deps)) + copy(h.Deps, g.Deps) + return &h +} + +func (g *Godeps) file() string { + if g.isOldFile { + return oldGodepsFile + } + return godepsFile +} + +func (g *Godeps) save() (int64, error) { + f, err := os.Create(g.file()) + if err != nil { + return 0, err + } + defer f.Close() + return g.writeTo(f) +} + +func (g *Godeps) writeTo(w io.Writer) (int64, error) { + g.GodepVersion = fmt.Sprintf("v%d", version) // godep always writes its current version. + b, err := json.MarshalIndent(g, "", "\t") + if err != nil { + return 0, err + } + n, err := w.Write(append(b, '\n')) + return int64(n), err +} + +func (g *Godeps) addOrUpdateDeps(deps []Dependency) { + var missing []Dependency + for _, d := range deps { + var found bool + for i := range g.Deps { + if g.Deps[i].ImportPath == d.ImportPath { + g.Deps[i] = d + found = true + break + } + } + if !found { + missing = append(missing, d) + } + } + for _, d := range missing { + g.Deps = append(g.Deps, d) + } +} + +func (g *Godeps) removeDeps(deps []Dependency) { + var f []Dependency + for i := range g.Deps { + var found bool + for _, d := range deps { + if g.Deps[i].ImportPath == d.ImportPath { + found = true + break + } + } + if !found { + f = append(f, g.Deps[i]) + } + } + g.Deps = f +} diff --git a/vendor/github.com/tools/godep/license.go b/vendor/github.com/tools/godep/license.go new file mode 100644 index 0000000000..d382063426 --- /dev/null +++ b/vendor/github.com/tools/godep/license.go @@ -0,0 +1,59 @@ +package main + +import ( + "strings" +) + +// LicenseFilePrefix is a list of filename prefixes that indicate it +// might contain a software license +var LicenseFilePrefix = []string{ + "licence", // UK spelling + "license", // US spelling + "copying", + "unlicense", + "copyright", + "copyleft", + "authors", + "contributors", +} + +// LegalFileSubstring are substrings that indicate the file is likely +// to contain some type of legal declaration. "legal" is often used +// that it might moved to LicenseFilePrefix +var LegalFileSubstring = []string{ + "legal", + "notice", + "disclaimer", + "patent", + "third-party", + "thirdparty", +} + +// IsLicenseFile returns true if the filename might be contain a +// software license +func IsLicenseFile(filename string) bool { + lowerfile := strings.ToLower(filename) + for _, prefix := range LicenseFilePrefix { + if strings.HasPrefix(lowerfile, prefix) { + return true + } + } + return false +} + +// IsLegalFile returns true if the file is likely to contain some type +// of of legal declaration or licensing information +func IsLegalFile(filename string) bool { + lowerfile := strings.ToLower(filename) + for _, prefix := range LicenseFilePrefix { + if strings.HasPrefix(lowerfile, prefix) { + return true + } + } + for _, substring := range LegalFileSubstring { + if strings.Index(lowerfile, substring) != -1 { + return true + } + } + return false +} diff --git a/vendor/github.com/tools/godep/list.go b/vendor/github.com/tools/godep/list.go new file mode 100644 index 0000000000..40abbb57bc --- /dev/null +++ b/vendor/github.com/tools/godep/list.go @@ -0,0 +1,604 @@ +package main + +import ( + "errors" + "fmt" + "go/build" + "go/parser" + "go/token" + "log" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "unicode" + + pathpkg "path" +) + +var ( + gorootSrc = filepath.Join(build.Default.GOROOT, "src") + ignoreTags = []string{"appengine", "ignore"} //TODO: appengine is a special case for now: https://github.com/tools/godep/issues/353 + versionMatch = regexp.MustCompile(`\Ago\d+\.\d+\z`) + versionNegativeMatch = regexp.MustCompile(`\A\!go\d+\.\d+\z`) +) + +type errorMissingDep struct { + i, dir string // import, dir +} + +func (e errorMissingDep) Error() string { + return "Unable to find dependent package " + e.i + " in context of " + e.dir +} + +// packageContext is used to track an import and which package imported it. +type packageContext struct { + pkg *build.Package // package that imports the import + imp string // import +} + +// depScanner tracks the processed and to be processed packageContexts +type depScanner struct { + processed []packageContext + todo []packageContext +} + +// Next package and import to process +func (ds *depScanner) Next() (*build.Package, string) { + c := ds.todo[0] + ds.processed = append(ds.processed, c) + ds.todo = ds.todo[1:] + return c.pkg, c.imp +} + +// Continue looping? +func (ds *depScanner) Continue() bool { + if len(ds.todo) > 0 { + return true + } + return false +} + +// Add a package and imports to the depScanner. Skips already processed/pending package/import combos +func (ds *depScanner) Add(pkg *build.Package, imports ...string) { +NextImport: + for _, i := range imports { + if i == "C" { + i = "runtime/cgo" + } + for _, epc := range ds.processed { + if pkg.Dir == epc.pkg.Dir && i == epc.imp { + debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i) + continue NextImport + } + } + for _, epc := range ds.todo { + if pkg.Dir == epc.pkg.Dir && i == epc.imp { + debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i) + continue NextImport + } + } + pc := packageContext{pkg, i} + debugln("Adding pc:", pc.pkg.Dir, pc.imp) + ds.todo = append(ds.todo, pc) + } +} + +var ( + pkgCache = make(map[string]*build.Package) // dir => *build.Package +) + +// returns the package in dir either from a cache or by importing it and then caching it +func fullPackageInDir(dir string) (*build.Package, error) { + var err error + pkg, ok := pkgCache[dir] + if !ok { + pkg, err = build.ImportDir(dir, build.FindOnly) + if pkg.Goroot { + pkg, err = build.ImportDir(pkg.Dir, 0) + } else { + err = fillPackage(pkg) + } + if err == nil { + pkgCache[dir] = pkg + } + } + return pkg, err +} + +// listPackage specified by path +func listPackage(path string) (*Package, error) { + debugln("listPackage", path) + var lp *build.Package + dir, err := findDirForPath(path, nil) + if err != nil { + return nil, err + } + lp, err = fullPackageInDir(dir) + p := &Package{ + Dir: lp.Dir, + Root: lp.Root, + ImportPath: lp.ImportPath, + XTestImports: lp.XTestImports, + TestImports: lp.TestImports, + GoFiles: lp.GoFiles, + CgoFiles: lp.CgoFiles, + TestGoFiles: lp.TestGoFiles, + XTestGoFiles: lp.XTestGoFiles, + IgnoredGoFiles: lp.IgnoredGoFiles, + } + p.Standard = lp.Goroot && lp.ImportPath != "" && !strings.Contains(lp.ImportPath, ".") + if err != nil || p.Standard { + return p, err + } + debugln("Looking For Package:", path, "in", dir) + ppln(lp) + + ds := depScanner{} + ds.Add(lp, lp.Imports...) + for ds.Continue() { + ip, i := ds.Next() + + debugf("Processing import %s for %s\n", i, ip.Dir) + pdir, err := findDirForPath(i, ip) + if err != nil { + return nil, err + } + dp, err := fullPackageInDir(pdir) + if err != nil { // This really should happen in this context though + ppln(err) + return nil, errorMissingDep{i: i, dir: ip.Dir} + } + ppln(dp) + if !dp.Goroot { + // Don't bother adding packages in GOROOT to the dependency scanner, they don't import things from outside of it. + ds.Add(dp, dp.Imports...) + } + debugln("lp:") + ppln(lp) + debugln("ip:") + ppln(ip) + if lp == ip { + debugln("lp == ip") + p.Imports = append(p.Imports, dp.ImportPath) + } + p.Deps = append(p.Deps, dp.ImportPath) + p.Dependencies = addDependency(p.Dependencies, dp) + } + p.Imports = uniq(p.Imports) + p.Deps = uniq(p.Deps) + debugln("Done Looking For Package:", path, "in", dir) + ppln(p) + return p, nil +} + +func addDependency(deps []build.Package, d *build.Package) []build.Package { + for i := range deps { + if deps[i].Dir == d.Dir { + return deps + } + } + return append(deps, *d) +} + +// finds the directory for the given import path in the context of the provided build.Package (if provided) +func findDirForPath(path string, ip *build.Package) (string, error) { + debugln("findDirForPath", path, ip) + var search []string + + if build.IsLocalImport(path) { + dir := path + if !filepath.IsAbs(dir) { + if abs, err := filepath.Abs(dir); err == nil { + // interpret relative to current directory + dir = abs + } + } + return dir, nil + } + + // We need to check to see if the import exists in vendor/ folders up the hierarchy of the importing package + if VendorExperiment && ip != nil { + debugln("resolving vendor posibilities:", ip.Dir, ip.Root) + cr := cleanPath(ip.Root) + + for base := cleanPath(ip.Dir); !pathEqual(base, cr); base = cleanPath(filepath.Dir(base)) { + s := filepath.Join(base, "vendor", path) + debugln("Adding search dir:", s) + search = append(search, s) + } + } + + for _, base := range build.Default.SrcDirs() { + search = append(search, filepath.Join(base, path)) + } + + for _, dir := range search { + debugln("searching", dir) + fi, err := stat(dir) + if err == nil && fi.IsDir() { + return dir, nil + } + } + + return "", errPackageNotFound{path} +} + +type statEntry struct { + fi os.FileInfo + err error +} + +var ( + statCache = make(map[string]statEntry) +) + +func clearStatCache() { + statCache = make(map[string]statEntry) +} + +func stat(p string) (os.FileInfo, error) { + if e, ok := statCache[p]; ok { + return e.fi, e.err + } + fi, err := os.Stat(p) + statCache[p] = statEntry{fi, err} + return fi, err +} + +// fillPackage full of info. Assumes p.Dir is set at a minimum +func fillPackage(p *build.Package) error { + if p.Goroot { + return nil + } + + if p.SrcRoot == "" { + for _, base := range build.Default.SrcDirs() { + if strings.HasPrefix(p.Dir, base) { + p.SrcRoot = base + } + } + } + + if p.SrcRoot == "" { + return errors.New("Unable to find SrcRoot for package " + p.ImportPath) + } + + if p.Root == "" { + p.Root = filepath.Dir(p.SrcRoot) + } + + var buildMatch = "+build " + var buildFieldSplit = func(r rune) bool { + return unicode.IsSpace(r) || r == ',' + } + + debugln("Filling package:", p.ImportPath, "from", p.Dir) + gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go")) + if err != nil { + debugln("Error globbing", err) + return err + } + + if len(gofiles) == 0 { + return &build.NoGoError{Dir: p.Dir} + } + + var testImports []string + var imports []string +NextFile: + for _, file := range gofiles { + debugln(file) + pf, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.ImportsOnly|parser.ParseComments) + if err != nil { + return err + } + testFile := strings.HasSuffix(file, "_test.go") + fname := filepath.Base(file) + for _, c := range pf.Comments { + ct := c.Text() + if i := strings.Index(ct, buildMatch); i != -1 { + for _, t := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) { + for _, tag := range ignoreTags { + if t == tag { + p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) + continue NextFile + } + } + + if versionMatch.MatchString(t) && !isSameOrNewer(t, majorGoVersion) { + debugln("Adding", fname, "to ignored list because of version tag", t) + p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) + continue NextFile + } + if versionNegativeMatch.MatchString(t) && isSameOrNewer(t[1:], majorGoVersion) { + debugln("Adding", fname, "to ignored list because of version tag", t) + p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) + continue NextFile + } + } + } + } + if testFile { + p.TestGoFiles = append(p.TestGoFiles, fname) + } else { + p.GoFiles = append(p.GoFiles, fname) + } + for _, is := range pf.Imports { + name, err := strconv.Unquote(is.Path.Value) + if err != nil { + return err // can't happen? + } + if testFile { + testImports = append(testImports, name) + } else { + imports = append(imports, name) + } + } + } + imports = uniq(imports) + testImports = uniq(testImports) + p.Imports = imports + p.TestImports = testImports + return nil +} + +// All of the following functions were vendored from go proper. Locations are noted in comments, but may change in future Go versions. + +// importPaths returns the import paths to use for the given command line. +// $GOROOT/src/cmd/main.go:366 +func importPaths(args []string) []string { + debugf("importPathsNoDotExpansion(%q) == ", args) + args = importPathsNoDotExpansion(args) + debugf("%q\n", args) + var out []string + for _, a := range args { + if strings.Contains(a, "...") { + if build.IsLocalImport(a) { + debugf("build.IsLocalImport(%q) == true\n", a) + pkgs := allPackagesInFS(a) + debugf("allPackagesInFS(%q) == %q\n", a, pkgs) + out = append(out, pkgs...) + } else { + debugf("build.IsLocalImport(%q) == false\n", a) + pkgs := allPackages(a) + debugf("allPackages(%q) == %q\n", a, pkgs) + out = append(out, allPackages(a)...) + } + continue + } + out = append(out, a) + } + return out +} + +// importPathsNoDotExpansion returns the import paths to use for the given +// command line, but it does no ... expansion. +// $GOROOT/src/cmd/main.go:332 +func importPathsNoDotExpansion(args []string) []string { + if len(args) == 0 { + return []string{"."} + } + var out []string + for _, a := range args { + // Arguments are supposed to be import paths, but + // as a courtesy to Windows developers, rewrite \ to / + // in command-line arguments. Handles .\... and so on. + if filepath.Separator == '\\' { + a = strings.Replace(a, `\`, `/`, -1) + } + + // Put argument in canonical form, but preserve leading ./. + if strings.HasPrefix(a, "./") { + a = "./" + pathpkg.Clean(a) + if a == "./." { + a = "." + } + } else { + a = pathpkg.Clean(a) + } + if a == "all" || a == "std" || a == "cmd" { + out = append(out, allPackages(a)...) + continue + } + out = append(out, a) + } + return out +} + +// allPackagesInFS is like allPackages but is passed a pattern +// beginning ./ or ../, meaning it should scan the tree rooted +// at the given directory. There are ... in the pattern too. +// $GOROOT/src/cmd/main.go:620 +func allPackagesInFS(pattern string) []string { + pkgs := matchPackagesInFS(pattern) + if len(pkgs) == 0 { + fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) + } + return pkgs +} + +// allPackages returns all the packages that can be found +// under the $GOPATH directories and $GOROOT matching pattern. +// The pattern is either "all" (all packages), "std" (standard packages), +// "cmd" (standard commands), or a path including "...". +// $GOROOT/src/cmd/main.go:542 +func allPackages(pattern string) []string { + pkgs := matchPackages(pattern) + if len(pkgs) == 0 { + fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) + } + return pkgs +} + +// $GOROOT/src/cmd/main.go:554 +// This has been changed to not use build.ImportDir +func matchPackages(pattern string) []string { + match := func(string) bool { return true } + treeCanMatch := func(string) bool { return true } + if pattern != "all" && pattern != "std" && pattern != "cmd" { + match = matchPattern(pattern) + treeCanMatch = treeCanMatchPattern(pattern) + } + + have := map[string]bool{ + "builtin": true, // ignore pseudo-package that exists only for documentation + } + if !build.Default.CgoEnabled { + have["runtime/cgo"] = true // ignore during walk + } + var pkgs []string + + for _, src := range build.Default.SrcDirs() { + if (pattern == "std" || pattern == "cmd") && src != gorootSrc { + continue + } + src = filepath.Clean(src) + string(filepath.Separator) + root := src + if pattern == "cmd" { + root += "cmd" + string(filepath.Separator) + } + filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { + if err != nil || !fi.IsDir() || path == src { + return nil + } + + // Avoid .foo, _foo, and testdata directory trees. + _, elem := filepath.Split(path) + if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { + return filepath.SkipDir + } + + name := filepath.ToSlash(path[len(src):]) + if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") { + // The name "std" is only the standard library. + // If the name has a dot, assume it's a domain name for go get, + // and if the name is cmd, it's the root of the command tree. + return filepath.SkipDir + } + if !treeCanMatch(name) { + return filepath.SkipDir + } + if have[name] { + return nil + } + have[name] = true + if !match(name) { + return nil + } + + ap, err := filepath.Abs(path) + if err != nil { + return nil + } + if _, err = fullPackageInDir(ap); err != nil { + debugf("matchPackage(%q) ap=%q Error: %q\n", ap, pattern, err) + if _, noGo := err.(*build.NoGoError); noGo { + return nil + } + } + pkgs = append(pkgs, name) + return nil + }) + } + return pkgs +} + +// treeCanMatchPattern(pattern)(name) reports whether +// name or children of name can possibly match pattern. +// Pattern is the same limited glob accepted by matchPattern. +// $GOROOT/src/cmd/main.go:527 +func treeCanMatchPattern(pattern string) func(name string) bool { + wildCard := false + if i := strings.Index(pattern, "..."); i >= 0 { + wildCard = true + pattern = pattern[:i] + } + return func(name string) bool { + return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || + wildCard && strings.HasPrefix(name, pattern) + } +} + +// hasPathPrefix reports whether the path s begins with the +// elements in prefix. +// $GOROOT/src/cmd/main.go:489 +func hasPathPrefix(s, prefix string) bool { + switch { + default: + return false + case len(s) == len(prefix): + return s == prefix + case len(s) > len(prefix): + if prefix != "" && prefix[len(prefix)-1] == '/' { + return strings.HasPrefix(s, prefix) + } + return s[len(prefix)] == '/' && s[:len(prefix)] == prefix + } +} + +// $GOROOT/src/cmd/go/main.go:631 +// This has been changed to not use build.ImportDir +func matchPackagesInFS(pattern string) []string { + // Find directory to begin the scan. + // Could be smarter but this one optimization + // is enough for now, since ... is usually at the + // end of a path. + i := strings.Index(pattern, "...") + dir, _ := pathpkg.Split(pattern[:i]) + + // pattern begins with ./ or ../. + // path.Clean will discard the ./ but not the ../. + // We need to preserve the ./ for pattern matching + // and in the returned import paths. + prefix := "" + if strings.HasPrefix(pattern, "./") { + prefix = "./" + } + match := matchPattern(pattern) + + var pkgs []string + filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { + if err != nil || !fi.IsDir() { + return nil + } + if path == dir { + // filepath.Walk starts at dir and recurses. For the recursive case, + // the path is the result of filepath.Join, which calls filepath.Clean. + // The initial case is not Cleaned, though, so we do this explicitly. + // + // This converts a path like "./io/" to "io". Without this step, running + // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io + // package, because prepending the prefix "./" to the unclean path would + // result in "././io", and match("././io") returns false. + path = filepath.Clean(path) + } + + // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". + _, elem := filepath.Split(path) + dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." + if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { + return filepath.SkipDir + } + + name := prefix + filepath.ToSlash(path) + if !match(name) { + return nil + } + ap, err := filepath.Abs(path) + if err != nil { + return nil + } + if _, err = fullPackageInDir(ap); err != nil { + debugf("matchPackageInFS(%q) ap=%q Error: %q\n", ap, pattern, err) + if _, noGo := err.(*build.NoGoError); !noGo { + log.Print(err) + } + return nil + } + pkgs = append(pkgs, name) + return nil + }) + return pkgs +} diff --git a/vendor/github.com/tools/godep/main.go b/vendor/github.com/tools/godep/main.go new file mode 100644 index 0000000000..284e7b42a6 --- /dev/null +++ b/vendor/github.com/tools/godep/main.go @@ -0,0 +1,255 @@ +package main + +import ( + "flag" + "fmt" + "go/build" + "io" + "log" + "os" + "path/filepath" + "runtime/pprof" + "strings" + "text/template" +) + +var ( + cpuprofile string + verbose bool // Verbose flag for commands that support it + debug bool // Debug flag for commands that support it + majorGoVersion string + VendorExperiment bool + sep string +) + +// Command is an implementation of a godep command +// like godep save or godep go. +type Command struct { + // Run runs the command. + // The args are the arguments after the command name. + Run func(cmd *Command, args []string) + + // Name of the command + Name string + + // Args the command would expect + Args string + + // Short is the short description shown in the 'godep help' output. + Short string + + // Long is the long message shown in the + // 'godep help ' output. + Long string + + // Flag is a set of flags specific to this command. + Flag flag.FlagSet + + // OnlyInGOPATH limits this command to being run only while inside of a GOPATH + OnlyInGOPATH bool +} + +// UsageExit prints usage information and exits. +func (c *Command) UsageExit() { + fmt.Fprintf(os.Stderr, "Args: godep %s [-v] [-d] %s\n\n", c.Name, c.Args) + fmt.Fprintf(os.Stderr, "Run 'godep help %s' for help.\n", c.Name) + os.Exit(2) +} + +// Commands lists the available commands and help topics. +// The order here is the order in which they are printed +// by 'godep help'. +var commands = []*Command{ + cmdSave, + cmdGo, + cmdGet, + cmdPath, + cmdRestore, + cmdUpdate, + cmdDiff, + cmdVersion, +} + +// VendorExperiment is the Go 1.5 vendor directory experiment flag, see +// https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff +// Honor the env var unless the project already has an old school godep workspace +func determineVendor(v string) bool { + go15ve := os.Getenv("GO15VENDOREXPERIMENT") + var ev bool + switch v { + case "go1", "go1.1", "go1.2", "go1.3", "go1.4": + ev = false + case "go1.5": + ev = go15ve == "1" + case "go1.6": + ev = go15ve != "0" + default: //go1.7+, devel* + ev = true + } + + ws := filepath.Join("Godeps", "_workspace") + s, err := os.Stat(ws) + if err == nil && s.IsDir() { + log.Printf("WARNING: Godep workspaces (./Godeps/_workspace) are deprecated and support for them will be removed when go1.8 is released.") + if ev { + log.Printf("WARNING: Go version (%s) & $GO15VENDOREXPERIMENT=%s wants to enable the vendor experiment, but disabling because a Godep workspace (%s) exists\n", v, go15ve, ws) + } + return false + } + + return ev +} + +func main() { + log.SetFlags(0) + log.SetPrefix("godep: ") + log.SetOutput(os.Stderr) + + flag.Usage = usageExit + flag.Parse() + args := flag.Args() + if len(args) < 1 { + usageExit() + } + + if args[0] == "help" { + help(args[1:]) + return + } + + var err error + majorGoVersion, err = goVersion() + if err != nil { + log.Fatal(err) + } + + for _, cmd := range commands { + if cmd.Name == args[0] { + if cmd.OnlyInGOPATH { + checkInGOPATH() + } + + VendorExperiment = determineVendor(majorGoVersion) + // sep is the signature set of path elements that + // precede the original path of an imported package. + sep = defaultSep(VendorExperiment) + + cmd.Flag.BoolVar(&verbose, "v", false, "enable verbose output") + cmd.Flag.BoolVar(&debug, "d", false, "enable debug output") + cmd.Flag.StringVar(&cpuprofile, "cpuprofile", "", "Write cpu profile to this file") + cmd.Flag.Usage = func() { cmd.UsageExit() } + cmd.Flag.Parse(args[1:]) + + debugln("versionString()", versionString()) + debugln("majorGoVersion", majorGoVersion) + debugln("VendorExperiment", VendorExperiment) + debugln("sep", sep) + + if cpuprofile != "" { + f, err := os.Create(cpuprofile) + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f) + defer pprof.StopCPUProfile() + } + cmd.Run(cmd, cmd.Flag.Args()) + return + } + } + + fmt.Fprintf(os.Stderr, "godep: unknown command %q\n", args[0]) + fmt.Fprintf(os.Stderr, "Run 'godep help' for usage.\n") + os.Exit(2) +} + +func subPath(sub, path string) bool { + ls := strings.ToLower(sub) + lp := strings.ToLower(path) + if ls == lp { + return false + } + return strings.HasPrefix(ls, lp) +} + +func checkInGOPATH() { + pwd, err := os.Getwd() + if err != nil { + log.Fatal("Unable to determine current working directory", err) + } + dirs := build.Default.SrcDirs() + for _, p := range dirs { + if ok := subPath(pwd, p); ok { + return + } + } + + log.Println("[WARNING]: godep should only be used inside a valid go package directory and") + log.Println("[WARNING]: may not function correctly. You are probably outside of your $GOPATH.") + log.Printf("[WARNING]:\tCurrent Directory: %s\n", pwd) + log.Printf("[WARNING]:\t$GOPATH: %s\n", os.Getenv("GOPATH")) +} + +var usageTemplate = ` +Godep is a tool for managing Go package dependencies. + +Usage: + + godep command [arguments] + +The commands are: +{{range .}} + {{.Name | printf "%-8s"}} {{.Short}}{{end}} + +Use "godep help [command]" for more information about a command. +` + +var helpTemplate = ` +Args: godep {{.Name}} [-v] [-d] {{.Args}} + +{{.Long | trim}} + +If -v is given, verbose output is enabled. + +If -d is given, debug output is enabled (you probably don't want this, see -v). + +` + +func help(args []string) { + if len(args) == 0 { + printUsage(os.Stdout) + return + } + if len(args) != 1 { + fmt.Fprintf(os.Stderr, "usage: godep help command\n\n") + fmt.Fprintf(os.Stderr, "Too many arguments given.\n") + os.Exit(2) + } + for _, cmd := range commands { + if cmd.Name == args[0] { + tmpl(os.Stdout, helpTemplate, cmd) + return + } + } +} + +func usageExit() { + printUsage(os.Stderr) + os.Exit(2) +} + +func printUsage(w io.Writer) { + tmpl(w, usageTemplate, commands) +} + +// tmpl executes the given template text on data, writing the result to w. +func tmpl(w io.Writer, text string, data interface{}) { + t := template.New("top") + t.Funcs(template.FuncMap{ + "trim": strings.TrimSpace, + }) + template.Must(t.Parse(strings.TrimSpace(text) + "\n\n")) + if err := t.Execute(w, data); err != nil { + panic(err) + } +} diff --git a/vendor/github.com/tools/godep/msg.go b/vendor/github.com/tools/godep/msg.go new file mode 100644 index 0000000000..4a6037824b --- /dev/null +++ b/vendor/github.com/tools/godep/msg.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "log" + + "github.com/kr/pretty" +) + +func debugln(a ...interface{}) (int, error) { + if debug { + return fmt.Println(a...) + } + return 0, nil +} + +func verboseln(a ...interface{}) { + if verbose { + log.Println(a...) + } +} + +func debugf(format string, a ...interface{}) (int, error) { + if debug { + return fmt.Printf(format, a...) + } + return 0, nil +} + +func verbosef(format string, a ...interface{}) { + if verbose { + log.Printf(format, a...) + } +} + +func pp(a ...interface{}) (int, error) { + if debug { + return pretty.Print(a...) + } + return 0, nil +} + +func ppln(a ...interface{}) (int, error) { + if debug { + return pretty.Println(a...) + } + return 0, nil +} + +func ppf(format string, a ...interface{}) (int, error) { + if debug { + return pretty.Printf(format, a...) + } + return 0, nil +} diff --git a/vendor/github.com/tools/godep/path.go b/vendor/github.com/tools/godep/path.go new file mode 100644 index 0000000000..c8e1f9f5b7 --- /dev/null +++ b/vendor/github.com/tools/godep/path.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "os" +) + +var cmdPath = &Command{ + Name: "path", + Short: "print GOPATH for dependency code", + Long: ` +Command path prints a path for use in env var GOPATH +that makes available the specified version of each dependency. + +The printed path does not include any GOPATH value from +the environment. + +For more about how GOPATH works, see 'go help gopath'. +`, + Run: runPath, + OnlyInGOPATH: true, +} + +// Print the gopath that points to +// the included dependency code. +func runPath(cmd *Command, args []string) { + if len(args) != 0 { + cmd.UsageExit() + } + if VendorExperiment { + fmt.Fprintln(os.Stderr, "Error: GO15VENDOREXPERIMENT is enabled and the vendor/ directory is not a valid Go workspace.") + os.Exit(1) + } + gopath := prepareGopath() + fmt.Println(gopath) +} diff --git a/vendor/github.com/tools/godep/pkg.go b/vendor/github.com/tools/godep/pkg.go new file mode 100644 index 0000000000..b19d5f9b0a --- /dev/null +++ b/vendor/github.com/tools/godep/pkg.go @@ -0,0 +1,81 @@ +package main + +import ( + "go/build" + "regexp" + "strings" +) + +// Package represents a Go package. +type Package struct { + Dir string + Root string + ImportPath string + Deps []string + Standard bool + Processed bool + + GoFiles []string + CgoFiles []string + IgnoredGoFiles []string + + TestGoFiles []string + TestImports []string + XTestGoFiles []string + XTestImports []string + + Error struct { + Err string + } + + // --- New stuff for now + Imports []string + Dependencies []build.Package +} + +// LoadPackages loads the named packages +// Unlike the go tool, an empty argument list is treated as an empty list; "." +// must be given explicitly if desired. +// IgnoredGoFiles will be processed and their dependencies resolved recursively +func LoadPackages(names ...string) (a []*Package, err error) { + debugln("LoadPackages", names) + if len(names) == 0 { + return nil, nil + } + for _, i := range importPaths(names) { + p, err := listPackage(i) + if err != nil { + return nil, err + } + a = append(a, p) + } + return a, nil +} + +func (p *Package) allGoFiles() []string { + var a []string + a = append(a, p.GoFiles...) + a = append(a, p.CgoFiles...) + a = append(a, p.TestGoFiles...) + a = append(a, p.XTestGoFiles...) + a = append(a, p.IgnoredGoFiles...) + return a +} + +// matchPattern(pattern)(name) reports whether +// name matches pattern. Pattern is a limited glob +// pattern in which '...' means 'any string' and there +// is no other special syntax. +// Taken from $GOROOT/src/cmd/go/main.go. +func matchPattern(pattern string) func(name string) bool { + re := regexp.QuoteMeta(pattern) + re = strings.Replace(re, `\.\.\.`, `.*`, -1) + // Special case: foo/... matches foo too. + if strings.HasSuffix(re, `/.*`) { + re = re[:len(re)-len(`/.*`)] + `(/.*)?` + } + reg := regexp.MustCompile(`^` + re + `$`) + return func(name string) bool { + return reg.MatchString(name) + } +} diff --git a/vendor/github.com/tools/godep/restore.go b/vendor/github.com/tools/godep/restore.go new file mode 100644 index 0000000000..9de53e022b --- /dev/null +++ b/vendor/github.com/tools/godep/restore.go @@ -0,0 +1,195 @@ +package main + +import ( + "errors" + "go/build" + "log" + "os" + "path/filepath" + + "golang.org/x/tools/go/vcs" +) + +var cmdRestore = &Command{ + Name: "restore", + Short: "check out listed dependency versions in GOPATH", + Long: ` +Restore checks out the Godeps-specified version of each package in GOPATH. + +NOTE: restore leaves git repositories in a detached state. go1.6+ no longer +checks out the master branch when doing a "go get", see: +https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669. + +`, + Run: runRestore, + OnlyInGOPATH: true, +} + +// Three phases: +// 1. Download all deps +// 2. Restore all deps (checkout the recorded rev) +// 3. Attempt to load all deps as a simple consistency check +func runRestore(cmd *Command, args []string) { + if len(build.Default.GOPATH) == 0 { + log.Println("Error restore requires GOPATH but it is empty.") + os.Exit(1) + } + + var hadError bool + checkErr := func(s string) { + if hadError { + log.Println(s) + os.Exit(1) + } + } + + g, err := loadDefaultGodepsFile() + if err != nil { + log.Fatalln(err) + } + for i, dep := range g.Deps { + verboseln("Downloading dependency (if needed):", dep.ImportPath) + err := download(&dep) + if err != nil { + log.Printf("error downloading dep (%s): %s\n", dep.ImportPath, err) + hadError = true + } + g.Deps[i] = dep + } + checkErr("Error downloading some deps. Aborting restore and check.") + for _, dep := range g.Deps { + verboseln("Restoring dependency (if needed):", dep.ImportPath) + err := restore(dep) + if err != nil { + log.Printf("error restoring dep (%s): %s\n", dep.ImportPath, err) + hadError = true + } + } + checkErr("Error restoring some deps. Aborting check.") + for _, dep := range g.Deps { + verboseln("Checking dependency:", dep.ImportPath) + _, err := LoadPackages(dep.ImportPath) + if err != nil { + log.Printf("Dep (%s) restored, but was unable to load it with error:\n\t%s\n", dep.ImportPath, err) + if me, ok := err.(errorMissingDep); ok { + log.Println("\tThis may be because the dependencies were saved with an older version of godep (< v33).") + log.Printf("\tTry `go get %s`. Then `godep save` to update deps.\n", me.i) + } + hadError = true + } + } + checkErr("Error checking some deps.") +} + +var downloaded = make(map[string]bool) + +// download the given dependency. +// 2 Passes: 1) go get -d , 2) git pull (if necessary) +func download(dep *Dependency) error { + + rr, err := vcs.RepoRootForImportPath(dep.ImportPath, debug) + if err != nil { + debugln("Error determining repo root for", dep.ImportPath) + return err + } + ppln("rr", rr) + + dep.vcs = cmd[rr.VCS] + + // try to find an existing directory in the GOPATHs + for _, gp := range filepath.SplitList(build.Default.GOPATH) { + t := filepath.Join(gp, "src", rr.Root) + fi, err := os.Stat(t) + if err != nil { + continue + } + if fi.IsDir() { + dep.root = t + break + } + } + + // If none found, just pick the first GOPATH entry (AFAICT that's what go get does) + if dep.root == "" { + dep.root = filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src", rr.Root) + } + ppln("dep", dep) + + if downloaded[rr.Repo] { + verboseln("Skipping already downloaded repo", rr.Repo) + return nil + } + + fi, err := os.Stat(dep.root) + if err != nil { + if os.IsNotExist(err) { + if err := os.MkdirAll(filepath.Dir(dep.root), os.ModePerm); err != nil { + debugln("Error creating base dir of", dep.root) + return err + } + err := rr.VCS.CreateAtRev(dep.root, rr.Repo, dep.Rev) + debugln("CreatedAtRev", dep.root, rr.Repo, dep.Rev) + if err != nil { + debugln("CreateAtRev error", err) + return err + } + downloaded[rr.Repo] = true + return nil + } + debugln("Error checking repo root for", dep.ImportPath, "at", dep.root, ":", err) + return err + } + + if !fi.IsDir() { + return errors.New("repo root src dir exists, but isn't a directory for " + dep.ImportPath + " at " + dep.root) + } + + if !dep.vcs.exists(dep.root, dep.Rev) { + debugln("Updating existing", dep.root) + if dep.vcs == vcsGit { + detached, err := gitDetached(dep.root) + if err != nil { + return err + } + if detached { + db, err := gitDefaultBranch(dep.root) + if err != nil { + return err + } + if err := gitCheckout(dep.root, db); err != nil { + return err + } + } + } + + dep.vcs.vcs.Download(dep.root) + downloaded[rr.Repo] = true + } + + debugln("Nothing to download") + return nil +} + +var restored = make(map[string]string) // dep.root -> dep.Rev + +// restore checks out the given revision. +func restore(dep Dependency) error { + rev, ok := restored[dep.root] + debugln(rev) + debugln(ok) + debugln(dep.root) + if ok { + if rev != dep.Rev { + return errors.New("Wanted to restore rev " + dep.Rev + ", already restored rev " + rev + " for another package in the repo") + } + verboseln("Skipping already restored repo") + return nil + } + + debugln("Restoring:", dep.ImportPath, dep.Rev) + err := dep.vcs.RevSync(dep.root, dep.Rev) + if err == nil { + restored[dep.root] = dep.Rev + } + return err +} diff --git a/vendor/github.com/tools/godep/rewrite.go b/vendor/github.com/tools/godep/rewrite.go new file mode 100644 index 0000000000..c4c859492a --- /dev/null +++ b/vendor/github.com/tools/godep/rewrite.go @@ -0,0 +1,168 @@ +package main + +import ( + "bytes" + "log" + "os" + "path/filepath" + "strconv" + "strings" + + "go/ast" + "go/parser" + "go/printer" + "go/token" + + "github.com/kr/fs" +) + +// rewrite visits the go files in pkgs, plus all go files +// in the directory tree Godeps, rewriting import statements +// according to the rules for func qualify. +func rewrite(pkgs []*Package, qual string, paths []string) error { + for _, path := range pkgFiles(pkgs) { + debugln("rewrite", path) + err := rewriteTree(path, qual, paths) + if err != nil { + return err + } + } + return rewriteTree("Godeps", qual, paths) +} + +// pkgFiles returns the full filesystem path to all go files in pkgs. +func pkgFiles(pkgs []*Package) []string { + var a []string + for _, pkg := range pkgs { + for _, s := range pkg.allGoFiles() { + a = append(a, filepath.Join(pkg.Dir, s)) + } + } + return a +} + +// rewriteTree recursively visits the go files in path, rewriting +// import statements according to the rules for func qualify. +// This function ignores the 'testdata' directory. +func rewriteTree(path, qual string, paths []string) error { + w := fs.Walk(path) + for w.Step() { + if w.Err() != nil { + log.Println("rewrite:", w.Err()) + continue + } + s := w.Stat() + if s.IsDir() && s.Name() == "testdata" { + w.SkipDir() + continue + } + if strings.HasSuffix(w.Path(), ".go") { + err := rewriteGoFile(w.Path(), qual, paths) + if err != nil { + return err + } + } + } + return nil +} + +// rewriteGoFile rewrites import statements in the named file +// according to the rules for func qualify. +func rewriteGoFile(name, qual string, paths []string) error { + debugln("rewriteGoFile", name, ",", qual, ",", paths) + printerConfig := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8} + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, name, nil, parser.ParseComments) + if err != nil { + return err + } + + var changed bool + for _, s := range f.Imports { + name, err := strconv.Unquote(s.Path.Value) + if err != nil { + return err // can't happen + } + q := qualify(unqualify(name), qual, paths) + if q != name { + s.Path.Value = strconv.Quote(q) + changed = true + } + } + if !changed { + return nil + } + var buffer bytes.Buffer + if err = printerConfig.Fprint(&buffer, fset, f); err != nil { + return err + } + fset = token.NewFileSet() + f, err = parser.ParseFile(fset, name, &buffer, parser.ParseComments) + ast.SortImports(fset, f) + tpath := name + ".temp" + t, err := os.Create(tpath) + if err != nil { + return err + } + if err = printerConfig.Fprint(t, fset, f); err != nil { + return err + } + if err = t.Close(); err != nil { + return err + } + // This is required before the rename on windows. + if err = os.Remove(name); err != nil { + return err + } + return os.Rename(tpath, name) +} + +func defaultSep(experiment bool) string { + if experiment { + return "/vendor/" + } + return "/Godeps/_workspace/src/" +} + +func relativeVendorTarget(experiment bool) string { + full := defaultSep(experiment) + if full[0] == '/' { + full = full[1:] + } + return filepath.FromSlash(full) +} + +// unqualify returns the part of importPath after the last +// occurrence of the signature path elements +// (Godeps/_workspace/src) that always precede imported +// packages in rewritten import paths. +// +// For example, +// unqualify(C) = C +// unqualify(D/Godeps/_workspace/src/C) = C +func unqualify(importPath string) string { + if i := strings.LastIndex(importPath, sep); i != -1 { + importPath = importPath[i+len(sep):] + } + return importPath +} + +// qualify qualifies importPath with its corresponding import +// path in the Godeps src copy of package pkg. If importPath +// is a directory lexically contained in a path in paths, +// it will be qualified with package pkg; otherwise, it will +// be returned unchanged. +// +// For example, given paths {D, T} and pkg C, +// importPath returns +// C C +// fmt fmt +// D C/Godeps/_workspace/src/D +// D/P C/Godeps/_workspace/src/D/P +// T C/Godeps/_workspace/src/T +func qualify(importPath, pkg string, paths []string) string { + if containsPathPrefix(paths, importPath) { + return pkg + sep + importPath + } + return importPath +} diff --git a/vendor/github.com/tools/godep/save.go b/vendor/github.com/tools/godep/save.go new file mode 100644 index 0000000000..ff0891a8f0 --- /dev/null +++ b/vendor/github.com/tools/godep/save.go @@ -0,0 +1,612 @@ +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "go/build" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/kr/fs" +) + +var cmdSave = &Command{ + Name: "save", + Args: "[-r] [-t] [packages]", + Short: "list and copy dependencies into Godeps", + Long: ` + +Save writes a list of the named packages and their dependencies along +with the exact source control revision of each package, and copies +their source code into a subdirectory. Packages inside "." are excluded +from the list to be copied. + +The list is written to Godeps/Godeps.json, and source code for all +dependencies is copied into either Godeps/_workspace or, if the vendor +experiment is turned on, vendor/. + +The dependency list is a JSON document with the following structure: + + type Godeps struct { + ImportPath string + GoVersion string // Abridged output of 'go version'. + Packages []string // Arguments to godep save, if any. + Deps []struct { + ImportPath string + Comment string // Tag or description of commit. + Rev string // VCS-specific commit ID. + } + } + +Any packages already present in the list will be left unchanged. +To update a dependency to a newer revision, use 'godep update'. + +If -r is given, import statements will be rewritten to refer directly +to the copied source code. This is not compatible with the vendor +experiment. Note that this will not rewrite the statements in the +files outside the project. + +If -t is given, test files (*_test.go files + testdata directories) are +also saved. + +For more about specifying packages, see 'go help packages'. +`, + Run: runSave, + OnlyInGOPATH: true, +} + +var ( + saveR, saveT bool +) + +func init() { + cmdSave.Flag.BoolVar(&saveR, "r", false, "rewrite import paths") + cmdSave.Flag.BoolVar(&saveT, "t", false, "save test files") + +} + +func runSave(cmd *Command, args []string) { + if VendorExperiment && saveR { + log.Println("flag -r is incompatible with the vendoring experiment") + cmd.UsageExit() + } + err := save(args) + if err != nil { + log.Fatalln(err) + } +} + +func dotPackage() (*build.Package, error) { + dir, err := filepath.Abs(".") + if err != nil { + return nil, err + } + return build.ImportDir(dir, build.FindOnly) +} + +func projectPackages(dDir string, a []*Package) []*Package { + var projPkgs []*Package + dotDir := fmt.Sprintf("%s%c", dDir, filepath.Separator) + for _, p := range a { + pkgDir := fmt.Sprintf("%s%c", p.Dir, filepath.Separator) + if strings.HasPrefix(pkgDir, dotDir) { + projPkgs = append(projPkgs, p) + } + } + return projPkgs +} + +func save(pkgs []string) error { + var err error + dp, err := dotPackage() + if err != nil { + return err + } + debugln("dotPackageImportPath:", dp.ImportPath) + debugln("dotPackageDir:", dp.Dir) + + cv, err := goVersion() + if err != nil { + return err + } + verboseln("Go Version:", cv) + + gold, err := loadDefaultGodepsFile() + if err != nil { + if !os.IsNotExist(err) { + return err + } + verboseln("No old Godeps.json found.") + gold.GoVersion = cv + } + + printVersionWarnings(gold.GoVersion) + if len(gold.GoVersion) == 0 { + gold.GoVersion = majorGoVersion + } else { + majorGoVersion, err = trimGoVersion(gold.GoVersion) + if err != nil { + log.Fatalf("Unable to determine go major version from value specified in %s: %s\n", gold.file(), gold.GoVersion) + } + } + + gnew := &Godeps{ + ImportPath: dp.ImportPath, + GoVersion: gold.GoVersion, + } + + switch len(pkgs) { + case 0: + pkgs = []string{"."} + default: + gnew.Packages = pkgs + } + + verboseln("Finding dependencies for", pkgs) + a, err := LoadPackages(pkgs...) + if err != nil { + return err + } + + for _, p := range a { + verboseln("Found package:", p.ImportPath) + verboseln("\tDeps:", strings.Join(p.Deps, " ")) + } + ppln(a) + + projA := projectPackages(dp.Dir, a) + debugln("Filtered projectPackages") + ppln(projA) + + verboseln("Computing new Godeps.json file") + err = gnew.fill(a, dp.ImportPath) + if err != nil { + return err + } + debugln("New Godeps Filled") + ppln(gnew) + + if gnew.Deps == nil { + gnew.Deps = make([]Dependency, 0) // produce json [], not null + } + gdisk := gnew.copy() + err = carryVersions(&gold, gnew) + if err != nil { + return err + } + + if gold.isOldFile { + // If we are migrating from an old format file, + // we require that the listed version of every + // dependency must be installed in GOPATH, so it's + // available to copy. + if !eqDeps(gnew.Deps, gdisk.Deps) { + return errors.New(strings.TrimSpace(needRestore)) + } + gold = Godeps{} + } + os.Remove("Godeps") // remove regular file if present; ignore error + readme := filepath.Join("Godeps", "Readme") + err = writeFile(readme, strings.TrimSpace(Readme)+"\n") + if err != nil { + log.Println(err) + } + _, err = gnew.save() + if err != nil { + return err + } + + verboseln("Computing diff between old and new deps") + // We use a name starting with "_" so the go tool + // ignores this directory when traversing packages + // starting at the project's root. For example, + // godep go list ./... + srcdir := filepath.FromSlash(strings.Trim(sep, "/")) + rem := subDeps(gold.Deps, gnew.Deps) + ppln(rem) + add := subDeps(gnew.Deps, gold.Deps) + ppln(add) + if len(rem) > 0 { + verboseln("Deps to remove:") + for _, r := range rem { + verboseln("\t", r.ImportPath) + } + verboseln("Removing unused dependencies") + err = removeSrc(srcdir, rem) + if err != nil { + return err + } + } + if len(add) > 0 { + verboseln("Deps to add:") + for _, a := range add { + verboseln("\t", a.ImportPath) + } + verboseln("Adding new dependencies") + err = copySrc(srcdir, add) + if err != nil { + return err + } + } + if !VendorExperiment { + f, _ := filepath.Split(srcdir) + writeVCSIgnore(f) + } + var rewritePaths []string + if saveR { + for _, dep := range gnew.Deps { + rewritePaths = append(rewritePaths, dep.ImportPath) + } + } + verboseln("Rewriting paths (if necessary)") + ppln(rewritePaths) + return rewrite(projA, dp.ImportPath, rewritePaths) +} + +func printVersionWarnings(ov string) { + var warning bool + cv, err := goVersion() + if err != nil { + return + } + // Trim the old version because we may have saved it w/o trimming it + // cv is already trimmed by goVersion() + tov, err := trimGoVersion(ov) + if err != nil { + return + } + + if tov != ov { + log.Printf("WARNING: Recorded go version (%s) with minor version string found.\n", ov) + warning = true + } + if cv != tov { + log.Printf("WARNING: Recorded major go version (%s) and in-use major go version (%s) differ.\n", tov, cv) + warning = true + } + if warning { + log.Println("To record current major go version run `godep update -goversion`.") + } +} + +type revError struct { + ImportPath string + WantRev string + HavePath string + HaveRev string +} + +func (v *revError) Error() string { + return fmt.Sprintf("cannot save %s at revision %s: already have %s at revision %s.\n"+ + "Run `godep update %s' first.", v.ImportPath, v.WantRev, v.HavePath, v.HaveRev, v.HavePath) +} + +// carryVersions copies Rev and Comment from a to b for +// each dependency with an identical ImportPath. For any +// dependency in b that appears to be from the same repo +// as one in a (for example, a parent or child directory), +// the Rev must already match - otherwise it is an error. +func carryVersions(a, b *Godeps) error { + for i := range b.Deps { + err := carryVersion(a, &b.Deps[i]) + if err != nil { + return err + } + } + return nil +} + +func carryVersion(a *Godeps, db *Dependency) error { + // First see if this exact package is already in the list. + for _, da := range a.Deps { + if db.ImportPath == da.ImportPath { + db.Rev = da.Rev + db.Comment = da.Comment + return nil + } + } + // No exact match, check for child or sibling package. + // We can't handle mismatched versions for packages in + // the same repo, so report that as an error. + for _, da := range a.Deps { + if strings.HasPrefix(db.ImportPath, da.ImportPath+"/") || + strings.HasPrefix(da.ImportPath, db.root+"/") { + if da.Rev != db.Rev { + return &revError{ + ImportPath: db.ImportPath, + WantRev: db.Rev, + HavePath: da.ImportPath, + HaveRev: da.Rev, + } + } + } + } + // No related package in the list, must be a new repo. + return nil +} + +// subDeps returns a - b, using ImportPath for equality. +func subDeps(a, b []Dependency) (diff []Dependency) { +Diff: + for _, da := range a { + for _, db := range b { + if da.ImportPath == db.ImportPath { + continue Diff + } + } + diff = append(diff, da) + } + return diff +} + +func removeSrc(srcdir string, deps []Dependency) error { + for _, dep := range deps { + path := filepath.FromSlash(dep.ImportPath) + err := os.RemoveAll(filepath.Join(srcdir, path)) + if err != nil { + return err + } + } + return nil +} + +func copySrc(dir string, deps []Dependency) error { + // mapping to see if we visited a parent directory already + visited := make(map[string]bool) + ok := true + for _, dep := range deps { + debugln("copySrc for", dep.ImportPath) + srcdir := filepath.Join(dep.ws, "src") + rel, err := filepath.Rel(srcdir, dep.dir) + debugln("srcdir", srcdir) + debugln("rel", rel) + debugln("err", err) + if err != nil { // this should never happen + return err + } + dstpkgroot := filepath.Join(dir, rel) + err = os.RemoveAll(dstpkgroot) + if err != nil { + log.Println(err) + ok = false + } + + // copy actual dependency + vf := dep.vcs.listFiles(dep.dir) + debugln("vf", vf) + w := fs.Walk(dep.dir) + for w.Step() { + err = copyPkgFile(vf, dir, srcdir, w) + if err != nil { + log.Println(err) + ok = false + } + } + + // Look for legal files in root + // some packages are imports as a sub-package but license info + // is at root: exampleorg/common has license file in exampleorg + // + if dep.ImportPath == dep.root { + // we are already at root + continue + } + + // prevent copying twice This could happen if we have + // two subpackages listed someorg/common and + // someorg/anotherpack which has their license in + // the parent dir of someorg + rootdir := filepath.Join(srcdir, filepath.FromSlash(dep.root)) + if visited[rootdir] { + continue + } + visited[rootdir] = true + vf = dep.vcs.listFiles(rootdir) + w = fs.Walk(rootdir) + for w.Step() { + fname := filepath.Base(w.Path()) + if IsLegalFile(fname) && !strings.Contains(w.Path(), sep) { + err = copyPkgFile(vf, dir, srcdir, w) + if err != nil { + log.Println(err) + ok = false + } + } + } + } + + if !ok { + return errorCopyingSourceCode + } + + return nil +} + +func copyPkgFile(vf vcsFiles, dstroot, srcroot string, w *fs.Walker) error { + if w.Err() != nil { + return w.Err() + } + name := w.Stat().Name() + if w.Stat().IsDir() { + if name[0] == '.' || name[0] == '_' || (!saveT && name == "testdata") { + // Skip directories starting with '.' or '_' or + // 'testdata' (last is only skipped if saveT is false) + w.SkipDir() + } + return nil + } + rel, err := filepath.Rel(srcroot, w.Path()) + if err != nil { // this should never happen + return err + } + if !saveT && strings.HasSuffix(name, "_test.go") { + if verbose { + log.Printf("save: skipping test file: %s", w.Path()) + } + return nil + } + if !vf.Contains(w.Path()) { + if verbose { + log.Printf("save: skipping untracked file: %s", w.Path()) + } + return nil + } + return copyFile(filepath.Join(dstroot, rel), w.Path()) +} + +// copyFile copies a regular file from src to dst. +// dst is opened with os.Create. +// If the file name ends with .go, +// copyFile strips canonical import path annotations. +// These are comments of the form: +// package foo // import "bar/foo" +// package foo /* import "bar/foo" */ +func copyFile(dst, src string) error { + err := os.MkdirAll(filepath.Dir(dst), 0777) + if err != nil { + return err + } + + linkDst, err := os.Readlink(src) + if err == nil { + return os.Symlink(linkDst, dst) + } + + si, err := stat(src) + if err != nil { + return err + } + + r, err := os.Open(src) + if err != nil { + return err + } + defer r.Close() + + w, err := os.Create(dst) + if err != nil { + return err + } + if err := os.Chmod(dst, si.Mode()); err != nil { + return err + } + + if strings.HasSuffix(dst, ".go") { + debugln("Copy Without Import Comment", w, r) + err = copyWithoutImportComment(w, r) + } else { + debugln("Copy (plain)", w, r) + _, err = io.Copy(w, r) + } + err1 := w.Close() + if err == nil { + err = err1 + } + + return err +} + +func copyWithoutImportComment(w io.Writer, r io.Reader) error { + b := bufio.NewReader(r) + for { + l, err := b.ReadBytes('\n') + eof := err == io.EOF + if err != nil && err != io.EOF { + return err + } + + // If we have data then write it out... + if len(l) > 0 { + // Strip off \n if it exists because stripImportComment + _, err := w.Write(append(stripImportComment(bytes.TrimRight(l, "\n")), '\n')) + if err != nil { + return err + } + } + + if eof { + return nil + } + } +} + +const ( + importAnnotation = `import\s+(?:"[^"]*"|` + "`[^`]*`" + `)` + importComment = `(?://\s*` + importAnnotation + `\s*$|/\*\s*` + importAnnotation + `\s*\*/)` +) + +var ( + importCommentRE = regexp.MustCompile(`^\s*(package\s+\w+)\s+` + importComment + `(.*)`) + pkgPrefix = []byte("package ") +) + +// stripImportComment returns line with its import comment removed. +// If s is not a package statement containing an import comment, +// it is returned unaltered. +// FIXME: expects lines w/o a \n at the end +// See also http://golang.org/s/go14customimport. +func stripImportComment(line []byte) []byte { + if !bytes.HasPrefix(line, pkgPrefix) { + // Fast path; this will skip all but one line in the file. + // This assumes there is no whitespace before the keyword. + return line + } + if m := importCommentRE.FindSubmatch(line); m != nil { + return append(m[1], m[2]...) + } + return line +} + +// Func writeVCSIgnore writes "ignore" files inside dir for known VCSs, +// so that dir/pkg and dir/bin don't accidentally get committed. +// It logs any errors it encounters. +func writeVCSIgnore(dir string) { + // Currently git is the only VCS for which we know how to do this. + // Mercurial and Bazaar have similar mechanisms, but they apparently + // require writing files outside of dir. + const ignore = "/pkg\n/bin\n" + name := filepath.Join(dir, ".gitignore") + err := writeFile(name, ignore) + if err != nil { + log.Println(err) + } +} + +// writeFile is like ioutil.WriteFile but it creates +// intermediate directories with os.MkdirAll. +func writeFile(name, body string) error { + err := os.MkdirAll(filepath.Dir(name), 0777) + if err != nil { + return err + } + return ioutil.WriteFile(name, []byte(body), 0666) +} + +const ( + // Readme contains the README text. + Readme = ` +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. +` + needRestore = ` +mismatched versions while migrating + +It looks like you are switching from the old Godeps format +(from flag -copy=false). The old format is just a file; it +doesn't contain source code. For this migration, godep needs +the appropriate version of each dependency to be installed in +GOPATH, so that the source code is available to copy. + +To fix this, run 'godep restore'. +` +) diff --git a/vendor/github.com/tools/godep/update.go b/vendor/github.com/tools/godep/update.go new file mode 100644 index 0000000000..129be3f7bc --- /dev/null +++ b/vendor/github.com/tools/godep/update.go @@ -0,0 +1,292 @@ +package main + +import ( + "go/parser" + "go/token" + "log" + "os" + "path" + "path/filepath" + "strconv" + "strings" +) + +var cmdUpdate = &Command{ + Name: "update", + Args: "[-goversion] [packages]", + Short: "update selected packages or the go version", + Long: ` +Update changes the named dependency packages to use the +revision of each currently installed in GOPATH. New code will +be copied into the Godeps workspace or vendor folder and the +new revision will be written to the manifest. + +If -goversion is specified, update the recorded go version. + +For more about specifying packages, see 'go help packages'. +`, + Run: runUpdate, + OnlyInGOPATH: true, +} + +var ( + updateGoVer bool +) + +func init() { + cmdUpdate.Flag.BoolVar(&saveT, "t", false, "save test files during update") + cmdUpdate.Flag.BoolVar(&updateGoVer, "goversion", false, "update the recorded go version") +} + +func runUpdate(cmd *Command, args []string) { + if updateGoVer { + err := updateGoVersion() + if err != nil { + log.Fatalln(err) + } + } + if len(args) > 0 { + err := update(args) + if err != nil { + log.Fatalln(err) + } + } +} + +func updateGoVersion() error { + gold, err := loadDefaultGodepsFile() + if err != nil { + if !os.IsNotExist(err) { + return err + } + } + cv, err := goVersion() + if err != nil { + return err + } + + gv := gold.GoVersion + gold.GoVersion = cv + _, err = gold.save() + if err != nil { + return err + } + + if gv != cv { + log.Println("Updated major go version to", cv) + } + return nil + +} + +func update(args []string) error { + if len(args) == 0 { + args = []string{"."} + } + g, err := loadDefaultGodepsFile() + if err != nil { + return err + } + for _, arg := range args { + arg := path.Clean(arg) + any := markMatches(arg, g.Deps) + if !any { + log.Println("not in manifest:", arg) + } + } + deps, rdeps, err := LoadVCSAndUpdate(g.Deps) + if err != nil { + return err + } + if len(deps) == 0 { + return errorNoPackagesUpdatable + } + g.addOrUpdateDeps(deps) + g.removeDeps(rdeps) + if _, err = g.save(); err != nil { + return err + } + + srcdir := relativeVendorTarget(VendorExperiment) + if err := removeSrc(filepath.FromSlash(strings.Trim(sep, "/")), rdeps); err != nil { + return err + } + copySrc(srcdir, deps) + + ok, err := needRewrite(g.Packages) + if err != nil { + return err + } + var rewritePaths []string + if ok { + for _, dep := range g.Deps { + rewritePaths = append(rewritePaths, dep.ImportPath) + } + } + return rewrite(nil, g.ImportPath, rewritePaths) +} + +func needRewrite(importPaths []string) (bool, error) { + if len(importPaths) == 0 { + importPaths = []string{"."} + } + a, err := LoadPackages(importPaths...) + if err != nil { + return false, err + } + for _, p := range a { + for _, name := range p.allGoFiles() { + path := filepath.Join(p.Dir, name) + hasSep, err := hasRewrittenImportStatement(path) + if err != nil { + return false, err + } + if hasSep { + return true, nil + } + } + } + return false, nil +} + +func hasRewrittenImportStatement(path string) (bool, error) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, path, nil, 0) + if err != nil { + return false, err + } + for _, s := range f.Imports { + name, _ := strconv.Unquote(s.Path.Value) + if strings.Contains(name, sep) { + return true, nil + } + } + return false, nil +} + +// markMatches marks each entry in deps with an import path that +// matches pat. It returns whether any matches occurred. +func markMatches(pat string, deps []Dependency) (matched bool) { + f := matchPattern(pat) + for i, dep := range deps { + if f(dep.ImportPath) { + deps[i].matched = true + matched = true + } + } + return matched +} + +func fillDeps(deps []Dependency) ([]Dependency, error) { + for i := range deps { + if deps[i].pkg != nil { + continue + } + ps, err := LoadPackages(deps[i].ImportPath) + if err != nil { + if _, ok := err.(errPackageNotFound); ok { + deps[i].missing = true + continue + } + return nil, err + } + if len(ps) > 1 { + panic("More than one package found for " + deps[i].ImportPath) + } + p := ps[0] + deps[i].pkg = p + deps[i].dir = p.Dir + deps[i].ws = p.Root + + vcs, reporoot, err := VCSFromDir(p.Dir, filepath.Join(p.Root, "src")) + if err != nil { + return nil, errorLoadingDeps + } + deps[i].root = filepath.ToSlash(reporoot) + deps[i].vcs = vcs + } + + return deps, nil +} + +// LoadVCSAndUpdate loads and updates a set of dependencies. +func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, []Dependency, error) { + var err1 error + + deps, err := fillDeps(deps) + if err != nil { + return nil, nil, err + } + + repoMask := make(map[string]bool) + for i := range deps { + if !deps[i].matched { + repoMask[deps[i].root] = true + } + } + + // Determine if we need any new packages because of new transitive imports + for _, dep := range deps { + if !dep.matched || dep.missing { + continue + } + for _, dp := range dep.pkg.Dependencies { + if dp.Goroot { + continue + } + var have bool + for _, d := range deps { + if d.ImportPath == dp.ImportPath { + have = true + break + } + } + if !have { + deps = append(deps, Dependency{ImportPath: dp.ImportPath, matched: true}) + } + } + } + + deps, err = fillDeps(deps) + if err != nil { + return nil, nil, err + } + + var toUpdate, toRemove []Dependency + for _, d := range deps { + if !d.matched || repoMask[d.root] { + continue + } + if d.missing { + toRemove = append(toRemove, d) + continue + } + toUpdate = append(toUpdate, d) + } + + debugln("toUpdate") + ppln(toUpdate) + + var toCopy []Dependency + for _, d := range toUpdate { + id, err := d.vcs.identify(d.dir) + if err != nil { + log.Println(err) + err1 = errorLoadingDeps + continue + } + if d.vcs.isDirty(d.dir, id) { + log.Println("dirty working tree (please commit changes):", d.dir) + } + d.Rev = id + d.Comment = d.vcs.describe(d.dir, id) + toCopy = append(toCopy, d) + } + debugln("toCopy") + ppln(toCopy) + + if err1 != nil { + return nil, nil, err1 + } + return toCopy, toRemove, nil +} diff --git a/vendor/github.com/tools/godep/util.go b/vendor/github.com/tools/godep/util.go new file mode 100644 index 0000000000..df5978645a --- /dev/null +++ b/vendor/github.com/tools/godep/util.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +// Runs a command in dir. +// The name and args are as in exec.Command. +// Stdout, stderr, and the environment are inherited +// from the current process. +func runIn(dir, name string, args ...string) error { + _, err := runInWithOutput(dir, name, args...) + return err +} + +func runInWithOutput(dir, name string, args ...string) (string, error) { + c := exec.Command(name, args...) + c.Dir = dir + o, err := c.CombinedOutput() + + if debug { + fmt.Printf("execute: %+v\n", c) + fmt.Printf(" output: %s\n", string(o)) + } + + return string(o), err +} + +// driveLetterToUpper converts Windows path's drive letters to uppercase. This +// is needed when comparing 2 paths with different drive letter case. +func driveLetterToUpper(path string) string { + if runtime.GOOS != "windows" || path == "" { + return path + } + + p := path + + // If path's drive letter is lowercase, change it to uppercase. + if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' { + p = string(p[0]+'A'-'a') + p[1:] + } + + return p +} + +// clean the path and ensure that a drive letter is upper case (if it exists). +func cleanPath(path string) string { + return driveLetterToUpper(filepath.Clean(path)) +} + +// deal with case insensitive filesystems and other weirdness +func pathEqual(a, b string) bool { + a = cleanPath(a) + b = cleanPath(b) + return strings.EqualFold(a, b) +} diff --git a/vendor/github.com/tools/godep/vcs.go b/vendor/github.com/tools/godep/vcs.go new file mode 100644 index 0000000000..5d4a16380f --- /dev/null +++ b/vendor/github.com/tools/godep/vcs.go @@ -0,0 +1,322 @@ +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "golang.org/x/tools/go/vcs" +) + +// VCS represents a version control system. +type VCS struct { + vcs *vcs.Cmd + + IdentifyCmd string + DescribeCmd string + DiffCmd string + ListCmd string + RootCmd string + + // run in sandbox repos + ExistsCmd string +} + +var vcsBzr = &VCS{ + vcs: vcs.ByCmd("bzr"), + + IdentifyCmd: "version-info --custom --template {revision_id}", + DescribeCmd: "revno", // TODO(kr): find tag names if possible + DiffCmd: "diff -r {rev}", + ListCmd: "ls --from-root -R", + RootCmd: "root", +} + +var vcsGit = &VCS{ + vcs: vcs.ByCmd("git"), + + IdentifyCmd: "rev-parse HEAD", + DescribeCmd: "describe --tags", + DiffCmd: "diff {rev}", + ListCmd: "ls-files --full-name", + RootCmd: "rev-parse --show-cdup", + + ExistsCmd: "cat-file -e {rev}", +} + +var vcsHg = &VCS{ + vcs: vcs.ByCmd("hg"), + + IdentifyCmd: "parents --template {node}", + DescribeCmd: "log -r . --template {latesttag}-{latesttagdistance}", + DiffCmd: "diff -r {rev}", + ListCmd: "status --all --no-status", + RootCmd: "root", + + ExistsCmd: "cat -r {rev} .", +} + +var cmd = map[*vcs.Cmd]*VCS{ + vcsBzr.vcs: vcsBzr, + vcsGit.vcs: vcsGit, + vcsHg.vcs: vcsHg, +} + +// VCSFromDir returns a VCS value from a directory. +func VCSFromDir(dir, srcRoot string) (*VCS, string, error) { + vcscmd, reporoot, err := vcs.FromDir(dir, srcRoot) + if err != nil { + return nil, "", fmt.Errorf("error while inspecting %q: %v", dir, err) + } + vcsext := cmd[vcscmd] + if vcsext == nil { + return nil, "", fmt.Errorf("%s is unsupported: %s", vcscmd.Name, dir) + } + return vcsext, reporoot, nil +} + +// VCSForImportPath returns a VCS value for an import path. +func VCSForImportPath(importPath string) (*VCS, error) { + rr, err := vcs.RepoRootForImportPath(importPath, debug) + if err != nil { + return nil, err + } + vcs := cmd[rr.VCS] + if vcs == nil { + return nil, fmt.Errorf("%s is unsupported: %s", rr.VCS.Name, importPath) + } + return vcs, nil +} + +func (v *VCS) identify(dir string) (string, error) { + out, err := v.runOutput(dir, v.IdentifyCmd) + return string(bytes.TrimSpace(out)), err +} + +func absRoot(dir, out string) string { + if filepath.IsAbs(out) { + return filepath.Clean(out) + } + return filepath.Join(dir, out) +} + +func (v *VCS) root(dir string) (string, error) { + out, err := v.runOutput(dir, v.RootCmd) + return absRoot(dir, string(bytes.TrimSpace(out))), err +} + +func (v *VCS) describe(dir, rev string) string { + out, err := v.runOutputVerboseOnly(dir, v.DescribeCmd, "rev", rev) + if err != nil { + return "" + } + return string(bytes.TrimSpace(out)) +} + +func (v *VCS) isDirty(dir, rev string) bool { + out, err := v.runOutput(dir, v.DiffCmd, "rev", rev) + return err != nil || len(out) != 0 +} + +type vcsFiles map[string]bool + +func (vf vcsFiles) Contains(path string) bool { + // Fast path, we have the path + if vf[path] { + return true + } + + // Slow path for case insensitive filesystems + // See #310 + for f := range vf { + if pathEqual(f, path) { + return true + } + // git's root command (maybe other vcs as well) resolve symlinks, so try that too + // FIXME: rev-parse --show-cdup + extra logic will fix this for git but also need to validate the other vcs commands. This is maybe temporary. + p, err := filepath.EvalSymlinks(path) + if err != nil { + return false + } + if pathEqual(f, p) { + return true + } + } + + // No matches by either method + return false +} + +// listFiles tracked by the VCS in the repo that contains dir, converted to absolute path. +func (v *VCS) listFiles(dir string) vcsFiles { + root, err := v.root(dir) + debugln("vcs dir", dir) + debugln("vcs root", root) + ppln(v) + if err != nil { + return nil + } + out, err := v.runOutput(dir, v.ListCmd) + if err != nil { + return nil + } + files := make(vcsFiles) + for _, file := range bytes.Split(out, []byte{'\n'}) { + if len(file) > 0 { + path, err := filepath.Abs(filepath.Join(root, string(file))) + if err != nil { + panic(err) // this should not happen + } + + if pathEqual(filepath.Dir(path), dir) { + files[path] = true + } + } + } + return files +} + +func (v *VCS) exists(dir, rev string) bool { + err := v.runVerboseOnly(dir, v.ExistsCmd, "rev", rev) + return err == nil +} + +// RevSync checks out the revision given by rev in dir. +// The dir must exist and rev must be a valid revision. +func (v *VCS) RevSync(dir, rev string) error { + return v.run(dir, v.vcs.TagSyncCmd, "tag", rev) +} + +// run runs the command line cmd in the given directory. +// keyval is a list of key, value pairs. run expands +// instances of {key} in cmd into value, but only after +// splitting cmd into individual arguments. +// If an error occurs, run prints the command line and the +// command's combined stdout+stderr to standard error. +// Otherwise run discards the command's output. +func (v *VCS) run(dir string, cmdline string, kv ...string) error { + _, err := v.run1(dir, cmdline, kv, true) + return err +} + +// runVerboseOnly is like run but only generates error output to standard error in verbose mode. +func (v *VCS) runVerboseOnly(dir string, cmdline string, kv ...string) error { + _, err := v.run1(dir, cmdline, kv, false) + return err +} + +// runOutput is like run but returns the output of the command. +func (v *VCS) runOutput(dir string, cmdline string, kv ...string) ([]byte, error) { + return v.run1(dir, cmdline, kv, true) +} + +// runOutputVerboseOnly is like runOutput but only generates error output to standard error in verbose mode. +func (v *VCS) runOutputVerboseOnly(dir string, cmdline string, kv ...string) ([]byte, error) { + return v.run1(dir, cmdline, kv, false) +} + +// run1 is the generalized implementation of run and runOutput. +func (v *VCS) run1(dir string, cmdline string, kv []string, verbose bool) ([]byte, error) { + m := make(map[string]string) + for i := 0; i < len(kv); i += 2 { + m[kv[i]] = kv[i+1] + } + args := strings.Fields(cmdline) + for i, arg := range args { + args[i] = expand(m, arg) + } + + _, err := exec.LookPath(v.vcs.Cmd) + if err != nil { + fmt.Fprintf(os.Stderr, "godep: missing %s command.\n", v.vcs.Name) + return nil, err + } + + cmd := exec.Command(v.vcs.Cmd, args...) + cmd.Dir = dir + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = &buf + err = cmd.Run() + out := buf.Bytes() + if err != nil { + if verbose { + fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.vcs.Cmd, strings.Join(args, " ")) + os.Stderr.Write(out) + } + return nil, err + } + return out, nil +} + +func expand(m map[string]string, s string) string { + for k, v := range m { + s = strings.Replace(s, "{"+k+"}", v, -1) + } + return s +} + +// Mercurial has no command equivalent to git remote add. +// We handle it as a special case in process. +func hgLink(dir, remote, url string) error { + hgdir := filepath.Join(dir, ".hg") + if err := os.MkdirAll(hgdir, 0777); err != nil { + return err + } + path := filepath.Join(hgdir, "hgrc") + f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + if err != nil { + return err + } + fmt.Fprintf(f, "[paths]\n%s = %s\n", remote, url) + return f.Close() +} + +func gitDetached(r string) (bool, error) { + o, err := vcsGit.runOutput(r, "status") + if err != nil { + return false, errors.New("unable to determine git status " + err.Error()) + } + return bytes.Contains(o, []byte("HEAD detached at")), nil +} + +func gitDefaultBranch(r string) (string, error) { + o, err := vcsGit.runOutput(r, "remote show origin") + if err != nil { + return "", errors.New("Running git remote show origin errored with: " + err.Error()) + } + return gitDetermineDefaultBranch(r, string(o)) +} + +func gitDetermineDefaultBranch(r, o string) (string, error) { + e := "Unable to determine HEAD branch: " + hb := "HEAD branch:" + lbcfgp := "Local branch configured for 'git pull':" + s := strings.Index(o, hb) + if s < 0 { + b := strings.Index(o, lbcfgp) + if b < 0 { + return "", errors.New(e + "Remote HEAD is ambiguous. Before godep can pull new commits you will need to:" + ` +cd ` + r + ` +git checkout +Here is what was reported: +` + o) + } + s = b + len(lbcfgp) + } else { + s += len(hb) + } + f := strings.Fields(o[s:]) + if len(f) < 3 { + return "", errors.New(e + "git output too short") + } + return f[0], nil +} + +func gitCheckout(r, b string) error { + return vcsGit.run(r, "checkout "+b) +} diff --git a/vendor/github.com/tools/godep/version.go b/vendor/github.com/tools/godep/version.go new file mode 100644 index 0000000000..71abe8d142 --- /dev/null +++ b/vendor/github.com/tools/godep/version.go @@ -0,0 +1,63 @@ +package main + +import ( + "fmt" + "log" + "runtime" + "strconv" + "strings" +) + +const version = 79 + +var cmdVersion = &Command{ + Name: "version", + Short: "show version info", + Long: ` + +Displays the version of godep as well as the target OS, architecture and go runtime version. +`, + Run: runVersion, +} + +func versionString() string { + return fmt.Sprintf("godep v%d (%s/%s/%s)", version, runtime.GOOS, runtime.GOARCH, runtime.Version()) +} + +func runVersion(cmd *Command, args []string) { + fmt.Printf("%s\n", versionString()) +} + +func GoVersionFields(c rune) bool { + return c == 'g' || c == 'o' || c == '.' +} + +// isSameOrNewer go version (goA.B) +// go1.6 >= go1.6 == true +// go1.5 >= go1.6 == false +func isSameOrNewer(base, check string) bool { + if base == check { + return true + } + if strings.HasPrefix(check, "devel-") { + return true + } + bp := strings.FieldsFunc(base, GoVersionFields) + cp := strings.FieldsFunc(check, GoVersionFields) + if len(bp) < 2 || len(cp) < 2 { + log.Fatalf("Error comparing %s to %s\n", base, check) + } + if bp[0] == cp[0] { // We only have go version 1 right now + bm, err := strconv.Atoi(bp[1]) + // These errors are unlikely and there is nothing nice to do here anyway + if err != nil { + panic(err) + } + cm, err := strconv.Atoi(cp[1]) + if err != nil { + panic(err) + } + return cm >= bm + } + return false +} diff --git a/vendor/golang.org/x/tools/go/vcs/BUILD b/vendor/golang.org/x/tools/go/vcs/BUILD new file mode 100644 index 0000000000..d960dcf634 --- /dev/null +++ b/vendor/golang.org/x/tools/go/vcs/BUILD @@ -0,0 +1,26 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "discovery.go", + "env.go", + "http.go", + "vcs.go", + ], + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/golang.org/x/tools/go/vcs/discovery.go b/vendor/golang.org/x/tools/go/vcs/discovery.go new file mode 100644 index 0000000000..f431dc1c5b --- /dev/null +++ b/vendor/golang.org/x/tools/go/vcs/discovery.go @@ -0,0 +1,76 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package vcs + +import ( + "encoding/xml" + "fmt" + "io" + "strings" +) + +// charsetReader returns a reader for the given charset. Currently +// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful +// error which is printed by go get, so the user can find why the package +// wasn't downloaded if the encoding is not supported. Note that, in +// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters +// greater than 0x7f are not rejected). +func charsetReader(charset string, input io.Reader) (io.Reader, error) { + switch strings.ToLower(charset) { + case "ascii": + return input, nil + default: + return nil, fmt.Errorf("can't decode XML document using charset %q", charset) + } +} + +// parseMetaGoImports returns meta imports from the HTML in r. +// Parsing ends at the end of the section or the beginning of the . +func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { + d := xml.NewDecoder(r) + d.CharsetReader = charsetReader + d.Strict = false + var t xml.Token + for { + t, err = d.Token() + if err != nil { + if err == io.EOF || len(imports) > 0 { + err = nil + } + return + } + if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { + return + } + if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { + return + } + e, ok := t.(xml.StartElement) + if !ok || !strings.EqualFold(e.Name.Local, "meta") { + continue + } + if attrValue(e.Attr, "name") != "go-import" { + continue + } + if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { + imports = append(imports, metaImport{ + Prefix: f[0], + VCS: f[1], + RepoRoot: f[2], + }) + } + } +} + +// attrValue returns the attribute value for the case-insensitive key +// `name', or the empty string if nothing is found. +func attrValue(attrs []xml.Attr, name string) string { + for _, a := range attrs { + if strings.EqualFold(a.Name.Local, name) { + return a.Value + } + } + return "" +} diff --git a/vendor/golang.org/x/tools/go/vcs/env.go b/vendor/golang.org/x/tools/go/vcs/env.go new file mode 100644 index 0000000000..e846f5b3b8 --- /dev/null +++ b/vendor/golang.org/x/tools/go/vcs/env.go @@ -0,0 +1,39 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package vcs + +import ( + "os" + "strings" +) + +// envForDir returns a copy of the environment +// suitable for running in the given directory. +// The environment is the current process's environment +// but with an updated $PWD, so that an os.Getwd in the +// child will be faster. +func envForDir(dir string) []string { + env := os.Environ() + // Internally we only use rooted paths, so dir is rooted. + // Even if dir is not rooted, no harm done. + return mergeEnvLists([]string{"PWD=" + dir}, env) +} + +// mergeEnvLists merges the two environment lists such that +// variables with the same name in "in" replace those in "out". +func mergeEnvLists(in, out []string) []string { +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +} diff --git a/vendor/golang.org/x/tools/go/vcs/http.go b/vendor/golang.org/x/tools/go/vcs/http.go new file mode 100644 index 0000000000..96188185cb --- /dev/null +++ b/vendor/golang.org/x/tools/go/vcs/http.go @@ -0,0 +1,80 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package vcs + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" +) + +// httpClient is the default HTTP client, but a variable so it can be +// changed by tests, without modifying http.DefaultClient. +var httpClient = http.DefaultClient + +// httpGET returns the data from an HTTP GET request for the given URL. +func httpGET(url string) ([]byte, error) { + resp, err := httpClient.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, fmt.Errorf("%s: %s", url, resp.Status) + } + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("%s: %v", url, err) + } + return b, nil +} + +// httpsOrHTTP returns the body of either the importPath's +// https resource or, if unavailable, the http resource. +func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) { + fetch := func(scheme string) (urlStr string, res *http.Response, err error) { + u, err := url.Parse(scheme + "://" + importPath) + if err != nil { + return "", nil, err + } + u.RawQuery = "go-get=1" + urlStr = u.String() + if Verbose { + log.Printf("Fetching %s", urlStr) + } + res, err = httpClient.Get(urlStr) + return + } + closeBody := func(res *http.Response) { + if res != nil { + res.Body.Close() + } + } + urlStr, res, err := fetch("https") + if err != nil || res.StatusCode != 200 { + if Verbose { + if err != nil { + log.Printf("https fetch failed.") + } else { + log.Printf("ignoring https fetch with status code %d", res.StatusCode) + } + } + closeBody(res) + urlStr, res, err = fetch("http") + } + if err != nil { + closeBody(res) + return "", nil, err + } + // Note: accepting a non-200 OK here, so people can serve a + // meta import in their http 404 page. + if Verbose { + log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode) + } + return urlStr, res.Body, nil +} diff --git a/vendor/golang.org/x/tools/go/vcs/vcs.go b/vendor/golang.org/x/tools/go/vcs/vcs.go new file mode 100644 index 0000000000..63fa46eb7f --- /dev/null +++ b/vendor/golang.org/x/tools/go/vcs/vcs.go @@ -0,0 +1,710 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package vcs + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" +) + +// Verbose enables verbose operation logging. +var Verbose bool + +// ShowCmd controls whether VCS commands are printed. +var ShowCmd bool + +// A Cmd describes how to use a version control system +// like Mercurial, Git, or Subversion. +type Cmd struct { + Name string + Cmd string // name of binary to invoke command + + CreateCmd string // command to download a fresh copy of a repository + DownloadCmd string // command to download updates into an existing repository + + TagCmd []TagCmd // commands to list tags + TagLookupCmd []TagCmd // commands to lookup tags before running tagSyncCmd + TagSyncCmd string // command to sync to specific tag + TagSyncDefault string // command to sync to default tag + + LogCmd string // command to list repository changelogs in an XML format + + Scheme []string + PingCmd string +} + +// A TagCmd describes a command to list available tags +// that can be passed to Cmd.TagSyncCmd. +type TagCmd struct { + Cmd string // command to list tags + Pattern string // regexp to extract tags from list +} + +// vcsList lists the known version control systems +var vcsList = []*Cmd{ + vcsHg, + vcsGit, + vcsSvn, + vcsBzr, +} + +// ByCmd returns the version control system for the given +// command name (hg, git, svn, bzr). +func ByCmd(cmd string) *Cmd { + for _, vcs := range vcsList { + if vcs.Cmd == cmd { + return vcs + } + } + return nil +} + +// vcsHg describes how to use Mercurial. +var vcsHg = &Cmd{ + Name: "Mercurial", + Cmd: "hg", + + CreateCmd: "clone -U {repo} {dir}", + DownloadCmd: "pull", + + // We allow both tag and branch names as 'tags' + // for selecting a version. This lets people have + // a go.release.r60 branch and a go1 branch + // and make changes in both, without constantly + // editing .hgtags. + TagCmd: []TagCmd{ + {"tags", `^(\S+)`}, + {"branches", `^(\S+)`}, + }, + TagSyncCmd: "update -r {tag}", + TagSyncDefault: "update default", + + LogCmd: "log --encoding=utf-8 --limit={limit} --template={template}", + + Scheme: []string{"https", "http", "ssh"}, + PingCmd: "identify {scheme}://{repo}", +} + +// vcsGit describes how to use Git. +var vcsGit = &Cmd{ + Name: "Git", + Cmd: "git", + + CreateCmd: "clone {repo} {dir}", + DownloadCmd: "pull --ff-only", + + TagCmd: []TagCmd{ + // tags/xxx matches a git tag named xxx + // origin/xxx matches a git branch named xxx on the default remote repository + {"show-ref", `(?:tags|origin)/(\S+)$`}, + }, + TagLookupCmd: []TagCmd{ + {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, + }, + TagSyncCmd: "checkout {tag}", + TagSyncDefault: "checkout master", + + Scheme: []string{"git", "https", "http", "git+ssh"}, + PingCmd: "ls-remote {scheme}://{repo}", +} + +// vcsBzr describes how to use Bazaar. +var vcsBzr = &Cmd{ + Name: "Bazaar", + Cmd: "bzr", + + CreateCmd: "branch {repo} {dir}", + + // Without --overwrite bzr will not pull tags that changed. + // Replace by --overwrite-tags after http://pad.lv/681792 goes in. + DownloadCmd: "pull --overwrite", + + TagCmd: []TagCmd{{"tags", `^(\S+)`}}, + TagSyncCmd: "update -r {tag}", + TagSyncDefault: "update -r revno:-1", + + Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + PingCmd: "info {scheme}://{repo}", +} + +// vcsSvn describes how to use Subversion. +var vcsSvn = &Cmd{ + Name: "Subversion", + Cmd: "svn", + + CreateCmd: "checkout {repo} {dir}", + DownloadCmd: "update", + + // There is no tag command in subversion. + // The branch information is all in the path names. + + LogCmd: "log --xml --limit={limit}", + + Scheme: []string{"https", "http", "svn", "svn+ssh"}, + PingCmd: "info {scheme}://{repo}", +} + +func (v *Cmd) String() string { + return v.Name +} + +// run runs the command line cmd in the given directory. +// keyval is a list of key, value pairs. run expands +// instances of {key} in cmd into value, but only after +// splitting cmd into individual arguments. +// If an error occurs, run prints the command line and the +// command's combined stdout+stderr to standard error. +// Otherwise run discards the command's output. +func (v *Cmd) run(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, true) + return err +} + +// runVerboseOnly is like run but only generates error output to standard error in verbose mode. +func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, false) + return err +} + +// runOutput is like run but returns the output of the command. +func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) { + return v.run1(dir, cmd, keyval, true) +} + +// run1 is the generalized implementation of run and runOutput. +func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) { + m := make(map[string]string) + for i := 0; i < len(keyval); i += 2 { + m[keyval[i]] = keyval[i+1] + } + args := strings.Fields(cmdline) + for i, arg := range args { + args[i] = expand(m, arg) + } + + _, err := exec.LookPath(v.Cmd) + if err != nil { + fmt.Fprintf(os.Stderr, + "go: missing %s command. See http://golang.org/s/gogetcmd\n", + v.Name) + return nil, err + } + + cmd := exec.Command(v.Cmd, args...) + cmd.Dir = dir + cmd.Env = envForDir(cmd.Dir) + if ShowCmd { + fmt.Printf("cd %s\n", dir) + fmt.Printf("%s %s\n", v.Cmd, strings.Join(args, " ")) + } + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = &buf + err = cmd.Run() + out := buf.Bytes() + if err != nil { + if verbose || Verbose { + fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.Cmd, strings.Join(args, " ")) + os.Stderr.Write(out) + } + return nil, err + } + return out, nil +} + +// Ping pings the repo to determine if scheme used is valid. +// This repo must be pingable with this scheme and VCS. +func (v *Cmd) Ping(scheme, repo string) error { + return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo) +} + +// Create creates a new copy of repo in dir. +// The parent of dir must exist; dir must not. +func (v *Cmd) Create(dir, repo string) error { + return v.run(".", v.CreateCmd, "dir", dir, "repo", repo) +} + +// CreateAtRev creates a new copy of repo in dir at revision rev. +// The parent of dir must exist; dir must not. +// rev must be a valid revision in repo. +func (v *Cmd) CreateAtRev(dir, repo, rev string) error { + if err := v.Create(dir, repo); err != nil { + return err + } + return v.run(dir, v.TagSyncCmd, "tag", rev) +} + +// Download downloads any new changes for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Download(dir string) error { + return v.run(dir, v.DownloadCmd) +} + +// Tags returns the list of available tags for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Tags(dir string) ([]string, error) { + var tags []string + for _, tc := range v.TagCmd { + out, err := v.runOutput(dir, tc.Cmd) + if err != nil { + return nil, err + } + re := regexp.MustCompile(`(?m-s)` + tc.Pattern) + for _, m := range re.FindAllStringSubmatch(string(out), -1) { + tags = append(tags, m[1]) + } + } + return tags, nil +} + +// TagSync syncs the repo in dir to the named tag, which is either a +// tag returned by Tags or the empty string (the default tag). +// dir must be a valid VCS repo compatible with v and the tag must exist. +func (v *Cmd) TagSync(dir, tag string) error { + if v.TagSyncCmd == "" { + return nil + } + if tag != "" { + for _, tc := range v.TagLookupCmd { + out, err := v.runOutput(dir, tc.Cmd, "tag", tag) + if err != nil { + return err + } + re := regexp.MustCompile(`(?m-s)` + tc.Pattern) + m := re.FindStringSubmatch(string(out)) + if len(m) > 1 { + tag = m[1] + break + } + } + } + if tag == "" && v.TagSyncDefault != "" { + return v.run(dir, v.TagSyncDefault) + } + return v.run(dir, v.TagSyncCmd, "tag", tag) +} + +// Log logs the changes for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Log(dir, logTemplate string) ([]byte, error) { + if err := v.Download(dir); err != nil { + return []byte{}, err + } + + const N = 50 // how many revisions to grab + return v.runOutput(dir, v.LogCmd, "limit", strconv.Itoa(N), "template", logTemplate) +} + +// LogAtRev logs the change for repo in dir at the rev revision. +// dir must be a valid VCS repo compatible with v. +// rev must be a valid revision for the repo in dir. +func (v *Cmd) LogAtRev(dir, rev, logTemplate string) ([]byte, error) { + if err := v.Download(dir); err != nil { + return []byte{}, err + } + + // Append revision flag to LogCmd. + logAtRevCmd := v.LogCmd + " --rev=" + rev + return v.runOutput(dir, logAtRevCmd, "limit", strconv.Itoa(1), "template", logTemplate) +} + +// A vcsPath describes how to convert an import path into a +// version control system and repository name. +type vcsPath struct { + prefix string // prefix this description applies to + re string // pattern for import path + repo string // repository to use (expand with match of re) + vcs string // version control system to use (expand with match of re) + check func(match map[string]string) error // additional checks + ping bool // ping for scheme to use to download repo + + regexp *regexp.Regexp // cached compiled form of re +} + +// FromDir inspects dir and its parents to determine the +// version control system and code repository to use. +// On return, root is the import path +// corresponding to the root of the repository. +func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) { + // Clean and double-check that dir is in (a subdirectory of) srcRoot. + dir = filepath.Clean(dir) + srcRoot = filepath.Clean(srcRoot) + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + origDir := dir + for len(dir) > len(srcRoot) { + for _, vcs := range vcsList { + if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil { + return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil + } + } + + // Move to parent. + ndir := filepath.Dir(dir) + if len(ndir) >= len(dir) { + // Shouldn't happen, but just in case, stop. + break + } + dir = ndir + } + + return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir) +} + +// RepoRoot represents a version control system, a repo, and a root of +// where to put it on disk. +type RepoRoot struct { + VCS *Cmd + + // Repo is the repository URL, including scheme. + Repo string + + // Root is the import path corresponding to the root of the + // repository. + Root string +} + +// RepoRootForImportPath analyzes importPath to determine the +// version control system, and code repository to use. +func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) { + rr, err := RepoRootForImportPathStatic(importPath, "") + if err == errUnknownSite { + rr, err = RepoRootForImportDynamic(importPath, verbose) + + // RepoRootForImportDynamic returns error detail + // that is irrelevant if the user didn't intend to use a + // dynamic import in the first place. + // Squelch it. + if err != nil { + if Verbose { + log.Printf("import %q: %v", importPath, err) + } + err = fmt.Errorf("unrecognized import path %q", importPath) + } + } + + if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") { + // Do not allow wildcards in the repo root. + rr = nil + err = fmt.Errorf("cannot expand ... in %q", importPath) + } + return rr, err +} + +var errUnknownSite = errors.New("dynamic lookup required to find mapping") + +// RepoRootForImportPathStatic attempts to map importPath to a +// RepoRoot using the commonly-used VCS hosting sites in vcsPaths +// (github.com/user/dir), or from a fully-qualified importPath already +// containing its VCS type (foo.com/repo.git/dir) +// +// If scheme is non-empty, that scheme is forced. +func RepoRootForImportPathStatic(importPath, scheme string) (*RepoRoot, error) { + if strings.Contains(importPath, "://") { + return nil, fmt.Errorf("invalid import path %q", importPath) + } + for _, srv := range vcsPaths { + if !strings.HasPrefix(importPath, srv.prefix) { + continue + } + m := srv.regexp.FindStringSubmatch(importPath) + if m == nil { + if srv.prefix != "" { + return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath) + } + continue + } + + // Build map of named subexpression matches for expand. + match := map[string]string{ + "prefix": srv.prefix, + "import": importPath, + } + for i, name := range srv.regexp.SubexpNames() { + if name != "" && match[name] == "" { + match[name] = m[i] + } + } + if srv.vcs != "" { + match["vcs"] = expand(match, srv.vcs) + } + if srv.repo != "" { + match["repo"] = expand(match, srv.repo) + } + if srv.check != nil { + if err := srv.check(match); err != nil { + return nil, err + } + } + vcs := ByCmd(match["vcs"]) + if vcs == nil { + return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) + } + if srv.ping { + if scheme != "" { + match["repo"] = scheme + "://" + match["repo"] + } else { + for _, scheme := range vcs.Scheme { + if vcs.Ping(scheme, match["repo"]) == nil { + match["repo"] = scheme + "://" + match["repo"] + break + } + } + } + } + rr := &RepoRoot{ + VCS: vcs, + Repo: match["repo"], + Root: match["root"], + } + return rr, nil + } + return nil, errUnknownSite +} + +// RepoRootForImportDynamic finds a *RepoRoot for a custom domain that's not +// statically known by RepoRootForImportPathStatic. +// +// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld". +func RepoRootForImportDynamic(importPath string, verbose bool) (*RepoRoot, error) { + slash := strings.Index(importPath, "/") + if slash < 0 { + slash = len(importPath) + } + host := importPath[:slash] + if !strings.Contains(host, ".") { + return nil, errors.New("import path doesn't contain a hostname") + } + urlStr, body, err := httpsOrHTTP(importPath) + if err != nil { + return nil, fmt.Errorf("http/https fetch: %v", err) + } + defer body.Close() + imports, err := parseMetaGoImports(body) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", importPath, err) + } + metaImport, err := matchGoImport(imports, importPath) + if err != nil { + if err != errNoMatch { + return nil, fmt.Errorf("parse %s: %v", urlStr, err) + } + return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr) + } + if verbose { + log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr) + } + // If the import was "uni.edu/bob/project", which said the + // prefix was "uni.edu" and the RepoRoot was "evilroot.com", + // make sure we don't trust Bob and check out evilroot.com to + // "uni.edu" yet (possibly overwriting/preempting another + // non-evil student). Instead, first verify the root and see + // if it matches Bob's claim. + if metaImport.Prefix != importPath { + if verbose { + log.Printf("get %q: verifying non-authoritative meta tag", importPath) + } + urlStr0 := urlStr + urlStr, body, err = httpsOrHTTP(metaImport.Prefix) + if err != nil { + return nil, fmt.Errorf("fetch %s: %v", urlStr, err) + } + imports, err := parseMetaGoImports(body) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", importPath, err) + } + if len(imports) == 0 { + return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr) + } + metaImport2, err := matchGoImport(imports, importPath) + if err != nil || metaImport != metaImport2 { + return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix) + } + } + + if !strings.Contains(metaImport.RepoRoot, "://") { + return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot) + } + rr := &RepoRoot{ + VCS: ByCmd(metaImport.VCS), + Repo: metaImport.RepoRoot, + Root: metaImport.Prefix, + } + if rr.VCS == nil { + return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS) + } + return rr, nil +} + +// metaImport represents the parsed tags from HTML files. +type metaImport struct { + Prefix, VCS, RepoRoot string +} + +// errNoMatch is returned from matchGoImport when there's no applicable match. +var errNoMatch = errors.New("no import match") + +// matchGoImport returns the metaImport from imports matching importPath. +// An error is returned if there are multiple matches. +// errNoMatch is returned if none match. +func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) { + match := -1 + for i, im := range imports { + if !strings.HasPrefix(importPath, im.Prefix) { + continue + } + if match != -1 { + err = fmt.Errorf("multiple meta tags match import path %q", importPath) + return + } + match = i + } + if match == -1 { + err = errNoMatch + return + } + return imports[match], nil +} + +// expand rewrites s to replace {k} with match[k] for each key k in match. +func expand(match map[string]string, s string) string { + for k, v := range match { + s = strings.Replace(s, "{"+k+"}", v, -1) + } + return s +} + +// vcsPaths lists the known vcs paths. +var vcsPaths = []*vcsPath{ + // go.googlesource.com + { + prefix: "go.googlesource.com", + re: `^(?Pgo\.googlesource\.com/[A-Za-z0-9_.\-]+/?)$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Github + { + prefix: "github.com/", + re: `^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Bitbucket + { + prefix: "bitbucket.org/", + re: `^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + repo: "https://{root}", + check: bitbucketVCS, + }, + + // Launchpad + { + prefix: "launchpad.net/", + re: `^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + vcs: "bzr", + repo: "https://{root}", + check: launchpadVCS, + }, + + // Git at OpenStack + { + prefix: "git.openstack.org", + re: `^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // General syntax for any server. + { + re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`, + ping: true, + }, +} + +func init() { + // fill in cached regexps. + // Doing this eagerly discovers invalid regexp syntax + // without having to run a command that needs that regexp. + for _, srv := range vcsPaths { + srv.regexp = regexp.MustCompile(srv.re) + } +} + +// noVCSSuffix checks that the repository name does not +// end in .foo for any version control system foo. +// The usual culprit is ".git". +func noVCSSuffix(match map[string]string) error { + repo := match["repo"] + for _, vcs := range vcsList { + if strings.HasSuffix(repo, "."+vcs.Cmd) { + return fmt.Errorf("invalid version control suffix in %s path", match["prefix"]) + } + } + return nil +} + +// bitbucketVCS determines the version control system for a +// Bitbucket repository, by using the Bitbucket API. +func bitbucketVCS(match map[string]string) error { + if err := noVCSSuffix(match); err != nil { + return err + } + + var resp struct { + SCM string `json:"scm"` + } + url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}") + data, err := httpGET(url) + if err != nil { + return err + } + if err := json.Unmarshal(data, &resp); err != nil { + return fmt.Errorf("decoding %s: %v", url, err) + } + + if ByCmd(resp.SCM) != nil { + match["vcs"] = resp.SCM + if resp.SCM == "git" { + match["repo"] += ".git" + } + return nil + } + + return fmt.Errorf("unable to detect version control system for bitbucket.org/ path") +} + +// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case, +// "foo" could be a series name registered in Launchpad with its own branch, +// and it could also be the name of a directory within the main project +// branch one level up. +func launchpadVCS(match map[string]string) error { + if match["project"] == "" || match["series"] == "" { + return nil + } + _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format")) + if err != nil { + match["root"] = expand(match, "launchpad.net/{project}") + match["repo"] = expand(match, "https://{root}") + } + return nil +}