|
|
@@ -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
|
|
|
}
|
|
|
|