Commit ac4ffb1e authored by Tim Hockin's avatar Tim Hockin

Vendor godep v79 and use it

parent a29c048e
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"Packages": [ "Packages": [
"github.com/onsi/ginkgo/ginkgo", "github.com/onsi/ginkgo/ginkgo",
"github.com/jteeuwen/go-bindata/go-bindata", "github.com/jteeuwen/go-bindata/go-bindata",
"github.com/tools/godep",
"./..." "./..."
], ],
"Deps": [ "Deps": [
...@@ -1923,11 +1924,20 @@ ...@@ -1923,11 +1924,20 @@
"Rev": "2788f0dbd16903de03cb8186e5c7d97b69ad387b" "Rev": "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
}, },
{ {
"ImportPath": "github.com/kr/pretty",
"Comment": "go.weekly.2011-12-22-24-gf31442d",
"Rev": "f31442d60e51465c69811e2107ae978868dbea5c"
},
{
"ImportPath": "github.com/kr/pty", "ImportPath": "github.com/kr/pty",
"Comment": "release.r56-29-gf7ee69f", "Comment": "release.r56-29-gf7ee69f",
"Rev": "f7ee69f31298ecbe5d2b349c711e2547a617d398" "Rev": "f7ee69f31298ecbe5d2b349c711e2547a617d398"
}, },
{ {
"ImportPath": "github.com/kr/text",
"Rev": "6807e777504f54ad073ecef66747de158294b639"
},
{
"ImportPath": "github.com/libopenstorage/openstorage/api", "ImportPath": "github.com/libopenstorage/openstorage/api",
"Rev": "093a0c3888753c2056e7373183693d670c6bba01" "Rev": "093a0c3888753c2056e7373183693d670c6bba01"
}, },
...@@ -2520,6 +2530,11 @@ ...@@ -2520,6 +2530,11 @@
"Rev": "e7cb7fa329f456b3855136a2642b197bad7366ba" "Rev": "e7cb7fa329f456b3855136a2642b197bad7366ba"
}, },
{ {
"ImportPath": "github.com/tools/godep",
"Comment": "v79",
"Rev": "f15f6db5da33a4ac48be83e20b9dd838e14f117b"
},
{
"ImportPath": "github.com/ugorji/go/codec", "ImportPath": "github.com/ugorji/go/codec",
"Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74"
}, },
...@@ -2860,6 +2875,10 @@ ...@@ -2860,6 +2875,10 @@
"Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32"
}, },
{ {
"ImportPath": "golang.org/x/tools/go/vcs",
"Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32"
},
{
"ImportPath": "google.golang.org/api/cloudkms/v1", "ImportPath": "google.golang.org/api/cloudkms/v1",
"Rev": "654f863362977d69086620b5f72f13e911da2410" "Rev": "654f863362977d69086620b5f72f13e911da2410"
}, },
......
...@@ -66825,6 +66825,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -66825,6 +66825,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: = = vendor/github.com/kr/pty licensed under: =
Copyright (c) 2011 Keith Rarick Copyright (c) 2011 Keith Rarick
...@@ -66856,6 +66885,33 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ...@@ -66856,6 +66885,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: = = vendor/github.com/libopenstorage/openstorage/api licensed under: =
...@@ -79403,6 +79459,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -79403,6 +79459,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: = = vendor/github.com/ugorji/go/codec licensed under: =
The MIT License (MIT) The MIT License (MIT)
...@@ -86287,6 +86379,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -86287,6 +86379,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: = = vendor/google.golang.org/api/cloudkms/v1 licensed under: =
Copyright (c) 2011 Google Inc. All rights reserved. Copyright (c) 2011 Google Inc. All rights reserved.
...@@ -58,6 +58,7 @@ fi ...@@ -58,6 +58,7 @@ fi
REQUIRED_BINS=( REQUIRED_BINS=(
"github.com/onsi/ginkgo/ginkgo" "github.com/onsi/ginkgo/ginkgo"
"github.com/jteeuwen/go-bindata/go-bindata" "github.com/jteeuwen/go-bindata/go-bindata"
"github.com/tools/godep"
"./..." "./..."
) )
......
...@@ -521,20 +521,9 @@ kube::util::ensure_godep_version() { ...@@ -521,20 +521,9 @@ kube::util::ensure_godep_version() {
return return
fi fi
kube::log::status "Getting godep version ${GODEP_VERSION}" kube::log::status "Installing godep version ${GODEP_VERSION}"
kube::util::ensure-temp-dir go install ./vendor/github.com/tools/godep/
mkdir -p "${KUBE_TEMP}/go/src"
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 if [[ "$(godep version 2>/dev/null)" != *"godep ${GODEP_VERSION}"* ]]; then
kube::log::error "Expected godep ${GODEP_VERSION}, got $(godep version)" kube::log::error "Expected godep ${GODEP_VERSION}, got $(godep version)"
return 1 return 1
......
...@@ -258,7 +258,9 @@ filegroup( ...@@ -258,7 +258,9 @@ filegroup(
"//vendor/github.com/kardianos/osext:all-srcs", "//vendor/github.com/kardianos/osext:all-srcs",
"//vendor/github.com/karlseguin/ccache:all-srcs", "//vendor/github.com/karlseguin/ccache:all-srcs",
"//vendor/github.com/kr/fs: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/pty:all-srcs",
"//vendor/github.com/kr/text:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/api: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/parser:all-srcs",
"//vendor/github.com/libopenstorage/openstorage/pkg/units:all-srcs", "//vendor/github.com/libopenstorage/openstorage/pkg/units:all-srcs",
...@@ -323,6 +325,7 @@ filegroup( ...@@ -323,6 +325,7 @@ filegroup(
"//vendor/github.com/stretchr/testify/mock:all-srcs", "//vendor/github.com/stretchr/testify/mock:all-srcs",
"//vendor/github.com/stretchr/testify/require:all-srcs", "//vendor/github.com/stretchr/testify/require:all-srcs",
"//vendor/github.com/syndtr/gocapability/capability: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/ugorji/go/codec:all-srcs",
"//vendor/github.com/vishvananda/netlink:all-srcs", "//vendor/github.com/vishvananda/netlink:all-srcs",
"//vendor/github.com/vishvananda/netns:all-srcs", "//vendor/github.com/vishvananda/netns:all-srcs",
...@@ -368,6 +371,7 @@ filegroup( ...@@ -368,6 +371,7 @@ filegroup(
"//vendor/golang.org/x/text/width:all-srcs", "//vendor/golang.org/x/text/width:all-srcs",
"//vendor/golang.org/x/time/rate:all-srcs", "//vendor/golang.org/x/time/rate:all-srcs",
"//vendor/golang.org/x/tools/container/intsets: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/cloudkms/v1:all-srcs",
"//vendor/google.golang.org/api/cloudmonitoring/v2beta2:all-srcs", "//vendor/google.golang.org/api/cloudmonitoring/v2beta2:all-srcs",
"//vendor/google.golang.org/api/compute/v0.alpha:all-srcs", "//vendor/google.golang.org/api/compute/v0.alpha:all-srcs",
......
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"],
)
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.
package pretty
import "github.com/kr/pretty"
Package pretty provides pretty-printing for Go values.
Documentation
http://godoc.org/github.com/kr/pretty
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
}
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
}
// 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
}
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
}
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"],
)
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.
This is a Go package for manipulating paragraphs of text.
See http://go.pkgdoc.org/github.com/kr/text for full documentation.
// Package text provides rudimentary functions for manipulating text in
// paragraphs.
package text
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
}
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
}
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
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"],
)
## 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
<cmd>`.
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.
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.
## 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 <pkg spec>
# 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 <pkg spec>
# 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`.
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])
}
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)
}
/*
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
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"
}
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
}
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.
`
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
}
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
}
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 <this-command>' 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)
}
}
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
}
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)
}
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)
}
}
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 <pkg>, 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
}
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
}
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
}
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)
}
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 <a HEAD branch>
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)
}
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
}
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"],
)
// 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 <head> section or the beginning of the <body>.
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 ""
}
// 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
}
// 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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment