Jelajahi Sumber

Merge branch 'master' into patch-1

Dave Cheney 7 tahun lalu
induk
melakukan
c1bc528f85
6 mengubah file dengan 129 tambahan dan 96 penghapusan
  1. 2 6
      .travis.yml
  2. 52 0
      Makefile
  3. 9 2
      README.md
  4. 1 1
      errors.go
  5. 23 25
      stack.go
  6. 42 62
      stack_test.go

+ 2 - 6
.travis.yml

@@ -1,14 +1,10 @@
 language: go
 go_import_path: github.com/pkg/errors
 go:
-  - 1.4.x
-  - 1.5.x
-  - 1.6.x
-  - 1.7.x
-  - 1.8.x
   - 1.9.x
   - 1.10.x
+  - 1.11.x
   - tip
 
 script:
-  - go test -v ./...
+  - make check

+ 52 - 0
Makefile

@@ -0,0 +1,52 @@
+PKGS := github.com/pkg/errors
+SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
+GO := go
+
+check: test vet gofmt unused misspell unconvert gosimple ineffassign
+
+test: 
+	$(GO) test $(PKGS)
+
+vet: | test
+	$(GO) vet $(PKGS)
+
+staticcheck:
+	$(GO) get honnef.co/go/tools/cmd/staticcheck
+	staticcheck $(PKGS)
+
+unused:
+	$(GO) get honnef.co/go/tools/cmd/unused
+	unused -exported $(PKGS)
+
+misspell:
+	$(GO) get github.com/client9/misspell/cmd/misspell
+	misspell \
+		-locale GB \
+		-error \
+		*.md *.go
+
+unconvert:
+	$(GO) get github.com/mdempsky/unconvert
+	unconvert -v $(PKGS)
+
+gosimple:
+	$(GO) get honnef.co/go/tools/cmd/gosimple
+	gosimple $(PKGS)
+
+ineffassign:
+	$(GO) get github.com/gordonklaus/ineffassign
+	find $(SRCDIRS) -name '*.go' | xargs ineffassign
+
+pedantic: check unparam errcheck staticcheck
+
+unparam:
+	$(GO) get mvdan.cc/unparam
+	unparam ./...
+
+errcheck:
+	$(GO) get github.com/kisielk/errcheck
+	errcheck $(PKGS)
+
+gofmt:  
+	@echo Checking code is gofmted
+	@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

+ 9 - 2
README.md

@@ -41,11 +41,18 @@ default:
 
 [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
 
+## Roadmap
+
+With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
+
+- 0.9. Remove pre Go 1.9 support, address outstanding pull requests (if possible)
+- 1.0. Final release.
+
 ## Contributing
 
-We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
+Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. 
 
-Before proposing a change, please discuss your change by raising an issue.
+Before sending a PR, please discuss your change by raising an issue.
 
 ## License
 

+ 1 - 1
errors.go

@@ -229,7 +229,7 @@ func WithMessagef(err error, format string, args ...interface{}) error {
 	}
 	return &withMessage{
 		cause: err,
-		msg: fmt.Sprintf(format, args...),
+		msg:   fmt.Sprintf(format, args...),
 	}
 }
 

+ 23 - 25
stack.go

@@ -9,32 +9,22 @@ import (
 )
 
 // Frame represents a program counter inside a stack frame.
