Skip to content

Commit a36075a

Browse files
committed
Use the compile-time GOROOT instead of the run-time GOROOT.
1 parent ac4c579 commit a36075a

File tree

1 file changed

+52
-42
lines changed

1 file changed

+52
-42
lines changed

stack.go

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"errors"
1515
"fmt"
1616
"io"
17-
"path/filepath"
1817
"runtime"
1918
"strconv"
2019
"strings"
@@ -94,43 +93,7 @@ func (c Call) Format(s fmt.State, verb rune) {
9493
case s.Flag('#'):
9594
// done
9695
case s.Flag('+'):
97-
// Here we want to get the source file path relative to the
98-
// compile time GOPATH. As of Go 1.4.x there is no direct way to
99-
// know the compiled GOPATH at runtime, but we can infer the
100-
// number of path segments in the GOPATH. We note that fn.Name()
101-
// returns the function name qualified by the import path, which
102-
// does not include the GOPATH. Thus we can trim segments from the
103-
// beginning of the file path until the number of path separators
104-
// remaining is one more than the number of path separators in the
105-
// function name. For example, given:
106-
//
107-
// GOPATH /home/user
108-
// file /home/user/src/pkg/sub/file.go
109-
// fn.Name() pkg/sub.Type.Method
110-
//
111-
// We want to produce:
112-
//
113-
// pkg/sub/file.go
114-
//
115-
// From this we can easily see that fn.Name() has one less path
116-
// separator than our desired output. We count separators from the
117-
// end of the file path until it finds two more than in the
118-
// function name and then move one character forward to preserve
119-
// the initial path segment without a leading separator.
120-
const sep = "/"
121-
goal := strings.Count(c.fn.Name(), sep) + 2
122-
pathCnt := 0
123-
i := len(file)
124-
for pathCnt < goal {
125-
i = strings.LastIndex(file[:i], sep)
126-
if i == -1 {
127-
i = -len(sep)
128-
break
129-
}
130-
pathCnt++
131-
}
132-
// get back to 0 or trim the leading seperator
133-
file = file[i+len(sep):]
96+
file = file[pkgIndex(file, c.fn.Name()):]
13497
default:
13598
const sep = "/"
13699
if i := strings.LastIndex(file, sep); i != -1 {
@@ -308,12 +271,59 @@ func (cs CallStack) TrimAbove(c Call) CallStack {
308271
return cs
309272
}
310273

311-
var goroot string
274+
// pkgIndex returns the index that results in file[index:] being the path of
275+
// file relative to the compile time GOPATH, and file[:index] being the
276+
// $GOPATH/src/ portion of file. funcName must be the name of a function in
277+
// file as returned by runtime.Func.Name.
278+
func pkgIndex(file, funcName string) int {
279+
// As of Go 1.6.2 there is no direct way to know the compile time GOPATH
280+
// at runtime, but we can infer the number of path segments in the GOPATH.
281+
// We note that runtime.Func.Name() returns the function name qualified by
282+
// the import path, which does not include the GOPATH. Thus we can trim
283+
// segments from the beginning of the file path until the number of path
284+
// separators remaining is one more than the number of path separators in
285+
// the function name. For example, given:
286+
//
287+
// GOPATH /home/user
288+
// file /home/user/src/pkg/sub/file.go
289+
// fn.Name() pkg/sub.Type.Method
290+
//
291+
// We want to produce:
292+
//
293+
// file[:idx] == /home/user/src/
294+
// file[idx:] == pkg/sub/file.go
295+
//
296+
// From this we can easily see that fn.Name() has one less path separator
297+
// than our desired result for file[idx:]. We count separators from the
298+
// end of the file path until it finds two more than in the function name
299+
// and then move one character forward to preserve the initial path
300+
// segment without a leading separator.
301+
const sep = "/"
302+
i := len(file)
303+
for n := strings.Count(funcName, sep) + 2; n > 0; n-- {
304+
i = strings.LastIndex(file[:i], sep)
305+
if i == -1 {
306+
i = -len(sep)
307+
break
308+
}
309+
}
310+
// get back to 0 or trim the leading seperator
311+
return i + len(sep)
312+
}
313+
314+
var runtimePath string
312315

313316
func init() {
314-
goroot = filepath.ToSlash(runtime.GOROOT())
317+
var pcs [1]uintptr
318+
runtime.Callers(0, pcs[:])
319+
fn := runtime.FuncForPC(pcs[0])
320+
file, _ := fn.FileLine(pcs[0])
321+
322+
idx := pkgIndex(file, fn.Name())
323+
324+
runtimePath = file[:idx]
315325
if runtime.GOOS == "windows" {
316-
goroot = strings.ToLower(goroot)
326+
runtimePath = strings.ToLower(runtimePath)
317327
}
318328
}
319329

@@ -325,7 +335,7 @@ func inGoroot(c Call) bool {
325335
if runtime.GOOS == "windows" {
326336
file = strings.ToLower(file)
327337
}
328-
return strings.HasPrefix(file, goroot) || strings.HasSuffix(file, "/_testmain.go")
338+
return strings.HasPrefix(file, runtimePath) || strings.HasSuffix(file, "/_testmain.go")
329339
}
330340

331341
// TrimRuntime returns a slice of the CallStack with the topmost entries from

0 commit comments

Comments
 (0)