diff --git a/src/cmd/internal/objabi/line.go b/src/cmd/internal/objabi/line.go index 1c671b211f831..178c8363d95d8 100644 --- a/src/cmd/internal/objabi/line.go +++ b/src/cmd/internal/objabi/line.go @@ -7,6 +7,7 @@ package objabi import ( "os" "path/filepath" + "strings" ) // WorkingDir returns the current working directory @@ -21,32 +22,63 @@ func WorkingDir() string { return filepath.ToSlash(path) } -// AbsFile returns the absolute filename for file in the given directory. -// It also removes a leading pathPrefix, or else rewrites a leading $GOROOT -// prefix to the literal "$GOROOT". +// AbsFile returns the absolute filename for file in the given directory, +// as rewritten by the rewrites argument. +// For unrewritten paths, AbsFile rewrites a leading $GOROOT prefix to the literal "$GOROOT". // If the resulting path is the empty string, the result is "??". -func AbsFile(dir, file, pathPrefix string) string { +// +// The rewrites argument is a ;-separated list of rewrites. +// Each rewrite is of the form "prefix" or "prefix=>replace", +// where prefix must match a leading sequence of path elements +// and is either removed entirely or replaced by the replacement. +func AbsFile(dir, file, rewrites string) string { abs := file if dir != "" && !filepath.IsAbs(file) { abs = filepath.Join(dir, file) } - if pathPrefix != "" && hasPathPrefix(abs, pathPrefix) { - if abs == pathPrefix { - abs = "" - } else { - abs = abs[len(pathPrefix)+1:] + start := 0 + for i := 0; i <= len(rewrites); i++ { + if i == len(rewrites) || rewrites[i] == ';' { + if new, ok := applyRewrite(abs, rewrites[start:i]); ok { + abs = new + goto Rewritten + } + start = i + 1 } - } else if hasPathPrefix(abs, GOROOT) { + } + if hasPathPrefix(abs, GOROOT) { abs = "$GOROOT" + abs[len(GOROOT):] } + +Rewritten: if abs == "" { abs = "??" } - return abs } +// applyRewrite applies the rewrite to the path, +// returning the rewritten path and a boolean +// indicating whether the rewrite applied at all. +func applyRewrite(path, rewrite string) (string, bool) { + prefix, replace := rewrite, "" + if j := strings.LastIndex(rewrite, "=>"); j >= 0 { + prefix, replace = rewrite[:j], rewrite[j+len("=>"):] + } + + if prefix == "" || !hasPathPrefix(path, prefix) { + return path, false + } + if len(path) == len(prefix) { + return replace, true + } + if replace == "" { + return path[len(prefix)+1:], true + } + return replace + path[len(prefix):], true +} + // Does s have t as a path prefix? // That is, does s == t or does s begin with t followed by a slash? // For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true. diff --git a/src/cmd/internal/objabi/line_test.go b/src/cmd/internal/objabi/line_test.go new file mode 100644 index 0000000000000..1fa0ff112ce17 --- /dev/null +++ b/src/cmd/internal/objabi/line_test.go @@ -0,0 +1,50 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "path/filepath" + "runtime" + "testing" +) + +// On Windows, "/foo" is reported as a relative path +// (it is relative to the current drive letter), +// so we need add a drive letter to test absolute path cases. +func drive() string { + if runtime.GOOS == "windows" { + return "c:" + } + return "" +} + +var absFileTests = []struct { + dir string + file string + rewrites string + abs string +}{ + {"/d", "f", "", "/d/f"}, + {"/d", drive() + "/f", "", drive() + "/f"}, + {"/d", "f/g", "", "/d/f/g"}, + {"/d", drive() + "/f/g", "", drive() + "/f/g"}, + + {"/d", "f", "/d/f", "??"}, + {"/d", "f/g", "/d/f", "g"}, + {"/d", "f/g", "/d/f=>h", "h/g"}, + {"/d", "f/g", "/d/f=>/h", "/h/g"}, + {"/d", "f/g", "/d/f=>/h;/d/e=>/i", "/h/g"}, + {"/d", "e/f", "/d/f=>/h;/d/e=>/i", "/i/f"}, +} + +func TestAbsFile(t *testing.T) { + for _, tt := range absFileTests { + abs := filepath.FromSlash(AbsFile(filepath.FromSlash(tt.dir), filepath.FromSlash(tt.file), tt.rewrites)) + want := filepath.FromSlash(tt.abs) + if abs != want { + t.Errorf("AbsFile(%q, %q, %q) = %q, want %q", tt.dir, tt.file, tt.rewrites, abs, want) + } + } +}