]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: in 'go get', promote named implicit dependencies to explicit
authorJay Conrod <jayconrod@google.com>
Wed, 16 Dec 2020 21:37:56 +0000 (16:37 -0500)
committerJay Conrod <jayconrod@google.com>
Wed, 23 Dec 2020 14:16:32 +0000 (14:16 +0000)
'go get pkg@vers' will now add an explicit requirement for the module
providing pkg if that version was already indirectly required.

'go get mod@vers' will do the same if mod is a module path but not a
package.

Requirements promoted this way will be marked "// indirect" because
'go get' doesn't know whether they're needed to build packages in the
main module. So users should prefer to run 'go get ./pkg' (where ./pkg
is a package in the main module) to promote requirements.

Fixes #43131

Change-Id: Ifbb65b71274b3cc752a7a593d6ddd875f7de23b8
Reviewed-on: https://go-review.googlesource.com/c/go/+/278812
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Jay Conrod <jayconrod@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
src/cmd/go/internal/modload/buildlist.go
src/cmd/go/internal/modload/init.go
src/cmd/go/internal/modload/query.go
src/cmd/go/internal/str/str.go
src/cmd/go/testdata/script/mod_get_promote_implicit.txt

index 896adebbb19de9b71aefc310e0e7dc8f0053c1df..45f220a6ee6946b510a6bb67cb06b21971d31576 100644 (file)
@@ -28,6 +28,11 @@ import (
 //
 var buildList []module.Version
 
+// additionalExplicitRequirements is a list of modules paths for which
+// WriteGoMod should record explicit requirements, even if they would be
+// selected without those requirements. Each path must also appear in buildList.
+var additionalExplicitRequirements []string
+
 // capVersionSlice returns s with its cap reduced to its length.
 func capVersionSlice(s []module.Version) []module.Version {
        return s[:len(s):len(s)]
@@ -121,6 +126,12 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error
 
        if !inconsistent {
                buildList = final
+               additionalExplicitRequirements = make([]string, 0, len(mustSelect))
+               for _, m := range mustSelect {
+                       if m.Version != "none" {
+                               additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path)
+                       }
+               }
                return nil
        }
 
index 3f70d041451f1e1c8168ac6b53b7234b35461619..445ebb262fb6cd2557e71f4f5bf6398efbdba9e8 100644 (file)
@@ -15,6 +15,7 @@ import (
        "os"
        "path"
        "path/filepath"
+       "sort"
        "strconv"
        "strings"
        "sync"
@@ -27,6 +28,7 @@ import (
        "cmd/go/internal/modfetch"
        "cmd/go/internal/mvs"
        "cmd/go/internal/search"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/modfile"
        "golang.org/x/mod/module"
@@ -845,13 +847,15 @@ func AllowWriteGoMod() {
 // MinReqs returns a Reqs with minimal additional dependencies of Target,
 // as will be written to go.mod.
 func MinReqs() mvs.Reqs {
-       var retain []string
+       retain := append([]string{}, additionalExplicitRequirements...)
        for _, m := range buildList[1:] {
                _, explicit := index.require[m]
                if explicit || loaded.direct[m.Path] {
                        retain = append(retain, m.Path)
                }
        }
+       sort.Strings(retain)
+       str.Uniq(&retain)
        min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
        if err != nil {
                base.Fatalf("go: %v", err)
index e35e0fc16e29b7f19790125b04b2e103d8272ec2..8affd179bb2e9c0b1d51fec1b3b2bd80e2254017 100644 (file)
@@ -21,6 +21,7 @@ import (
        "cmd/go/internal/imports"
        "cmd/go/internal/modfetch"
        "cmd/go/internal/search"
+       "cmd/go/internal/str"
        "cmd/go/internal/trace"
 
        "golang.org/x/mod/module"
@@ -1005,13 +1006,8 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
        sort.Slice(versions, func(i, j int) bool {
                return semver.Compare(versions[i], versions[j]) < 0
        })
-       uniq := versions[:1]
-       for _, v := range versions {
-               if v != uniq[len(uniq)-1] {
-                       uniq = append(uniq, v)
-               }
-       }
-       return uniq, nil
+       str.Uniq(&versions)
+       return versions, nil
 }
 
 func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
index 0413ed8e69e19992effa8e68a7ff57e2222cc2fd..9106ebf74d5e31cb04e7deddf26e1a72ff6e9c74 100644 (file)
@@ -96,6 +96,20 @@ func Contains(x []string, s string) bool {
        return false
 }
 
+// Uniq removes consecutive duplicate strings from ss.
+func Uniq(ss *[]string) {
+       if len(*ss) <= 1 {
+               return
+       }
+       uniq := (*ss)[:1]
+       for _, s := range *ss {
+               if s != uniq[len(uniq)-1] {
+                       uniq = append(uniq, s)
+               }
+       }
+       *ss = uniq
+}
+
 func isSpaceByte(c byte) bool {
        return c == ' ' || c == '\t' || c == '\n' || c == '\r'
 }
index 33f6a299e291dcd6a35df23a7e1ecbbce8ff0c8f..c64e0c0f7068a777253d99d9d7cb05583e208c54 100644 (file)
@@ -14,6 +14,12 @@ go get -d m/use-indirect
 cmp go.mod go.mod.use
 cp go.mod.orig go.mod
 
+# We can also promote implicit requirements using 'go get' on them, or their
+# packages. This gives us "// indirect" requirements, since 'go get' doesn't
+# know they're needed by the main module. See #43131 for the rationale.
+go get -d indirect-with-pkg indirect-without-pkg
+cmp go.mod go.mod.indirect
+
 -- go.mod.orig --
 module m