go/packages: prefer import map to identity imports
For any identity imports to be added to the import map of a package,
make sure these are not already in there. If the package imports "C",
be sure not to overwrite the import map entries for "runtime/cgo", "unsafe",
and "syscall".
Test the import map when test variants are loaded. This tests the fix
in 'go list' made by https://golang.org/cl/128836
Fixes golang/go#26847
Change-Id: I05dff4d3a75fab03f333f6d88128de6a6bf169e6
Reviewed-on: https://go-review.googlesource.com/128876
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/go/packages/golist.go b/go/packages/golist.go
index 3e9d1e0..26d6277 100644
--- a/go/packages/golist.go
+++ b/go/packages/golist.go
@@ -230,13 +230,7 @@
delete(ids, id)
}
for id := range ids {
- // Go issue 26136: go list omits imports in cgo-generated files.
if id == "C" {
- imports["unsafe"] = &Package{ID: "unsafe"}
- imports["syscall"] = &Package{ID: "syscall"}
- if pkgpath != "runtime/cgo" {
- imports["runtime/cgo"] = &Package{ID: "runtime/cgo"}
- }
continue
}
diff --git a/go/packages/golist_fallback.go b/go/packages/golist_fallback.go
index 79400de..331bb655 100644
--- a/go/packages/golist_fallback.go
+++ b/go/packages/golist_fallback.go
@@ -54,10 +54,10 @@
for _, id := range importlist {
if id == "C" {
- importMap["unsafe"] = &Package{ID: "unsafe"}
- importMap["syscall"] = &Package{ID: "syscall"}
- if pkgpath != "runtime/cgo" {
- importMap["runtime/cgo"] = &Package{ID: "runtime/cgo"}
+ for _, path := range []string{"unsafe", "syscall", "runtime/cgo"} {
+ if pkgpath != path && importMap[path] == nil {
+ importMap[path] = &Package{ID: path}
+ }
}
continue
}
diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go
index 93e0e8a..d826b93 100644
--- a/go/packages/packages_test.go
+++ b/go/packages/packages_test.go
@@ -16,6 +16,7 @@
"os"
"path/filepath"
"reflect"
+ "runtime"
"sort"
"strings"
"sync"
@@ -279,6 +280,98 @@
}
}
+func TestLoadImportsTestVariants(t *testing.T) {
+ if usesOldGolist {
+ t.Skip("not yet supported in pre-Go 1.10.4 golist fallback implementation")
+ }
+
+ tmp, cleanup := makeTree(t, map[string]string{
+ "src/a/a.go": `package a; import _ "b"`,
+ "src/b/b.go": `package b`,
+ "src/b/b_test.go": `package b`,
+ "src/b/bx_test.go": `package b_test; import _ "a"`,
+ })
+ defer cleanup()
+
+ cfg := &packages.Config{
+ Mode: packages.LoadImports,
+ Env: append(os.Environ(), "GOPATH="+tmp),
+ Tests: true,
+ }
+ initial, err := packages.Load(cfg, "a", "b")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check graph topology.
+ graph, _ := importGraph(initial)
+ wantGraph := `
+* a
+ a [b.test]
+* b
+* b [b.test]
+* b.test
+* b_test [b.test]
+ a -> b
+ a [b.test] -> b [b.test]
+ b.test -> b [b.test]
+ b.test -> b_test [b.test]
+ b.test -> os (pruned)
+ b.test -> testing (pruned)
+ b.test -> testing/internal/testdeps (pruned)
+ b_test [b.test] -> a [b.test]
+`[1:]
+
+ if graph != wantGraph {
+ t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
+ }
+}
+
+func TestLoadImportsC(t *testing.T) {
+ // This test checks that when a package depends on the
+ // test variant of "syscall", "unsafe", or "runtime/cgo", that dependency
+ // is not removed when those packages are added when it imports "C".
+ //
+ // For this test to work, the external test of syscall must have a dependency
+ // on net, and net must import "syscall" and "C".
+ if runtime.GOOS == "windows" {
+ t.Skipf("skipping on windows; packages on windows do not satisfy conditions for test.")
+ }
+
+ if usesOldGolist {
+ t.Skip("not yet supported in pre-Go 1.10.4 golist fallback implementation")
+ }
+
+ cfg := &packages.Config{
+ Mode: packages.LoadImports,
+ Tests: true,
+ }
+ initial, err := packages.Load(cfg, "syscall", "net")
+ if err != nil {
+ t.Fatalf("failed to load imports: %v", err)
+ }
+
+ _, all := importGraph(initial)
+
+ for _, test := range []struct {
+ pattern string
+ wantImport string // an import to check for
+ }{
+ {"net", "syscall:syscall"},
+ {"net [syscall.test]", "syscall:syscall [syscall.test]"},
+ {"syscall_test [syscall.test]", "net:net [syscall.test]"},
+ } {
+ // Test the import paths.
+ pkg := all[test.pattern]
+ if pkg == nil {
+ t.Errorf("package %q not loaded", test.pattern)
+ }
+ if imports := strings.Join(imports(pkg), " "); !strings.Contains(imports, test.wantImport) {
+ t.Errorf("package %q: got \n%s, \nwant to have %s", test.pattern, imports, test.wantImport)
+ }
+ }
+}
+
func TestVendorImports(t *testing.T) {
tmp, cleanup := makeTree(t, map[string]string{
"src/a/a.go": `package a; import _ "b"; import _ "c";`,