]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go/internal/modload: avoid a network fetch when querying a valid semantic version
authorBryan C. Mills <bcmills@google.com>
Tue, 15 Sep 2020 19:14:55 +0000 (15:14 -0400)
committerBryan C. Mills <bcmills@google.com>
Thu, 17 Sep 2020 21:05:27 +0000 (21:05 +0000)
Test this behavior incidentally in a test for ambiguous import errors.
(I rediscovered the error when writing the new test.)

For #32567
Updates #28806

Change-Id: I323f05145734e5cf99818b9f04d65075f7c0f787
Reviewed-on: https://go-review.googlesource.com/c/go/+/255046
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
src/cmd/go/internal/modload/query.go
src/cmd/go/testdata/script/mod_get_ambiguous_import.txt [new file with mode: 0644]

index f67a738677c1b9453be0758a721369d7ab80faa5..5ddb4e65653ec114dfdf9ffb298750bd86c65ac4 100644 (file)
@@ -212,7 +212,20 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
 
        default:
                // Direct lookup of semantic version or commit identifier.
-               //
+
+               // If the query is a valid semantic version and that version is replaced,
+               // use the replacement module without searching the proxy.
+               canonicalQuery := module.CanonicalVersion(query)
+               if canonicalQuery != "" {
+                       m := module.Version{Path: path, Version: query}
+                       if r := Replacement(m); r.Path != "" {
+                               if err := allowed(ctx, m); errors.Is(err, ErrDisallowed) {
+                                       return nil, err
+                               }
+                               return &modfetch.RevInfo{Version: query}, nil
+                       }
+               }
+
                // If the identifier is not a canonical semver tag — including if it's a
                // semver tag with a +metadata suffix — then modfetch.Stat will populate
                // info.Version with a suitable pseudo-version.
@@ -222,9 +235,9 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
                        // The full query doesn't correspond to a tag. If it is a semantic version
                        // with a +metadata suffix, see if there is a tag without that suffix:
                        // semantic versioning defines them to be equivalent.
-                       if vers := module.CanonicalVersion(query); vers != "" && vers != query {
-                               info, err = modfetch.Stat(proxy, path, vers)
-                               if !errors.Is(err, os.ErrNotExist) {
+                       if canonicalQuery != "" && query != canonicalQuery {
+                               info, err = modfetch.Stat(proxy, path, canonicalQuery)
+                               if err != nil && !errors.Is(err, os.ErrNotExist) {
                                        return info, err
                                }
                        }
diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt
new file mode 100644 (file)
index 0000000..8f5bf20
--- /dev/null
@@ -0,0 +1,60 @@
+go list -m all
+stdout '^example.net/m v0.1.0 '
+! stdout '^example.net/m/p '
+cp go.mod go.mod.orig
+
+# Upgrading example.net/m/p without also upgrading example.net/m
+# causes the import of package example.net/m/p to be ambiguous.
+#
+# TODO(#27899): Should we automatically upgrade example.net/m to v0.2.0
+# to resolve the conflict?
+! go get -d example.net/m/p@v1.0.0
+stderr '^go get example.net/m/p@v1.0.0: ambiguous import: found package example.net/m/p in multiple modules:\n\texample.net/m v0.1.0 \(.*[/\\]m1[/\\]p\)\n\texample.net/m/p v1.0.0 \(.*[/\\]p0\)\n\z'
+cmp go.mod go.mod.orig
+
+# Upgrading both modules simultaneously resolves the ambiguous upgrade.
+# Note that this command line mixes a module path (example.net/m)
+# and a package path (example.net/m/p) in the same command.
+go get -d example.net/m@v0.2.0 example.net/m/p@v1.0.0
+
+go list -m all
+stdout '^example.net/m v0.2.0 '
+stdout '^example.net/m/p v1.0.0 '
+
+-- go.mod --
+module example.net/importer
+
+go 1.16
+
+require (
+       example.net/m v0.1.0
+)
+
+replace (
+       example.net/m v0.1.0 => ./m1
+       example.net/m v0.2.0 => ./m2
+       example.net/m/p v1.0.0 => ./p0
+)
+-- importer.go --
+package importer
+import _ "example.net/m/p"
+-- m1/go.mod --
+module example.net/m
+
+go 1.16
+-- m1/p/p.go --
+package p
+-- m2/go.mod --
+module example.net/m
+
+go 1.16
+-- m2/README.txt --
+Package p has been moved to module …/m/p.
+Module …/m/p does not require any version of module …/m.
+
+-- p0/go.mod --
+module example.net/m/p
+
+go 1.16
+-- p0/p.go --
+package p