case pruned:
return updatePrunedRoots(ctx, direct, rs, pkgs, add, rootsImported)
case workspace:
- return updateWorkspaceRoots(ctx, rs, add)
+ return updateWorkspaceRoots(ctx, direct, rs, add)
default:
panic(fmt.Sprintf("unsupported pruning mode: %v", rs.pruning))
}
}
-func updateWorkspaceRoots(ctx context.Context, rs *Requirements, add []module.Version) (*Requirements, error) {
+func updateWorkspaceRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
if len(add) != 0 {
// add should be empty in workspace mode because workspace mode implies
// -mod=readonly, which in turn implies no new requirements. The code path
// return an error.
panic("add is not empty")
}
- return rs, nil
+ return newRequirements(workspace, rs.rootModules, direct), nil
}
// tidyPrunedRoots returns a minimal set of root requirements that maintains the
toolchain = workFile.Toolchain.Name
}
roots = appendGoAndToolchainRoots(roots, goVersion, toolchain, direct)
+ direct = directRequirements(modFiles)
} else {
pruning = pruningForGoVersion(MainModules.GoVersion())
if len(modFiles) != 1 {
withToolchainRoot = true
)
+func directRequirements(modFiles []*modfile.File) map[string]bool {
+ direct := make(map[string]bool)
+ for _, modFile := range modFiles {
+ for _, r := range modFile.Require {
+ if !r.Indirect {
+ direct[r.Mod.Path] = true
+ }
+ }
+ }
+ return direct
+}
+
func rootsFromModFile(m module.Version, modFile *modfile.File, addToolchainRoot addToolchainRoot) (roots []module.Version, direct map[string]bool) {
direct = make(map[string]bool)
padding := 2 // Add padding for the toolchain and go version, added upon return.
Module: dep.mod,
}
}
- continue
- }
-
- if pkg.err == nil && cfg.BuildMod != "mod" {
+ } else if pkg.err == nil && cfg.BuildMod != "mod" {
if v, ok := rs.rootSelected(dep.mod.Path); !ok || v != dep.mod.Version {
// dep.mod is not an explicit dependency, but needs to be.
// Because we are not in "mod" mode, we will not be able to update it.
--- /dev/null
+# Test that ModuleDirect.Public is correctly set on go list output.
+# This is a regression test for issue #66789.
+
+# In this test, the workspace contains modules example.com/a and
+# example.com/b. Module example.com/a has a direct requirement
+# on rsc.io/sampler, and an indirect requirement on golang.org/x/text
+# through rsc.io/isampler. Module example.com/b has a direct
+# requirement on example.com/c which is incorrectly marked as indirect
+# in module example.com/b's go.mod file.
+
+# Check that go list -m processes the indirect annotations in the
+# go.mod file.
+go list -f '{{.Path}} {{.Indirect}}' -m all
+stdout 'example.com/a false'
+stdout 'example.com/b false'
+stdout 'rsc.io/sampler false'
+stdout 'golang.org/x/text true'
+stdout 'example.com/c true' # Uses the information in go.mod without checking imports.
+
+# Check that 'go list all' correctly populates "indirect" module annotation.
+go list -f '{{.ImportPath}} {{with .Module}}{{.Indirect}}{{end}}' all
+stdout 'example.com/a false'
+stdout 'example.com/b false'
+stdout 'rsc.io/sampler false'
+stdout 'golang.org/x/text/language true'
+stdout 'example.com/c false'
+
+-- go.work --
+go 1.23
+
+use ./a
+use ./b
+-- a/go.mod --
+module example.com/a
+
+go 1.23
+
+require rsc.io/sampler v1.2.1
+
+require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
+-- a/a.go --
+package a
+
+import "rsc.io/sampler"
+
+func A() string {
+ return sampler.Hello()
+}
+-- b/go.mod --
+module example.com/b
+
+go 1.23
+
+// The indrect comment below is inaccurate. Its purpose
+// is to test that it is corrected when enough packages
+// are loaded to correct it.
+
+require example.com/c v1.0.0 // indirect
+
+replace example.com/c => ../c
+-- b/b.go --
+package b
+
+import "example.com/c"
+
+func B() {
+ c.C()
+}
+-- c/go.mod --
+module example.com/c
+
+go 1.23
+-- c/c.go --
+package c
+
+func C() {}
\ No newline at end of file