From 85a8e1786a669efe525fd4555edb77a60bac2ffe Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Tue, 23 Nov 2021 17:36:21 -0500 Subject: [PATCH] cmd/go: fix hang in workspaces golang.org/cl/365234 incorrectly had pruningForGoVersion always return workspace pruning instead of just returning workspace pruning at the top level, which broke the proper determination of pruning for dependency packages. Fix that code, and also fix a hang that resulted because the module loading code keeps loading dependencies until it reaches a pruned module or an unpruned module it already saw, so it could get stuck in a cycle. Change-Id: I8911f7d83aaee5870c43ef0355abbd439f15d4f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/366775 Trust: Michael Matloob Run-TryBot: Michael Matloob Reviewed-by: Bryan Mills TryBot-Result: Gopher Robot --- src/cmd/go/internal/modload/init.go | 6 +- src/cmd/go/internal/modload/modfile.go | 3 - .../testdata/script/work_regression_hang.txt | 71 +++++++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 src/cmd/go/testdata/script/work_regression_hang.txt diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 854c17d776..df083e7fcc 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -694,7 +694,11 @@ func LoadModFile(ctx context.Context) *Requirements { MainModules = makeMainModules([]module.Version{mainModule}, []string{""}, []*modfile.File{nil}, []*modFileIndex{nil}, "", nil) goVersion := LatestGoVersion() rawGoVersion.Store(mainModule, goVersion) - requirements = newRequirements(pruningForGoVersion(goVersion), nil, nil) + pruning := pruningForGoVersion(goVersion) + if inWorkspaceMode() { + pruning = workspace + } + requirements = newRequirements(pruning, nil, nil) return requirements } diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 7cc2272ea0..40e6ed787d 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -124,9 +124,6 @@ const ( ) func pruningForGoVersion(goVersion string) modPruning { - if inWorkspaceMode() { - return workspace - } if semver.Compare("v"+goVersion, ExplicitIndirectVersionV) < 0 { // The go.mod file does not duplicate relevant information about transitive // dependencies, so they cannot be pruned out. diff --git a/src/cmd/go/testdata/script/work_regression_hang.txt b/src/cmd/go/testdata/script/work_regression_hang.txt new file mode 100644 index 0000000000..a7661b68ad --- /dev/null +++ b/src/cmd/go/testdata/script/work_regression_hang.txt @@ -0,0 +1,71 @@ +# This test makes checks against a regression of a bug in the Go command +# where the module loader hung forever because all main module dependencies +# kept workspace pruning instead of adopting the pruning in their go.mod +# files, and the loader kept adding dependencies on the queue until they +# were either pruned or unpruned, never breaking a module dependency cycle. +# +# This is the module graph in the test: +# +# /-------------------------\ +# | | +# V | +# example.com/a -> example.com/b v1.0.0 -> example.com/c v1.1.0 + +go list -m -f '{{.Version}}' example.com/c + +-- go.work -- +go 1.16 + +use ( + ./a +) +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 + +replace example.com/b v1.0.0 => ../b +replace example.com/c v1.0.0 => ../c +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/c v1.0.0 +-- b/b.go -- +package b + +func B() { +} +-- b/cmd/main.go -- +package main + +import "example.com/c" + +func main() { + c.C() +} +-- c/go.mod -- +module example.com/c + +go 1.18 + +require example.com/b v1.0.0 +-- c/c.go -- +package c + +import "example.com/b" + +func C() { + b.B() +} \ No newline at end of file -- 2.50.0