diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 53ce7e3c0..bd0524e09 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -60,6 +60,10 @@ "ImportPath": "github.com/coreos/go-semver/semver", "Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa" }, + { + "ImportPath": "github.com/facebookgo/stackerr", + "Rev": "060fbf9364c89acd41bf710e9e92915a90e7a5b5" + }, { "ImportPath": "github.com/gonuts/flag", "Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493" diff --git a/Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml b/Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml new file mode 100644 index 000000000..2cc62c5e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml @@ -0,0 +1,24 @@ +language: go + +go: + - 1.2 + - 1.3 + +matrix: + fast_finish: true + +before_install: + - go get -v code.google.com/p/go.tools/cmd/vet + - go get -v github.com/golang/lint/golint + - go get -v code.google.com/p/go.tools/cmd/cover + +install: + - go install -race -v std + - go get -race -t -v ./... + - go install -race -v ./... + +script: + - go vet ./... + - $HOME/gopath/bin/golint . + - go test -cpu=2 -race -v ./... + - go test -cpu=2 -covermode=atomic ./... diff --git a/Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md b/Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md new file mode 100644 index 000000000..8837ed070 --- /dev/null +++ b/Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md @@ -0,0 +1,4 @@ +stackerr [![Build Status](https://secure.travis-ci.org/facebookgo/stackerr.png)](http://travis-ci.org/facebookgo/stackerr) +======== + +Documentation: https://godoc.org/github.com/facebookgo/stackerr diff --git a/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go b/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go new file mode 100644 index 000000000..e0d2e209c --- /dev/null +++ b/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go @@ -0,0 +1,97 @@ +// Package stackerr provides a way to augment errors with one or more stack +// traces to allow for easier debugging. +package stackerr + +import ( + "errors" + "fmt" + + "github.com/facebookgo/stack" +) + +// Error provides the wrapper that adds multiple Stacks to an error. Each Stack +// represents a location in code thru which this error was wrapped. +type Error struct { + multiStack *stack.Multi + underlying error +} + +// Error provides a multi line error string that includes the stack trace. +func (e *Error) Error() string { + return fmt.Sprintf("%s\n%s", e.underlying, e.multiStack) +} + +// MultiStack identifies the locations this error was wrapped at. +func (e *Error) MultiStack() *stack.Multi { + return e.multiStack +} + +// Underlying returns the error that is being wrapped. +func (e *Error) Underlying() error { + return e.underlying +} + +type hasMultiStack interface { + MultiStack() *stack.Multi +} + +// WrapSkip the error and add the current Stack. The argument skip is the +// number of stack frames to ascend, with 0 identifying the caller of Wrap. If +// the error to be wrapped has a MultiStack, the current stack will be added to +// it. If the error to be wrapped is nil, a nil error is returned. +func WrapSkip(err error, skip int) error { + // nil errors are returned back as nil. + if err == nil { + return nil + } + + // we're adding another Stack to an already wrapped error. + if se, ok := err.(hasMultiStack); ok { + se.MultiStack().AddCallers(skip + 1) + return err + } + + // we're create a freshly wrapped error. + return &Error{ + multiStack: stack.CallersMulti(skip + 1), + underlying: err, + } +} + +// Wrap provides a convenience function that calls WrapSkip with skip=0. That +// is, the Stack starts with the caller of Wrap. +func Wrap(err error) error { + return WrapSkip(err, 1) +} + +// New returns a new error that includes the Stack. +func New(s string) error { + return WrapSkip(errors.New(s), 1) +} + +// Newf formats and returns a new error that includes the Stack. +func Newf(format string, args ...interface{}) error { + return WrapSkip(fmt.Errorf(format, args...), 1) +} + +type hasUnderlying interface { + Underlying() error +} + +// Underlying returns all the underlying errors by iteratively checking if the +// error has an Underlying error. If e is nil, the returned slice will be nil. +func Underlying(e error) []error { + var errs []error + for { + if e == nil { + return errs + } + errs = append(errs, e) + + if eh, ok := e.(hasUnderlying); ok { + e = eh.Underlying() + } else { + e = nil + } + } +} diff --git a/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go b/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go new file mode 100644 index 000000000..a160e675b --- /dev/null +++ b/Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go @@ -0,0 +1,82 @@ +package stackerr_test + +import ( + "errors" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/facebookgo/stackerr" +) + +func TestNew(t *testing.T) { + const errStr = "foo bar baz" + e := stackerr.New(errStr) + matches := []string{ + errStr, + "^github.com/facebookgo/stackerr/stackerr_test.go:15 +TestNew$", + } + match(t, e.Error(), matches) +} + +func TestNewf(t *testing.T) { + const fmtStr = "%s 42" + const errStr = "foo bar baz" + e := stackerr.Newf(fmtStr, errStr) + matches := []string{ + fmt.Sprintf(fmtStr, errStr), + "^github.com/facebookgo/stackerr/stackerr_test.go:26 +TestNewf$", + } + match(t, e.Error(), matches) +} + +func TestWrap(t *testing.T) { + const errStr = "foo bar baz" + e := stackerr.Wrap(errors.New(errStr)) + matches := []string{ + errStr, + "^github.com/facebookgo/stackerr/stackerr_test.go:36 +TestWrap$", + } + match(t, e.Error(), matches) +} + +func TestNilWrap(t *testing.T) { + if stackerr.WrapSkip(nil, 1) != nil { + t.Fatal("did not get nil error") + } +} + +func TestDoubleWrap(t *testing.T) { + e := stackerr.New("") + if stackerr.WrapSkip(e, 1) != e { + t.Fatal("double wrap failure") + } +} + +func TestLog(t *testing.T) { + t.Log(stackerr.New("hello")) +} + +func TestUnderlying(t *testing.T) { + e1 := errors.New("") + e2 := stackerr.Wrap(e1) + errs := stackerr.Underlying(e2) + if len(errs) != 2 || errs[0] != e2 || errs[1] != e1 { + t.Fatal("failed Underlying") + } +} + +func match(t testing.TB, s string, matches []string) { + lines := strings.Split(s, "\n") + for i, m := range matches { + if !regexp.MustCompile(m).MatchString(lines[i]) { + t.Fatalf( + "did not find expected match \"%s\" on line %d in:\n%s", + m, + i, + s, + ) + } + } +} diff --git a/cmd/ipfs2/main.go b/cmd/ipfs2/main.go index 4bbe1da92..d11127eed 100644 --- a/cmd/ipfs2/main.go +++ b/cmd/ipfs2/main.go @@ -169,6 +169,7 @@ func (i *cmdInvocation) Parse(args []string) error { if err != nil { return err } + log.Debugf("config path is %s", configPath) // this sets up the function that will initialize the config lazily. ctx := i.req.Context() diff --git a/config/config.go b/config/config.go index d03a26b11..1416bb139 100644 --- a/config/config.go +++ b/config/config.go @@ -5,11 +5,11 @@ import ( "crypto" "crypto/x509" "encoding/base64" - "errors" "os" "path/filepath" u "github.com/jbenet/go-ipfs/util" + "github.com/jbenet/go-ipfs/util/debugerror" ) var log = u.Logger("config") @@ -129,7 +129,7 @@ func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error func Load(filename string) (*Config, error) { // if nothing is there, fail. User must run 'ipfs init' if _, err := os.Stat(filename); os.IsNotExist(err) { - return nil, errors.New("ipfs not initialized, please run 'ipfs init'") + return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'") } var cfg Config diff --git a/util/debugerror/debugerror.go b/util/debugerror/debugerror.go new file mode 100644 index 000000000..2b6370f98 --- /dev/null +++ b/util/debugerror/debugerror.go @@ -0,0 +1,30 @@ +// package debugerror provides a way to augment errors with additional +// information to allow for easier debugging. +package debugerror + +import ( + "errors" + "fmt" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/stackerr" + "github.com/jbenet/go-ipfs/util" +) + +func Errorf(format string, a ...interface{}) error { + return Wrap(fmt.Errorf(format, a...)) +} + +// New returns an error that contains a stack trace (in debug mode) +func New(s string) error { + if util.Debug { + return stackerr.New(s) + } + return errors.New(s) +} + +func Wrap(err error) error { + if util.Debug { + return stackerr.Wrap(err) + } + return err +}