-type Frame uintptr
-
-// pc returns the program counter for this frame;
-// multiple frames may have the same PC value.
-func (f Frame) pc() uintptr { return uintptr(f) - 1 }
+type Frame runtime.Frame
 
 // file returns the full path to the file that contains the
 // function for this Frame's pc.
 func (f Frame) file() string {
-	fn := runtime.FuncForPC(f.pc())
-	if fn == nil {
+	file := runtime.Frame(f).File
+	if file == "" {
 		return "unknown"
 	}
-	file, _ := fn.FileLine(f.pc())
 	return file
 }
 
 // line returns the line number of source code of the
 // function for this Frame's pc.
 func (f Frame) line() int {
-	fn := runtime.FuncForPC(f.pc())
-	if fn == nil {
-		return 0
-	}
-	_, line := fn.FileLine(f.pc())
-	return line
+	return runtime.Frame(f).Line
 }
 
 // Format formats the frame according to the fmt.Formatter interface.
@@ -54,12 +44,11 @@ func (f Frame) Format(s fmt.State, verb rune) {
 	case 's':
 		switch {
 		case s.Flag('+'):
-			pc := f.pc()
-			fn := runtime.FuncForPC(pc)
+			fn := runtime.Frame(f).Func
 			if fn == nil {
 				io.WriteString(s, "unknown")
 			} else {
-				file, _ := fn.FileLine(pc)
+				file := runtime.Frame(f).File
 				fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
 			}
 		default:
@@ -68,7 +57,7 @@ func (f Frame) Format(s fmt.State, verb rune) {
 	case 'd':
 		fmt.Fprintf(s, "%d", f.line())
 	case 'n':
-		name := runtime.FuncForPC(f.pc()).Name()
+		name := runtime.Frame(f).Function
 		io.WriteString(s, funcname(name))
 	case 'v':
 		f.Format(s, 's')
@@ -114,20 +103,29 @@ func (s *stack) Format(st fmt.State, verb rune) {
 	case 'v':
 		switch {
 		case st.Flag('+'):
-			for _, pc := range *s {
-				f := Frame(pc)
-				fmt.Fprintf(st, "\n%+v", f)
+			frames := runtime.CallersFrames(*s)
+			for {
+				frame, more := frames.Next()
+				fmt.Fprintf(st, "\n%+v", Frame(frame))
+				if !more {
+					break
+				}
 			}
 		}
 	}
 }
 
 func (s *stack) StackTrace() StackTrace {
-	f := make([]Frame, len(*s))
-	for i := 0; i < len(f); i++ {
-		f[i] = Frame((*s)[i])
+	var st []Frame
+	frames := runtime.CallersFrames(*s)
+	for {
+		frame, more := frames.Next()
+		st = append(st, Frame(frame))
+		if !more {
+			break
+		}
 	}
-	return f
+	return st
 }
 
 func callers() *stack {

+ 42 - 62
stack_test.go

@@ -6,51 +6,18 @@ import (
 	"testing"
 )
 
-var initpc, _, _, _ = runtime.Caller(0)
-
-func TestFrameLine(t *testing.T) {
-	var tests = []struct {
-		Frame
-		want int
-	}{{
-		Frame(initpc),
-		9,
-	}, {
-		func() Frame {
-			var pc, _, _, _ = runtime.Caller(0)
-			return Frame(pc)
-		}(),
-		20,
-	}, {
-		func() Frame {
-			var pc, _, _, _ = runtime.Caller(1)
-			return Frame(pc)
-		}(),
-		28,
-	}, {
-		Frame(0), // invalid PC
-		0,
-	}}
-
-	for _, tt := range tests {
-		got := tt.Frame.line()
-		want := tt.want
-		if want != got {
-			t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
-		}
-	}
-}
+var initpc = caller()
 
 type X struct{}
 
+// val returns a Frame pointing to itself.
 func (x X) val() Frame {
-	var pc, _, _, _ = runtime.Caller(0)
-	return Frame(pc)
+	return caller()
 }
 
+// ptr returns a Frame pointing to itself.
 func (x *X) ptr() Frame {
-	var pc, _, _, _ = runtime.Caller(0)
-	return Frame(pc)
+	return caller()
 }
 
 func TestFrameFormat(t *testing.T) {
@@ -59,32 +26,32 @@ func TestFrameFormat(t *testing.T) {
 		format string
 		want   string
 	}{{
-		Frame(initpc),
+		initpc,
 		"%s",
 		"stack_test.go",
 	}, {
-		Frame(initpc),
+		initpc,
 		"%+s",
 		"github.com/pkg/errors.init\n" +
 			"\t.+/github.com/pkg/errors/stack_test.go",
 	}, {
-		Frame(0),
+		Frame{},
 		"%s",
 		"unknown",
 	}, {
-		Frame(0),
+		Frame{},
 		"%+s",
 		"unknown",
 	}, {
-		Frame(initpc),
+		initpc,
 		"%d",
 		"9",
 	}, {
-		Frame(0),
+		Frame{},
 		"%d",
 		"0",
 	}, {
-		Frame(initpc),
+		initpc,
 		"%n",
 		"init",
 	}, {
@@ -102,20 +69,20 @@ func TestFrameFormat(t *testing.T) {
 		"%n",
 		"X.val",
 	}, {
-		Frame(0),
+		Frame{},
 		"%n",
 		"",
 	}, {
-		Frame(initpc),
+		initpc,
 		"%v",
 		"stack_test.go:9",
 	}, {
-		Frame(initpc),
+		initpc,
 		"%+v",
 		"github.com/pkg/errors.init\n" +
 			"\t.+/github.com/pkg/errors/stack_test.go:9",
 	}, {
-		Frame(0),
+		Frame{},
 		"%v",
 		"unknown:0",
 	}}
@@ -153,24 +120,24 @@ func TestStackTrace(t *testing.T) {
 	}{{
 		New("ooh"), []string{
 			"github.com/pkg/errors.TestStackTrace\n" +
-				"\t.+/github.com/pkg/errors/stack_test.go:154",
+				"\t.+/github.com/pkg/errors/stack_test.go:121",
 		},
 	}, {
 		Wrap(New("ooh"), "ahh"), []string{
 			"github.com/pkg/errors.TestStackTrace\n" +
-				"\t.+/github.com/pkg/errors/stack_test.go:159", // this is the stack of Wrap, not New
+				"\t.+/github.com/pkg/errors/stack_test.go:126", // this is the stack of Wrap, not New
 		},
 	}, {
 		Cause(Wrap(New("ooh"), "ahh")), []string{
 			"github.com/pkg/errors.TestStackTrace\n" +
-				"\t.+/github.com/pkg/errors/stack_test.go:164", // this is the stack of New
+				"\t.+/github.com/pkg/errors/stack_test.go:131", // this is the stack of New
 		},
 	}, {
-		func() error { return New("ooh") }(), []string{
+		func() error { noinline(); return New("ooh") }(), []string{
 			`github.com/pkg/errors.(func·009|TestStackTrace.func1)` +
-				"\n\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New
+				"\n\t.+/github.com/pkg/errors/stack_test.go:136", // this is the stack of New
 			"github.com/pkg/errors.TestStackTrace\n" +
-				"\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New's caller
+				"\t.+/github.com/pkg/errors/stack_test.go:136", // this is the stack of New's caller
 		},
 	}, {
 		Cause(func() error {
@@ -179,11 +146,11 @@ func TestStackTrace(t *testing.T) {
 			}()
 		}()), []string{
 			`github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` +
-				"\n\t.+/github.com/pkg/errors/stack_test.go:178", // this is the stack of Errorf
+				"\n\t.+/github.com/pkg/errors/stack_test.go:145", // this is the stack of Errorf
 			`github.com/pkg/errors.(func·011|TestStackTrace.func2)` +
-				"\n\t.+/github.com/pkg/errors/stack_test.go:179", // this is the stack of Errorf's caller
+				"\n\t.+/github.com/pkg/errors/stack_test.go:146", // this is the stack of Errorf's caller
 			"github.com/pkg/errors.TestStackTrace\n" +
-				"\t.+/github.com/pkg/errors/stack_test.go:180", // this is the stack of Errorf's caller's caller
+				"\t.+/github.com/pkg/errors/stack_test.go:147", // this is the stack of Errorf's caller's caller
 		},
 	}}
 	for i, tt := range tests {
@@ -253,22 +220,35 @@ func TestStackTraceFormat(t *testing.T) {
 	}, {
 		stackTrace()[:2],
 		"%v",
-		`\[stack_test.go:207 stack_test.go:254\]`,
+		`\[stack_test.go:174 stack_test.go:221\]`,
 	}, {
 		stackTrace()[:2],
 		"%+v",
 		"\n" +
 			"github.com/pkg/errors.stackTrace\n" +
-			"\t.+/github.com/pkg/errors/stack_test.go:207\n" +
+			"\t.+/github.com/pkg/errors/stack_test.go:174\n" +
 			"github.com/pkg/errors.TestStackTraceFormat\n" +
-			"\t.+/github.com/pkg/errors/stack_test.go:258",
+			"\t.+/github.com/pkg/errors/stack_test.go:225",
 	}, {
 		stackTrace()[:2],
 		"%#v",
-		`\[\]errors.Frame{stack_test.go:207, stack_test.go:266}`,
+		`\[\]errors.Frame{stack_test.go:174, stack_test.go:233}`,
 	}}
 
 	for i, tt := range tests {
 		testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
 	}
 }
+
+// a version of runtime.Caller that returns a Frame, not a uintptr.
+func caller() Frame {
+	var pcs [3]uintptr
+	n := runtime.Callers(2, pcs[:])
+	frames := runtime.CallersFrames(pcs[:n])
+	frame, _ := frames.Next()
+	return Frame(frame)
+}
+
+//go:noinline
+// noinline prevents the caller being inlined
+func noinline() {}