1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:54:42 -07:00

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 <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
Michael Matloob 2018-09-24 17:54:34 -04:00
parent 51aacb1402
commit 16720d5f2d
2 changed files with 75 additions and 0 deletions

View File

@ -10,6 +10,7 @@ import (
"go/build"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
@ -27,6 +28,12 @@ import (
// in Q1 2019.
func golistDriverFallback(cfg *Config, words ...string) (*driverResponse, error) {
// Turn absolute paths into GOROOT and GOPATH-relative paths to provide to go list.
// This will have surprising behavior if GOROOT or GOPATH contain multiple packages with the same
// path and a user provides an absolute path to a directory that's shadowed by an earlier
// directory in GOROOT or GOPATH with the same package path.
words = cleanAbsPaths(cfg, words)
original, deps, err := getDeps(cfg, words...)
if err != nil {
return nil, err
@ -283,6 +290,47 @@ func createTestVariants(response *driverResponse, pkgUnderTest, xtestPkg *Packag
}
}
// cleanAbsPaths replaces all absolute paths with GOPATH- and GOROOT-relative
// paths. If an absolute path is not GOPATH- or GOROOT- relative, it is left as an
// absolute path so an error can be returned later.
func cleanAbsPaths(cfg *Config, words []string) []string {
var searchpaths []string
var cleaned = make([]string, len(words))
for i := range cleaned {
cleaned[i] = words[i]
if !filepath.IsAbs(cleaned[i]) {
continue
}
// otherwise, it's an absolute path. Search GOPATH and GOROOT to find it.
if searchpaths == nil {
cmd := exec.Command("go", "env", "GOPATH", "GOROOT")
cmd.Env = cfg.Env
out, err := cmd.Output()
if err != nil {
searchpaths = []string{}
continue // suppress the error, it will show up again when running go list
}
lines := strings.Split(string(out), "\n")
if len(lines) != 3 || lines[0] == "" || lines[1] == "" || lines[2] != "" {
continue // suppress error
}
// first line is GOPATH
for _, path := range filepath.SplitList(lines[0]) {
searchpaths = append(searchpaths, filepath.Join(path, "src"))
}
// second line is GOROOT
searchpaths = append(searchpaths, filepath.Join(lines[1], "src"))
}
for _, sp := range searchpaths {
if strings.HasPrefix(cleaned[i], sp) {
cleaned[i] = strings.TrimPrefix(cleaned[i], sp)
cleaned[i] = strings.TrimLeft(cleaned[i], string(filepath.Separator))
}
}
}
return cleaned
}
// vendorlessPath returns the devendorized version of the import path ipath.
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
// Copied from golang.org/x/tools/imports/fix.go.

View File

@ -331,6 +331,33 @@ func TestLoadImportsC(t *testing.T) {
}
}
func TestLoadAbsolutePath(t *testing.T) {
tmp, cleanup := makeTree(t, map[string]string{
"gopatha/src/a/a.go": `package a`,
"gopathb/src/b/b.go": `package b`,
})
defer cleanup()
cfg := &packages.Config{
Mode: packages.LoadImports,
Env: append(os.Environ(),
"GOPATH="+filepath.Join(tmp, "gopatha")+string(filepath.ListSeparator)+filepath.Join(tmp, "gopathb"),
"GO111MODULE=off"),
}
initial, err := packages.Load(cfg, filepath.Join(tmp, "gopatha", "src", "a"), filepath.Join(tmp, "gopathb", "src", "b"))
if err != nil {
t.Fatalf("failed to load imports: %v", err)
}
got := []string{}
for _, p := range initial {
got = append(got, p.ID)
}
if !reflect.DeepEqual(got, []string{"a", "b"}) {
t.Fatalf("initial packages loaded: got [%s], want [a b]", got)
}
}
func TestVendorImports(t *testing.T) {
tmp, cleanup := makeTree(t, map[string]string{
"src/a/a.go": `package a; import _ "b"; import _ "c";`,