cp go.mod go.mod.orig # 'go get' on a package already provided by the build list should update # the module already in the build list, not fail with an ambiguous import error. go get -d example.net/split/nested@patch go list -m all stdout '^example.net/split v0.2.1 ' ! stdout '^example.net/split/nested' # We should get the same behavior if we use a pattern that matches only that package. cp go.mod.orig go.mod go get -d example.net/split/nested/...@patch go list -m all stdout '^example.net/split v0.2.1 ' ! stdout '^example.net/split/nested' # If we request a version for which the package only exists in one particular module, # we should add that one particular module but not resolve import ambiguities. # # In particular, if the module that previously provided the package has a # matching version, but does not itself match the pattern and contains no # matching packages, we should not change its version. (We should *not* downgrade # module example.net/split to v0.1.0, despite the fact that # example.net/split v0.2.0 currently provides the package with the requested path.) # # TODO(#27899): Maybe we should resolve the ambiguities by upgrading. cp go.mod.orig go.mod ! go get -d example.net/split/nested@v0.1.0 stderr '^example.net/split/nested: ambiguous import: found package example.net/split/nested in multiple modules:\n\texample.net/split v0.2.0 \(.*split.2[/\\]nested\)\n\texample.net/split/nested v0.1.0 \(.*nested.1\)$' # A wildcard that matches packages in some module at its selected version # but not at the requested version should fail. # # We can't set the module to the selected version, because that version doesn't # even match the query: if we ran the same query twice, we wouldn't consider the # module to match the wildcard during the second call, so why should we consider # it to match during the first one? ('go get' should be idempotent, and if we # did that then it would not be.) # # But we also can't leave it where it is: the user requested that we set everything # matching the pattern to the given version, and right now we have packages # that match the pattern but *not* the version. # # That only leaves two options: we can set the module to an arbitrary version # (perhaps 'latest' or 'none'), or we can report an error and the let the user # disambiguate. We would rather not choose arbitrarily, so we do the latter. # # TODO(#27899): Should we instead upgrade or downgrade to an arbirary version? ! go get -d example.net/split/nested/...@v0.1.0 stderr '^go get: example.net/split/nested/\.\.\.@v0.1.0 matches packages in example.net/split@v0.2.0 but not example.net/split@v0.1.0: specify a different version for module example.net/split$' cmp go.mod go.mod.orig # If another argument resolves the ambiguity, we should be ok again. go get -d example.net/split@none example.net/split/nested@v0.1.0 go list -m all ! stdout '^example.net/split ' stdout '^example.net/split/nested v0.1.0 ' cp go.mod.orig go.mod go get -d example.net/split@v0.3.0 example.net/split/nested@v0.1.0 go list -m all stdout '^example.net/split v0.3.0 ' stdout '^example.net/split/nested v0.1.0 ' # If a pattern applies to modules and to packages, we should set all matching # modules to the version indicated by the pattern, and also resolve packages # to match the pattern if possible. cp go.mod.orig go.mod go get -d example.net/split/nested@v0.0.0 go get -d example.net/...@v0.1.0 go list -m all stdout '^example.net/split v0.1.0 ' stdout '^example.net/split/nested v0.1.0 ' go get -d example.net/... go list -m all stdout '^example.net/split v0.3.0 ' stdout '^example.net/split/nested v0.2.0 ' # @none applies to all matching module paths, # regardless of whether they contain any packages. go get -d example.net/...@none go list -m all ! stdout '^example.net' # Starting from no dependencies, a wildcard can resolve to an empty module with # the same prefix even if it contains no packages. go get -d example.net/...@none go get -d example.net/split/...@v0.1.0 go list -m all stdout '^example.net/split v0.1.0 ' -- go.mod -- module m go 1.16 require example.net/split v0.2.0 replace ( example.net/split v0.1.0 => ./split.1 example.net/split v0.2.0 => ./split.2 example.net/split v0.2.1 => ./split.2 example.net/split v0.3.0 => ./split.3 example.net/split/nested v0.0.0 => ./nested.0 example.net/split/nested v0.1.0 => ./nested.1 example.net/split/nested v0.2.0 => ./nested.2 ) -- split.1/go.mod -- module example.net/split go 1.16 -- split.2/go.mod -- module example.net/split go 1.16 -- split.2/nested/nested.go -- package nested -- split.3/go.mod -- module example.net/split go 1.16 -- nested.0/go.mod -- module example.net/split/nested go 1.16 -- nested.1/go.mod -- module example.net/split/nested go 1.16 -- nested.1/nested.go -- package nested -- nested.2/go.mod -- module example.net/split/nested go 1.16 -- nested.2/nested.go -- package nested