modFiles map[module.Version]*modfile.File
+ tools map[string]bool
+
modContainingCWD module.Version
workFile *modfile.WorkFile
return mms.versions
}
+// Tools returns the tools defined by all the main modules.
+// The key is the absolute package path of the tool.
+func (mms *MainModuleSet) Tools() map[string]bool {
+ if mms == nil {
+ return nil
+ }
+ return mms.tools
+}
+
func (mms *MainModuleSet) Contains(path string) bool {
if mms == nil {
return false
modFiles: map[module.Version]*modfile.File{},
indices: map[module.Version]*modFileIndex{},
highestReplaced: map[string]string{},
+ tools: map[string]bool{},
workFile: workFile,
}
var workFileReplaces []*modfile.Replace
mainModules.highestReplaced[r.Old.Path] = r.Old.Version
}
}
+
+ for _, t := range modFiles[i].Tool {
+ if err := module.CheckImportPath(t.Path); err != nil {
+ if e, ok := err.(*module.InvalidPathError); ok {
+ e.Kind = "tool"
+ }
+ base.Fatal(err)
+ }
+
+ mainModules.tools[t.Path] = true
+ }
}
}
// A package matches the "all" pattern if:
// - it is in the main module, or
// - it is imported by any test in the main module, or
+// - it is imported by a tool of the main module, or
// - it is imported by another package in "all", or
// - the main module specifies a go version ≤ 1.15, and the package is imported
// by a *test of* another package in "all".
case m.Pattern() == "all":
if ld == nil {
- // The initial roots are the packages in the main module.
+ // The initial roots are the packages and tools in the main module.
// loadFromRoots will expand that to "all".
m.Errs = m.Errs[:0]
matchModules := MainModules.Versions()
matchModules = []module.Version{opts.MainModule}
}
matchPackages(ctx, m, opts.Tags, omitStd, matchModules)
+ for tool := range MainModules.Tools() {
+ m.Pkgs = append(m.Pkgs, tool)
+ }
} else {
// Starting with the packages in the main module,
// enumerate the full list of "all".
m.MatchPackages() // Locate the packages within GOROOT/src.
}
+ case m.Pattern() == "tool":
+ for tool, _ := range MainModules.Tools() {
+ m.Pkgs = append(m.Pkgs, tool)
+ }
default:
panic(fmt.Sprintf("internal error: modload missing case for pattern %s", m.Pattern()))
}
// essentially nothing (these atomic flag ops are essentially free compared
// to scanning source code for imports).
ld.applyPkgFlags(ctx, pkg, pkgInAll)
+ } else if MainModules.Tools()[pkg.path] {
+ // Tools declared by main modules are always in "all".
+ ld.applyPkgFlags(ctx, pkg, pkgInAll)
}
if ld.AllowPackage != nil {
if err := ld.AllowPackage(ctx, pkg.path, pkg.mod); err != nil {
}
// IsMeta reports whether the pattern is a “meta-package” keyword that represents
-// multiple packages, such as "std", "cmd", or "all".
+// multiple packages, such as "std", "cmd", "tool", or "all".
func (m *Match) IsMeta() bool {
return IsMetaPackage(m.pattern)
}
// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
func IsMetaPackage(name string) bool {
- return name == "std" || name == "cmd" || name == "all"
+ return name == "std" || name == "cmd" || name == "tool" || name == "all"
}
// A MatchError indicates an error that occurred while attempting to match a
--- /dev/null
+go list tool
+stdout example.com/foo/cmd
+stdout example.com/dependency/cmd/bar
+go list all
+stdout example.com/foo/cmd
+stdout example.com/foo/lib
+stdout example.com/dependency/cmd/bar
+
+cd workspace
+go list tool
+stdout example.com/foo/cmd
+stdout example.com/dependency/cmd/bar
+stdout example.com/dependency/cmd/baz
+go list all
+stdout example.com/foo/cmd
+stdout example.com/foo/lib
+stdout example.com/other
+stdout example.com/dependency/cmd/bar
+stdout example.com/dependency/cmd/baz
+
+cd ../invalid_path
+! go list all
+stderr 'malformed tool path'
+
+-- go.mod --
+module example.com/foo
+
+go 1.24
+
+tool example.com/foo/cmd/eg
+tool example.com/dependency/cmd/bar
+
+replace example.com/dependency => ./dependency
+
+require example.com/dependency v1.0.0
+
+-- lib/main.go --
+package lib
+
+-- cmd/eg/main.go --
+package main
+
+func main(){}
+
+-- dependency/go.mod --
+module example.com/dependency
+
+go 1.24
+-- dependency/cmd/bar/main.go --
+package main
+
+func main(){}
+-- dependency/cmd/baz/main.go --
+package main
+
+func main() {}
+-- other/go.mod --
+module example.com/other
+
+go 1.24
+
+tool example.com/dependency/cmd/baz
+
+replace example.com/dependency => ../dependency
+
+require example.com/dependency v1.0.0
+-- other/lib.go --
+package other
+-- workspace/go.work --
+go 1.24
+
+use (
+ ../
+ ../other
+)
+
+-- invalid_path/go.mod --
+module example.com/invalid_path
+
+go 1.24
+
+tool ./invalid_path