-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
While testing some other behaviors for #36460, I noticed a curious interaction between go get
and -mod=readonly
.
If a package or test in the main module directly imports a package found in an implicit (transitive) dependency, go build
and go test
invocations for that package with -mod=readonly
will fail with updates to go.mod needed
, because the go
command has always maintained the invariant that modules directly imported by the main module are explicit requirements.
In this situation, the go
command recommends running go mod tidy
, which is usually the first tool users ought to consider for dependency problems. However, a user who does not want to lose other temporary edits to the go.mod
file might prefer to instead use go get
to promote only one specific package instead.
Unfortunately, if the module containing the package passed to go get
is already transitively required at the requested version, go get
does not promote that module from an implicit dependency to an explicit one. (It will under lazy loading, but does not yet.)
The user can work around this problem by running go mod edit -require
to add the requirement explicitly, but we would rather not encourage users to reach for go mod edit
to make dependency changes, as it does not ensure that the resulting requirements are consistent.
Now that -mod=readonly
is the default (#40728), I think users will be much more likely to encounter this awkward interaction. They may be frustrated by it, and might not consider the go mod edit
workaround.
For Go 1.16, perhaps we should make go get -d
always record explicit dependencies for the requested packages, which can be subsequently cleaned up with an explicit go mod tidy
.
$ go version
go version devel +6c64b6db6 Thu Dec 10 03:18:00 2020 +0000 linux/amd64
$ go list all
usemod/usemod.go:3:8: no required module provides package golang.org/x/mod/module; try 'go mod tidy' to add it
usetools/usetools.go:3:8: no required module provides package golang.org/x/tools/go/packages; try 'go mod tidy' to add it
$ go get -d golang.org/x/tools/go/packages
go: downloading golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
go: downloading golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
go: downloading golang.org/x/mod v0.3.0
go get: added golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
$ go list -deps ./usetools >/dev/null
$ go list -deps ./usemod >/dev/null
go: updates to go.mod needed; try 'go mod tidy' first
$ cat go.mod
module example.com
go 1.16
require golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11 // indirect
$ go list -m all
example.com
github.com/yuin/goldmark v1.2.1
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/mod v0.3.0
golang.org/x/net v0.0.0-20201021035429-f5854403a974
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f
golang.org/x/text v0.3.3
golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
$ go get -d golang.org/x/mod@v0.3.0
$ cat go.mod
module example.com
go 1.16
require golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11 // indirect
$ go list -deps ./usemod >/dev/null
go: updates to go.mod needed; try 'go mod tidy' first
$ go mod edit -require=golang.org/x/mod@v0.3.0
$ cat go.mod
module example.com
go 1.16
require (
golang.org/x/mod v0.3.0
golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11 // indirect
)
$ go list -deps ./usemod >/dev/null
$
-- go.mod --
module example.com
go 1.16
-- usemod/usemod.go --
package usemod
import _ "golang.org/x/mod/module"
-- usetools/usetools.go --
package usetools
import _ "golang.org/x/tools/go/packages"