Skip to content

Commit 16720d5

Browse files
committed
go/packages: allow absolute paths when using the fallback
Another change to bring the go1.10 fallback's functionality in line with the go1.11 go list implementation. The fallback now uses go env to determine GOPATH and GOROOT and searches them to see if any match an absolute path, and if so trims the GOPATH/GOROOT entry off the start of the path. Fixes golang/go#27734 Change-Id: Ibd2313fc4301d42fd8c0cd98f1f3e7a313d65eb7 Reviewed-on: https://go-review.googlesource.com/137096 Run-TryBot: Michael Matloob <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent 51aacb1 commit 16720d5

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

go/packages/golist_fallback.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go/build"
1111
"io/ioutil"
1212
"os"
13+
"os/exec"
1314
"path/filepath"
1415
"sort"
1516
"strings"
@@ -27,6 +28,12 @@ import (
2728
// in Q1 2019.
2829

2930
func golistDriverFallback(cfg *Config, words ...string) (*driverResponse, error) {
31+
// Turn absolute paths into GOROOT and GOPATH-relative paths to provide to go list.
32+
// This will have surprising behavior if GOROOT or GOPATH contain multiple packages with the same
33+
// path and a user provides an absolute path to a directory that's shadowed by an earlier
34+
// directory in GOROOT or GOPATH with the same package path.
35+
words = cleanAbsPaths(cfg, words)
36+
3037
original, deps, err := getDeps(cfg, words...)
3138
if err != nil {
3239
return nil, err
@@ -283,6 +290,47 @@ func createTestVariants(response *driverResponse, pkgUnderTest, xtestPkg *Packag
283290
}
284291
}
285292

293+
// cleanAbsPaths replaces all absolute paths with GOPATH- and GOROOT-relative
294+
// paths. If an absolute path is not GOPATH- or GOROOT- relative, it is left as an
295+
// absolute path so an error can be returned later.
296+
func cleanAbsPaths(cfg *Config, words []string) []string {
297+
var searchpaths []string
298+
var cleaned = make([]string, len(words))
299+
for i := range cleaned {
300+
cleaned[i] = words[i]
301+
if !filepath.IsAbs(cleaned[i]) {
302+
continue
303+
}
304+
// otherwise, it's an absolute path. Search GOPATH and GOROOT to find it.
305+
if searchpaths == nil {
306+
cmd := exec.Command("go", "env", "GOPATH", "GOROOT")
307+
cmd.Env = cfg.Env
308+
out, err := cmd.Output()
309+
if err != nil {
310+
searchpaths = []string{}
311+
continue // suppress the error, it will show up again when running go list
312+
}
313+
lines := strings.Split(string(out), "\n")
314+
if len(lines) != 3 || lines[0] == "" || lines[1] == "" || lines[2] != "" {
315+
continue // suppress error
316+
}
317+
// first line is GOPATH
318+
for _, path := range filepath.SplitList(lines[0]) {
319+
searchpaths = append(searchpaths, filepath.Join(path, "src"))
320+
}
321+
// second line is GOROOT
322+
searchpaths = append(searchpaths, filepath.Join(lines[1], "src"))
323+
}
324+
for _, sp := range searchpaths {
325+
if strings.HasPrefix(cleaned[i], sp) {
326+
cleaned[i] = strings.TrimPrefix(cleaned[i], sp)
327+
cleaned[i] = strings.TrimLeft(cleaned[i], string(filepath.Separator))
328+
}
329+
}
330+
}
331+
return cleaned
332+
}
333+
286334
// vendorlessPath returns the devendorized version of the import path ipath.
287335
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
288336
// Copied from golang.org/x/tools/imports/fix.go.

go/packages/packages_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,33 @@ func TestLoadImportsC(t *testing.T) {
331331
}
332332
}
333333

334+
func TestLoadAbsolutePath(t *testing.T) {
335+
tmp, cleanup := makeTree(t, map[string]string{
336+
"gopatha/src/a/a.go": `package a`,
337+
"gopathb/src/b/b.go": `package b`,
338+
})
339+
defer cleanup()
340+
341+
cfg := &packages.Config{
342+
Mode: packages.LoadImports,
343+
Env: append(os.Environ(),
344+
"GOPATH="+filepath.Join(tmp, "gopatha")+string(filepath.ListSeparator)+filepath.Join(tmp, "gopathb"),
345+
"GO111MODULE=off"),
346+
}
347+
initial, err := packages.Load(cfg, filepath.Join(tmp, "gopatha", "src", "a"), filepath.Join(tmp, "gopathb", "src", "b"))
348+
if err != nil {
349+
t.Fatalf("failed to load imports: %v", err)
350+
}
351+
352+
got := []string{}
353+
for _, p := range initial {
354+
got = append(got, p.ID)
355+
}
356+
if !reflect.DeepEqual(got, []string{"a", "b"}) {
357+
t.Fatalf("initial packages loaded: got [%s], want [a b]", got)
358+
}
359+
}
360+
334361
func TestVendorImports(t *testing.T) {
335362
tmp, cleanup := makeTree(t, map[string]string{
336363
"src/a/a.go": `package a; import _ "b"; import _ "c";`,

0 commit comments

Comments
 (0)