From 665006faabd7211e3f20f84ec2c1b3dd3f26b83f Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Sun, 24 Apr 2016 20:41:47 -0400 Subject: [PATCH 1/2] Infer compile time GOPATH from fn.Name(). --- errors.go | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/errors.go b/errors.go index 7ebcbba..b098f60 100644 --- a/errors.go +++ b/errors.go @@ -65,11 +65,45 @@ func (l loc) Location() (string, int) { return "unknown", 0 } - _, prefix, _, _ := runtime.Caller(0) file, line := fn.FileLine(pc) - if i := strings.LastIndex(prefix, "github.com/pkg/errors"); i > 0 { - file = file[i:] + + // Here we want to get the source file path relative to the compile time + // GOPATH. As of Go 1.6.x there is no direct way to know the compiled + // GOPATH at runtime, but we can infer the number of path segments in the + // GOPATH. We note that fn.Name() returns the function name qualified by + // the import path, which does not include the GOPATH. Thus we can trim + // segments from the beginning of the file path until the number of path + // separators remaining is one more than the number of path separators in + // the function name. For example, given: + // + // GOPATH /home/user + // file /home/user/src/pkg/sub/file.go + // fn.Name() pkg/sub.Type.Method + // + // We want to produce: + // + // pkg/sub/file.go + // + // From this we can easily see that fn.Name() has one less path separator + // than our desired output. We count separators from the end of the file + // path until it finds two more than in the function name and then move + // one character forward to preserve the initial path segment without a + // leading separator. + const sep = "/" + goal := strings.Count(fn.Name(), sep) + 2 + pathCnt := 0 + i := len(file) + for pathCnt < goal { + i = strings.LastIndex(file[:i], sep) + if i == -1 { + i = -len(sep) + break + } + pathCnt++ } + // get back to 0 or trim the leading seperator + file = file[i+len(sep):] + return file, line } From 046fc1474d6e1ace7eea71434c0d96f0685a2d6f Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Sun, 24 Apr 2016 21:36:07 -0400 Subject: [PATCH 2/2] Updates from code review. --- errors.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/errors.go b/errors.go index b098f60..30b5885 100644 --- a/errors.go +++ b/errors.go @@ -91,15 +91,15 @@ func (l loc) Location() (string, int) { // leading separator. const sep = "/" goal := strings.Count(fn.Name(), sep) + 2 - pathCnt := 0 i := len(file) - for pathCnt < goal { + for n := 0; n < goal; n++ { i = strings.LastIndex(file[:i], sep) if i == -1 { + // not enough separators found, set i so that the slice expression + // below leaves file unmodified i = -len(sep) break } - pathCnt++ } // get back to 0 or trim the leading seperator file = file[i+len(sep):]