mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-30 18:13:54 +08:00
Merge pull request #336 from jbenet/feat/test2
fix update check when running ipfs init
This commit is contained in:
10
Godeps/Godeps.json
generated
10
Godeps/Godeps.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ImportPath": "github.com/jbenet/go-ipfs",
|
"ImportPath": "github.com/jbenet/go-ipfs",
|
||||||
"GoVersion": "go1.3",
|
"GoVersion": "go1.3.3",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
],
|
],
|
||||||
@ -60,6 +60,14 @@
|
|||||||
"ImportPath": "github.com/coreos/go-semver/semver",
|
"ImportPath": "github.com/coreos/go-semver/semver",
|
||||||
"Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa"
|
"Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/facebookgo/stack",
|
||||||
|
"Rev": "4da6d991fc3c389efa512151354d643eb5fae4e2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/facebookgo/stackerr",
|
||||||
|
"Rev": "060fbf9364c89acd41bf710e9e92915a90e7a5b5"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/gonuts/flag",
|
"ImportPath": "github.com/gonuts/flag",
|
||||||
"Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493"
|
"Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493"
|
||||||
|
24
Godeps/_workspace/src/github.com/facebookgo/stack/.travis.yml
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/facebookgo/stack/.travis.yml
generated
vendored
Normal file
@ -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 ./...
|
4
Godeps/_workspace/src/github.com/facebookgo/stack/readme.md
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/facebookgo/stack/readme.md
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
stack [](http://travis-ci.org/facebookgo/stack)
|
||||||
|
=====
|
||||||
|
|
||||||
|
Documentation: https://godoc.org/github.com/facebookgo/stack
|
197
Godeps/_workspace/src/github.com/facebookgo/stack/stack.go
generated
vendored
Normal file
197
Godeps/_workspace/src/github.com/facebookgo/stack/stack.go
generated
vendored
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// Package stack provides utilities to capture and pass around stack traces.
|
||||||
|
//
|
||||||
|
// This is useful for building errors that know where they originated from, to
|
||||||
|
// track where a certain log event occured and so on.
|
||||||
|
package stack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxStackSize = 32
|
||||||
|
|
||||||
|
// Frame identifies a file, line & function name in the stack.
|
||||||
|
type Frame struct {
|
||||||
|
File string
|
||||||
|
Line int
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String provides the standard file:line representation.
|
||||||
|
func (f Frame) String() string {
|
||||||
|
return fmt.Sprintf("%s:%d %s", f.File, f.Line, f.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack represents an ordered set of Frames.
|
||||||
|
type Stack []Frame
|
||||||
|
|
||||||
|
// String provides the standard multi-line stack trace.
|
||||||
|
func (s Stack) String() string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
writeStack(&b, s)
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi represents a number of Stacks. This is useful to allow tracking a
|
||||||
|
// value as it travels thru code.
|
||||||
|
type Multi struct {
|
||||||
|
stacks []Stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stacks returns the tracked Stacks.
|
||||||
|
func (m *Multi) Stacks() []Stack {
|
||||||
|
return m.stacks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the given Stack to this Multi.
|
||||||
|
func (m *Multi) Add(s Stack) {
|
||||||
|
m.stacks = append(m.stacks, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCallers adds the Callers Stack to this Multi. The argument skip is
|
||||||
|
// the number of stack frames to ascend, with 0 identifying the caller of
|
||||||
|
// Callers.
|
||||||
|
func (m *Multi) AddCallers(skip int) {
|
||||||
|
m.Add(Callers(skip + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String provides a human readable multi-line stack trace.
|
||||||
|
func (m *Multi) String() string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
for i, s := range m.stacks {
|
||||||
|
if i != 0 {
|
||||||
|
fmt.Fprintf(&b, "\n(Stack %d)\n", i+1)
|
||||||
|
}
|
||||||
|
writeStack(&b, s)
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caller returns a single Frame for the caller. The argument skip is the
|
||||||
|
// number of stack frames to ascend, with 0 identifying the caller of Callers.
|
||||||
|
func Caller(skip int) Frame {
|
||||||
|
pc, file, line, _ := runtime.Caller(skip + 1)
|
||||||
|
fun := runtime.FuncForPC(pc)
|
||||||
|
return Frame{
|
||||||
|
File: StripGOPATH(file),
|
||||||
|
Line: line,
|
||||||
|
Name: StripPackage(fun.Name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callers returns a Stack of Frames for the callers. The argument skip is the
|
||||||
|
// number of stack frames to ascend, with 0 identifying the caller of Callers.
|
||||||
|
func Callers(skip int) Stack {
|
||||||
|
pcs := make([]uintptr, maxStackSize)
|
||||||
|
num := runtime.Callers(skip+2, pcs)
|
||||||
|
stack := make(Stack, num)
|
||||||
|
for i, pc := range pcs[:num] {
|
||||||
|
fun := runtime.FuncForPC(pc)
|
||||||
|
file, line := fun.FileLine(pc)
|
||||||
|
stack[i].File = StripGOPATH(file)
|
||||||
|
stack[i].Line = line
|
||||||
|
stack[i].Name = StripPackage(fun.Name())
|
||||||
|
}
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallersMulti returns a Multi which includes one Stack for the
|
||||||
|
// current callers. The argument skip is the number of stack frames to ascend,
|
||||||
|
// with 0 identifying the caller of CallersMulti.
|
||||||
|
func CallersMulti(skip int) *Multi {
|
||||||
|
m := new(Multi)
|
||||||
|
m.AddCallers(skip + 1)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStack(b *bytes.Buffer, s Stack) {
|
||||||
|
var width int
|
||||||
|
for _, f := range s {
|
||||||
|
if l := len(f.File) + numDigits(f.Line) + 1; l > width {
|
||||||
|
width = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last := len(s) - 1
|
||||||
|
for i, f := range s {
|
||||||
|
b.WriteString(f.File)
|
||||||
|
b.WriteRune(rune(':'))
|
||||||
|
n, _ := fmt.Fprintf(b, "%d", f.Line)
|
||||||
|
for i := width - len(f.File) - n; i != 0; i-- {
|
||||||
|
b.WriteRune(rune(' '))
|
||||||
|
}
|
||||||
|
b.WriteString(f.Name)
|
||||||
|
if i != last {
|
||||||
|
b.WriteRune(rune('\n'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func numDigits(i int) int {
|
||||||
|
var n int
|
||||||
|
for {
|
||||||
|
n++
|
||||||
|
i = i / 10
|
||||||
|
if i == 0 {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can be set by a build script. It will be the colon separated equivalent
|
||||||
|
// of the environment variable.
|
||||||
|
var gopath string
|
||||||
|
|
||||||
|
// This is the processed version based on either the above variable set by the
|
||||||
|
// build or from the GOPATH environment variable.
|
||||||
|
var gopaths []string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// prefer the variable set at build time, otherwise fallback to the
|
||||||
|
// environment variable.
|
||||||
|
if gopath == "" {
|
||||||
|
gopath = os.Getenv("GOPATH")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range strings.Split(gopath, ":") {
|
||||||
|
if p != "" {
|
||||||
|
gopaths = append(gopaths, filepath.Join(p, "src")+"/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also strip GOROOT for maximum cleanliness
|
||||||
|
gopaths = append(gopaths, filepath.Join(runtime.GOROOT(), "src", "pkg")+"/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StripGOPATH strips the GOPATH prefix from the file path f.
|
||||||
|
// In development, this will be done using the GOPATH environment variable.
|
||||||
|
// For production builds, where the GOPATH environment will not be set, the
|
||||||
|
// GOPATH can be included in the binary by passing ldflags, for example:
|
||||||
|
//
|
||||||
|
// GO_LDFLAGS="$GO_LDFLAGS -X github.com/facebookgo/stack.gopath $GOPATH"
|
||||||
|
// go install "-ldflags=$GO_LDFLAGS" my/pkg
|
||||||
|
func StripGOPATH(f string) string {
|
||||||
|
for _, p := range gopaths {
|
||||||
|
if strings.HasPrefix(f, p) {
|
||||||
|
return f[len(p):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// StripPackage strips the package name from the given Func.Name.
|
||||||
|
func StripPackage(n string) string {
|
||||||
|
slashI := strings.LastIndex(n, "/")
|
||||||
|
if slashI == -1 {
|
||||||
|
slashI = 0 // for built-in packages
|
||||||
|
}
|
||||||
|
dotI := strings.Index(n[slashI:], ".")
|
||||||
|
if dotI == -1 {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return n[slashI+dotI+1:]
|
||||||
|
}
|
102
Godeps/_workspace/src/github.com/facebookgo/stack/stack_test.go
generated
vendored
Normal file
102
Godeps/_workspace/src/github.com/facebookgo/stack/stack_test.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package stack_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func indirect1() stack.Stack {
|
||||||
|
return stack.Callers(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func indirect2() stack.Stack {
|
||||||
|
return indirect1()
|
||||||
|
}
|
||||||
|
|
||||||
|
func indirect3() stack.Stack {
|
||||||
|
return indirect2()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallers(t *testing.T) {
|
||||||
|
s := indirect3()
|
||||||
|
matches := []string{
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:12 +indirect1$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:16 +indirect2$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:20 +indirect3$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:24 +TestCallers$",
|
||||||
|
}
|
||||||
|
match(t, s.String(), matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallersMulti(t *testing.T) {
|
||||||
|
m := stack.CallersMulti(0)
|
||||||
|
const expected = "github.com/facebookgo/stack/stack_test.go:35 TestCallersMulti"
|
||||||
|
first := m.Stacks()[0][0].String()
|
||||||
|
if first != expected {
|
||||||
|
t.Fatalf(`expected "%s" got "%s"`, expected, first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallersMultiWithTwo(t *testing.T) {
|
||||||
|
m := stack.CallersMulti(0)
|
||||||
|
m.AddCallers(0)
|
||||||
|
matches := []string{
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:44 +TestCallersMultiWithTwo$",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
`^\(Stack 2\)$`,
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:46 +TestCallersMultiWithTwo$",
|
||||||
|
}
|
||||||
|
match(t, m.String(), matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
type typ struct{}
|
||||||
|
|
||||||
|
func (m typ) indirect1() stack.Stack {
|
||||||
|
return stack.Callers(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m typ) indirect2() stack.Stack {
|
||||||
|
return m.indirect1()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m typ) indirect3() stack.Stack {
|
||||||
|
return m.indirect2()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallersWithStruct(t *testing.T) {
|
||||||
|
var m typ
|
||||||
|
s := m.indirect3()
|
||||||
|
matches := []string{
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:59 +typ.indirect1$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:63 +typ.indirect2$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:67 +typ.indirect3$",
|
||||||
|
"^github.com/facebookgo/stack/stack_test.go:72 +TestCallersWithStruct$",
|
||||||
|
}
|
||||||
|
match(t, s.String(), matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCaller(t *testing.T) {
|
||||||
|
f := stack.Caller(0)
|
||||||
|
const expected = "github.com/facebookgo/stack/stack_test.go:83 TestCaller"
|
||||||
|
if f.String() != expected {
|
||||||
|
t.Fatalf(`expected "%s" got "%s"`, expected, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/facebookgo/stackerr/.travis.yml
generated
vendored
Normal file
@ -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 ./...
|
4
Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/facebookgo/stackerr/readme.md
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
stackerr [](http://travis-ci.org/facebookgo/stackerr)
|
||||||
|
========
|
||||||
|
|
||||||
|
Documentation: https://godoc.org/github.com/facebookgo/stackerr
|
97
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go
generated
vendored
Normal file
97
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr.go
generated
vendored
Normal file
@ -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/jbenet/go-ipfs/Godeps/_workspace/src/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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go
generated
vendored
Normal file
82
Godeps/_workspace/src/github.com/facebookgo/stackerr/stackerr_test.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package stackerr_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -55,6 +55,15 @@ type cmdDetails struct {
|
|||||||
cannotRunOnClient bool
|
cannotRunOnClient bool
|
||||||
cannotRunOnDaemon bool
|
cannotRunOnDaemon bool
|
||||||
doesNotUseRepo bool
|
doesNotUseRepo bool
|
||||||
|
|
||||||
|
// initializesConfig describes commands that initialize the config.
|
||||||
|
// pre-command hooks that require configs must not be run before this
|
||||||
|
// command
|
||||||
|
initializesConfig bool
|
||||||
|
|
||||||
|
// preemptsAutoUpdate describes commands that must be executed without the
|
||||||
|
// pre-command update hook
|
||||||
|
preemptsAutoUpdate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *cmdDetails) String() string {
|
func (d *cmdDetails) String() string {
|
||||||
@ -71,14 +80,14 @@ func (d *cmdDetails) usesRepo() bool { return !d.doesNotUseRepo }
|
|||||||
// properties so that other code can make decisions about whether to invoke a
|
// properties so that other code can make decisions about whether to invoke a
|
||||||
// command or return an error to the user.
|
// command or return an error to the user.
|
||||||
var cmdDetailsMap = map[*cmds.Command]cmdDetails{
|
var cmdDetailsMap = map[*cmds.Command]cmdDetails{
|
||||||
initCmd: cmdDetails{cannotRunOnDaemon: true, doesNotUseRepo: true},
|
initCmd: cmdDetails{initializesConfig: true, cannotRunOnDaemon: true, doesNotUseRepo: true},
|
||||||
daemonCmd: cmdDetails{cannotRunOnDaemon: true},
|
daemonCmd: cmdDetails{cannotRunOnDaemon: true},
|
||||||
commandsClientCmd: cmdDetails{doesNotUseRepo: true},
|
commandsClientCmd: cmdDetails{doesNotUseRepo: true},
|
||||||
commands.CommandsDaemonCmd: cmdDetails{doesNotUseRepo: true},
|
commands.CommandsDaemonCmd: cmdDetails{doesNotUseRepo: true},
|
||||||
commands.DiagCmd: cmdDetails{cannotRunOnClient: true},
|
commands.DiagCmd: cmdDetails{cannotRunOnClient: true},
|
||||||
commands.VersionCmd: cmdDetails{doesNotUseRepo: true},
|
commands.VersionCmd: cmdDetails{doesNotUseRepo: true},
|
||||||
commands.UpdateCmd: cmdDetails{cannotRunOnDaemon: true},
|
commands.UpdateCmd: cmdDetails{preemptsAutoUpdate: true, cannotRunOnDaemon: true},
|
||||||
commands.UpdateCheckCmd: cmdDetails{},
|
commands.UpdateCheckCmd: cmdDetails{preemptsAutoUpdate: true},
|
||||||
commands.UpdateLogCmd: cmdDetails{},
|
commands.UpdateLogCmd: cmdDetails{preemptsAutoUpdate: true},
|
||||||
commands.LogCmd: cmdDetails{cannotRunOnClient: true},
|
commands.LogCmd: cmdDetails{cannotRunOnClient: true},
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
daemon "github.com/jbenet/go-ipfs/daemon2"
|
daemon "github.com/jbenet/go-ipfs/daemon2"
|
||||||
updates "github.com/jbenet/go-ipfs/updates"
|
updates "github.com/jbenet/go-ipfs/updates"
|
||||||
u "github.com/jbenet/go-ipfs/util"
|
u "github.com/jbenet/go-ipfs/util"
|
||||||
|
"github.com/jbenet/go-ipfs/util/debugerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
// log is the command logger
|
// log is the command logger
|
||||||
@ -169,6 +170,7 @@ func (i *cmdInvocation) Parse(args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Debugf("config path is %s", configPath)
|
||||||
|
|
||||||
// this sets up the function that will initialize the config lazily.
|
// this sets up the function that will initialize the config lazily.
|
||||||
ctx := i.req.Context()
|
ctx := i.req.Context()
|
||||||
@ -200,21 +202,61 @@ func (i *cmdInvocation) requestedHelp() (short bool, long bool, err error) {
|
|||||||
return longHelp, shortHelp, nil
|
return longHelp, shortHelp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func callPreCommandHooks(details cmdDetails, req cmds.Request, root *cmds.Command) error {
|
||||||
|
|
||||||
|
log.Debug("Calling pre-command hooks...")
|
||||||
|
|
||||||
|
// some hooks only run when the command is executed locally
|
||||||
|
daemon, err := commandShouldRunOnDaemon(details, req, root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for updates when 1) commands is going to be run locally, 2) the
|
||||||
|
// command does not initialize the config, and 3) the command does not
|
||||||
|
// pre-empt updates
|
||||||
|
if !daemon && !details.initializesConfig && !details.preemptsAutoUpdate {
|
||||||
|
|
||||||
|
log.Debug("Calling hook: Check for updates")
|
||||||
|
|
||||||
|
cfg, err := req.Context().GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Check for updates and potentially install one.
|
||||||
|
if err := updates.CliCheckForUpdates(cfg, req.Context().ConfigRoot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
|
func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
|
||||||
var res cmds.Response
|
var res cmds.Response
|
||||||
|
|
||||||
useDaemon, err := commandShouldRunOnDaemon(req, root)
|
details, err := commandDetails(req.Path(), root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := req.Context().GetConfig()
|
useDaemon, err := commandShouldRunOnDaemon(*details, req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = callPreCommandHooks(*details, req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if useDaemon {
|
if useDaemon {
|
||||||
|
|
||||||
|
cfg, err := req.Context().GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
addr, err := ma.NewMultiaddr(cfg.Addresses.API)
|
addr, err := ma.NewMultiaddr(cfg.Addresses.API)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -236,11 +278,6 @@ func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
|
|||||||
} else {
|
} else {
|
||||||
log.Info("Executing command locally")
|
log.Info("Executing command locally")
|
||||||
|
|
||||||
// Check for updates and potentially install one.
|
|
||||||
if err := updates.CliCheckForUpdates(cfg, req.Context().ConfigRoot); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// this sets up the function that will initialize the node
|
// this sets up the function that will initialize the node
|
||||||
// this is so that we can construct the node lazily.
|
// this is so that we can construct the node lazily.
|
||||||
ctx := req.Context()
|
ctx := req.Context()
|
||||||
@ -266,13 +303,11 @@ func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandShouldRunOnDaemon(req cmds.Request, root *cmds.Command) (bool, error) {
|
// commandDetails returns a command's details for the command given by |path|
|
||||||
path := req.Path()
|
// within the |root| command tree.
|
||||||
// root command.
|
//
|
||||||
if len(path) < 1 {
|
// Returns an error if the command is not found in the Command tree.
|
||||||
return false, nil
|
func commandDetails(path []string, root *cmds.Command) (*cmdDetails, error) {
|
||||||
}
|
|
||||||
|
|
||||||
var details cmdDetails
|
var details cmdDetails
|
||||||
// find the last command in path that has a cmdDetailsMap entry
|
// find the last command in path that has a cmdDetailsMap entry
|
||||||
cmd := root
|
cmd := root
|
||||||
@ -280,7 +315,7 @@ func commandShouldRunOnDaemon(req cmds.Request, root *cmds.Command) (bool, error
|
|||||||
var found bool
|
var found bool
|
||||||
cmd, found = cmd.Subcommands[cmp]
|
cmd, found = cmd.Subcommands[cmp]
|
||||||
if !found {
|
if !found {
|
||||||
return false, fmt.Errorf("subcommand %s should be in root", cmp)
|
return nil, debugerror.Errorf("subcommand %s should be in root", cmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmdDetails, found := cmdDetailsMap[cmd]; found {
|
if cmdDetails, found := cmdDetailsMap[cmd]; found {
|
||||||
@ -288,6 +323,21 @@ func commandShouldRunOnDaemon(req cmds.Request, root *cmds.Command) (bool, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debugf("cmd perms for +%v: %s", path, details.String())
|
log.Debugf("cmd perms for +%v: %s", path, details.String())
|
||||||
|
return &details, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// commandShouldRunOnDaemon determines, from commmand details, whether a
|
||||||
|
// command ought to be executed on an IPFS daemon.
|
||||||
|
//
|
||||||
|
// It returns true if the command should be executed on a daemon and false if
|
||||||
|
// it should be executed on a client. It returns an error if the command must
|
||||||
|
// NOT be executed on either.
|
||||||
|
func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.Command) (bool, error) {
|
||||||
|
path := req.Path()
|
||||||
|
// root command.
|
||||||
|
if len(path) < 1 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
if details.cannotRunOnClient && details.cannotRunOnDaemon {
|
if details.cannotRunOnClient && details.cannotRunOnDaemon {
|
||||||
return false, fmt.Errorf("command disabled: %s", path[0])
|
return false, fmt.Errorf("command disabled: %s", path[0])
|
||||||
|
@ -5,11 +5,11 @@ import (
|
|||||||
"crypto"
|
"crypto"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
u "github.com/jbenet/go-ipfs/util"
|
u "github.com/jbenet/go-ipfs/util"
|
||||||
|
"github.com/jbenet/go-ipfs/util/debugerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = u.Logger("config")
|
var log = u.Logger("config")
|
||||||
@ -129,7 +129,7 @@ func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error
|
|||||||
func Load(filename string) (*Config, error) {
|
func Load(filename string) (*Config, error) {
|
||||||
// if nothing is there, fail. User must run 'ipfs init'
|
// if nothing is there, fail. User must run 'ipfs init'
|
||||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
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
|
var cfg Config
|
||||||
|
30
util/debugerror/debugerror.go
Normal file
30
util/debugerror/debugerror.go
Normal file
@ -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
|
||||||
|
}
|
Reference in New Issue
Block a user