From e9c96835971044aa4ace37c7787de231bbde05d9 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 4 Feb 2021 15:26:52 -0500 Subject: [PATCH] cmd/go: suppress errors from 'go get -d' for packages that only conditionally exist Fixes #44106 Fixes #29268 Change-Id: Id113f2ced274d43fbf66cb804581448218996f81 Reviewed-on: https://go-review.googlesource.com/c/go/+/289769 TryBot-Result: Go Bot Reviewed-by: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills --- src/cmd/go/internal/modget/get.go | 20 ++- .../go/testdata/script/mod_get_pkgtags.txt | 116 ++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_get_pkgtags.txt diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 574f3e194d1..1a8c9d37255 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -380,10 +380,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { pkgs := load.PackagesAndErrors(ctx, pkgPatterns) load.CheckPackageErrors(pkgs) work.InstallPackages(ctx, pkgPatterns, pkgs) - // TODO(#40276): After Go 1.16, print a deprecation notice when building - // and installing main packages. 'go install pkg' or - // 'go install pkg@version' should be used instead. - // Give the specific argument to use if possible. + // TODO(#40276): After Go 1.16, print a deprecation notice when building and + // installing main packages. 'go install pkg' or 'go install pkg@version' + // should be used instead. Give the specific argument to use if possible. } if !modload.HasModRoot() { @@ -1453,7 +1452,18 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns } } for _, pkg := range pkgs { - if _, _, err := modload.Lookup("", false, pkg); err != nil { + if dir, _, err := modload.Lookup("", false, pkg); err != nil { + if dir != "" && errors.Is(err, imports.ErrNoGo) { + // Since dir is non-empty, we must have located source files + // associated with either the package or its test — ErrNoGo must + // indicate that none of those source files happen to apply in this + // configuration. If we are actually building the package (no -d + // flag), the compiler will report the problem; otherwise, assume that + // the user is going to build or test it in some other configuration + // and suppress the error. + continue + } + base.SetExitStatus(1) if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { for _, m := range ambiguousErr.Modules { diff --git a/src/cmd/go/testdata/script/mod_get_pkgtags.txt b/src/cmd/go/testdata/script/mod_get_pkgtags.txt new file mode 100644 index 00000000000..c0a57f3fab2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pkgtags.txt @@ -0,0 +1,116 @@ +# https://golang.org/issue/44106 +# 'go get' should fetch the transitive dependencies of packages regardless of +# tags, but shouldn't error out if the package is missing tag-guarded +# dependencies. + +# Control case: just adding the top-level module to the go.mod file does not +# fetch its dependencies. + +go mod edit -require example.net/tools@v0.1.0 +! go list -deps example.net/cmd/tool +stderr '^module example\.net/cmd provides package example\.net/cmd/tool and is replaced but not required; to add it:\n\tgo get example\.net/cmd@v0\.1\.0$' +go mod edit -droprequire example.net/tools + + +# 'go get -d' makes a best effort to fetch those dependencies, but shouldn't +# error out if dependencies of tag-guarded files are missing. + +go get -d example.net/tools@v0.1.0 + +! go list example.net/tools +stderr '^package example.net/tools: build constraints exclude all Go files in .*[/\\]tools$' + +go list -tags=tools -e -deps example.net/tools +stdout '^example.net/cmd/tool$' +stdout '^example.net/missing$' + +go list -deps example.net/cmd/tool + +! go list example.net/missing +stderr '^no required module provides package example.net/missing; to add it:\n\tgo get example.net/missing$' + + +# https://golang.org/issue/29268 +# 'go get' should fetch modules whose roots contain test-only packages, but +# without the -t flag shouldn't error out if the test has missing dependencies. + +go get -d example.net/testonly@v0.1.0 + +# With the -t flag, the test dependencies must resolve successfully. +! go get -d -t example.net/testonly@v0.1.0 +stderr '^example.net/testonly tested by\n\texample.net/testonly\.test imports\n\texample.net/missing: cannot find module providing package example.net/missing$' + + +# 'go get -d' should succeed for a module path that does not contain a package, +# but fail for a non-package subdirectory of a module. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + +go get -d example.net/missing@v0.1.0 + + +# Getting the subdirectory should continue to fail even if the corresponding +# module is already present in the build list. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + + +-- go.mod -- +module example.net/m + +go 1.15 + +replace ( + example.net/tools v0.1.0 => ./tools + example.net/cmd v0.1.0 => ./cmd + example.net/testonly v0.1.0 => ./testonly + example.net/missing v0.1.0 => ./missing +) + +-- tools/go.mod -- +module example.net/tools + +go 1.15 + +// Requirements intentionally omitted. + +-- tools/tools.go -- +// +build tools + +package tools + +import ( + _ "example.net/cmd/tool" + _ "example.net/missing" +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/tool/tool.go -- +package main + +func main() {} + +-- testonly/go.mod -- +module example.net/testonly + +go 1.15 +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.net/missing" + +func Test(t *testing.T) {} + +-- missing/go.mod -- +module example.net/missing + +go 1.15 +-- missing/README.txt -- +There are no Go source files here. +-- missing/subdir/README.txt -- +There are no Go source files here either.