From cf6739caad1869ec3a022802d53a4de098cb0533 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 3 Feb 2020 13:40:14 -0500 Subject: [PATCH] cmd/go: add a regression test for package import cycles guarded by build tags I've been thinking about the relationship between the package import graph and the module import graph, and realized that the package import graph is not always acyclic. (The package import graph must be acyclic given a specific set of build tags, but the 'mod' subcommands intentionally ignore build tags.) I'm not sure whether we have any existing regression tests that cover this sort of cycle, so I'm adding one now. Thankfully, it passes! Updates #36460 Change-Id: I7679320994ee169855241efa51cd45f71315f7f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/217557 Run-TryBot: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Gobot Gobot --- .../script/mod_tagged_import_cycle.txt | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_tagged_import_cycle.txt diff --git a/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt new file mode 100644 index 00000000000000..0491acb8723a55 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt @@ -0,0 +1,106 @@ +# Because 'go mod' subcommands ignore build constraints, they can encounter +# package-import cycles that are not possible in an ordinary build. This test +# verifies that such cycles are handled even when they cross module boundaries. + +# First, verify that the import graph depends on build tags as expected. +go list -deps example.com/left +stdout '^example.com/right$' +go list -deps example.com/right +! stdout left + +env GOFLAGS=-tags=mirror +go list -deps example.com/left +! stdout right +go list -deps example.com/right +stdout '^example.com/left$' +env GOFLAGS='' + +# 'go mod why' should be agnostic to build tags. +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' + +env GOFLAGS='-tags=mirror' +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' +env GOFLAGS='' + +# 'go mod tidy' should successfully handle the cycle. +env GOFLAGS=-mod=readonly +go mod tidy + +# 'go mod vendor' should copy in both packages without crashing. +go mod vendor +exists vendor/example.com/left/default.go +exists vendor/example.com/left/mirror.go +exists vendor/example.com/right/default.go +exists vendor/example.com/right/mirror.go + +-- go.mod -- +module example.com/chiral + +go 1.14 + +require ( + example.com/left v0.1.0 + example.com/right v0.1.0 +) + +replace ( + example.com/left => ./left + example.com/right => ./right +) +-- chiral.go -- +// Package chiral imports packages in an order that depends on build tags. +package chiral +-- default.go -- +// +build !mirror + +package chiral + +import _ "example.com/left" +-- mirror.go -- +// +build mirror + +package chiral + +import _ "example.com/right" +-- left/go.mod -- +module example.com/left + +go 1.14 + +require example.com/right v0.1.0 + +replace example.com/right v0.1.0 => ../right +-- left/default.go -- +// +build !mirror + +package left + +import _ "example.com/right" +-- left/mirror.go -- +// +build mirror + +package left +-- right/go.mod -- +module example.com/right + +go 1.14 + +require example.com/left v0.1.0 + +replace example.com/left v0.1.0 => ../left +-- right/default.go -- +// +build !mirror + +package right +-- right/mirror.go -- +// +build mirror + +package right + +import _ "example.com/left"