Merge pull request #9 from ChrisHines/location-path-fix
Infer compile time GOPATH from fn.Name().
diff --git a/errors.go b/errors.go
index 7ebcbba..30b5885 100644
--- a/errors.go
+++ b/errors.go
@@ -65,11 +65,45 @@
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
+ i := len(file)
+ 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
+ }
}
+ // get back to 0 or trim the leading seperator
+ file = file[i+len(sep):]
+
return file, line
}