cmd/go: add 'work' package pattern

The 'work' package pattern will resolve to the set of packages in the
work (formerly called main) modules. It's essentially 'all', but without
the dependencies. And the implementation is similar to that of 'all',
except that we don't expand to the dependencies.

Fixes #71294

Change-Id: I3d02beb74fa4e5c6de2290e24eedc51745d13080
Reviewed-on: https://go-review.googlesource.com/c/go/+/643235
Reviewed-by: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Michael Matloob 2025-01-16 17:05:02 -05:00
parent 9bd2160790
commit 24d22352d3
5 changed files with 136 additions and 2 deletions

View File

@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"
"cmd/go/internal/modload"
"cmd/go/internal/search"
"cmd/internal/pkgpattern"
)
@ -45,11 +46,23 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
return matchPath(rel)
}
case pattern == "all":
// This is slightly inaccurate: it matches every package, which isn't the same
// as matching the "all" package pattern.
// TODO(matloob): Should we make this more accurate? Does anyone depend on this behavior?
return func(p *Package) bool { return true }
case pattern == "std":
return func(p *Package) bool { return p.Standard }
case pattern == "cmd":
return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") }
case pattern == "tool" && modload.Enabled():
return func(p *Package) bool {
return modload.MainModules.Tools()[p.ImportPath]
}
case pattern == "work" && modload.Enabled():
return func(p *Package) bool {
return p.Module != nil && modload.MainModules.Contains(p.Module.Path)
}
default:
matchPath := pkgpattern.MatchPattern(pattern)
return func(p *Package) bool { return matchPath(p.ImportPath) }

View File

@ -323,6 +323,13 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
}
matchPackages(ctx, m, opts.Tags, includeStd, mg.BuildList())
case m.Pattern() == "work":
matchModules := MainModules.Versions()
if opts.MainModule != (module.Version{}) {
matchModules = []module.Version{opts.MainModule}
}
matchPackages(ctx, m, opts.Tags, omitStd, matchModules)
case m.Pattern() == "all":
if ld == nil {
// The initial roots are the packages and tools in the main module.

View File

@ -60,14 +60,14 @@ func (m *Match) IsLocal() bool {
}
// IsMeta reports whether the pattern is a “meta-package” keyword that represents
// multiple packages, such as "std", "cmd", "tool", or "all".
// multiple packages, such as "std", "cmd", "tool", "work", 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 == "tool" || name == "all"
return name == "std" || name == "cmd" || name == "tool" || name == "work" || name == "all"
}
// A MatchError indicates an error that occurred while attempting to match a

View File

@ -0,0 +1,35 @@
# Test the work and tool patterns in a per-package flag
go build -n '-gcflags=work=-fakeflag' example.com/foo/a
stderr 'compile.*-p example.com/foo/a.*-fakeflag'
! stderr 'compile.*-p example.com/dep.*-fakeflag'
go build -n '-gcflags=tool=-fakeflag' example.com/foo/a example.com/dep/tooldep
! stderr 'compile.*-p example.com/foo/a.*-fakeflag'
! stderr 'compile.*-p example.com/dep.*-fakeflag'
stderr 'compile.*-p main.*-fakeflag.*main.go'
-- go.mod --
module example.com/foo
go 1.24
tool example.com/dep/tooldep
require example.com/dep v1.0.0
replace example.com/dep => ./dep
-- a/a.go --
package a
import _ "example.com/dep"
-- dep/go.mod --
module example.com/dep
go 1.24
-- dep/dep.go --
package dep
-- dep/tooldep/main.go --
package main
import _ "example.com/dep"

View File

@ -0,0 +1,79 @@
cd m
go list all
stdout 'example.com/dep'
stdout 'example.com/m/a'
stdout 'example.com/m/b'
go list work
! stdout 'example.com/dep'
stdout 'example.com/m/a'
stdout 'example.com/m/b'
cd ../n
go list all
stdout 'example.com/n/c'
stdout 'example.com/n/d'
stdout 'unsafe'
go list work
stdout 'example.com/n/c'
stdout 'example.com/n/d'
! stdout 'unsafe'
cd ../w
go list all
stdout 'example.com/dep'
stdout 'example.com/m/a'
stdout 'example.com/m/b'
stdout 'example.com/n/c'
stdout 'example.com/n/d'
stdout 'unsafe'
go list work
! stdout 'example.com/dep'
stdout 'example.com/m/a'
stdout 'example.com/m/b'
stdout 'example.com/n/c'
stdout 'example.com/n/d'
! stdout 'unsafe'
-- m/go.mod --
module example.com/m
go 1.24
require example.com/dep v1.0.0
replace example.com/dep v1.0.0 => ../dep
-- m/a/a.go --
package a
-- m/b/b.go --
package b
import _ "example.com/dep"
-- n/go.mod --
module example.com/n
go 1.24
-- n/c/c.go --
package c
-- n/d/d.go --
package d
import _ "unsafe"
-- w/go.work --
go 1.24
use (
../m
../n
)
-- dep/go.mod --
module example.com/dep
go 1.24
-- dep/dep.go --
package dep
-- want_w_all.txt --
example.com/dep
example.com/work/a
example.com/work/b
-- want_w_all.txt --
example.com/work/a
example.com/work/b