Skip to content

Commit f529d56

Browse files
committed
cmd/go: add global ignore mechanism
This CL adds the ignore directive which enables users to tell the Go Command to skip traversing into a given directory. This behaves similar to how '_' or 'testdata' are currently treated. This mainly has benefits for go list and go mod tidy. This does not affect what is packed into a module. Fixes: #42965 Change-Id: I232e27c1a065bb6eb2d210dbddad0208426a1fdd Reviewed-on: https://go-review.googlesource.com/c/go/+/643355 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Michael Matloob <matloob@google.com>
1 parent b450b54 commit f529d56

13 files changed

+796
-22
lines changed

src/cmd/go/alldocs.go

+10-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/go/internal/load/pkg.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -2927,8 +2927,7 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
29272927
}
29282928
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
29292929
} else {
2930-
noModRoots := []string{}
2931-
matches = search.ImportPaths(patterns, noModRoots)
2930+
matches = search.ImportPaths(patterns)
29322931
}
29332932

29342933
var (

src/cmd/go/internal/modcmd/edit.go

+38-2
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,13 @@ like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
9090
The -tool=path and -droptool=path flags add and drop a tool declaration
9191
for the given path.
9292
93+
The -ignore=path and -dropignore=path flags add and drop a ignore declaration
94+
for the given path.
95+
9396
The -godebug, -dropgodebug, -require, -droprequire, -exclude, -dropexclude,
94-
-replace, -dropreplace, -retract, -dropretract, -tool, and -droptool editing
95-
flags may be repeated, and the changes are applied in the order given.
97+
-replace, -dropreplace, -retract, -dropretract, -tool, -droptool, -ignore,
98+
and -dropignore editing flags may be repeated, and the changes are applied
99+
in the order given.
96100
97101
The -print flag prints the final go.mod in its text format instead of
98102
writing it back to go.mod.
@@ -147,6 +151,10 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
147151
Path string
148152
}
149153
154+
type Ignore struct {
155+
Path string
156+
}
157+
150158
Retract entries representing a single version (not an interval) will have
151159
the "Low" and "High" fields set to the same value.
152160
@@ -190,6 +198,8 @@ func init() {
190198
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
191199
cmdEdit.Flag.Var(flagFunc(flagTool), "tool", "")
192200
cmdEdit.Flag.Var(flagFunc(flagDropTool), "droptool", "")
201+
cmdEdit.Flag.Var(flagFunc(flagIgnore), "ignore", "")
202+
cmdEdit.Flag.Var(flagFunc(flagDropIgnore), "dropignore", "")
193203

194204
base.AddBuildFlagsNX(&cmdEdit.Flag)
195205
base.AddChdirFlag(&cmdEdit.Flag)
@@ -546,6 +556,24 @@ func flagDropTool(arg string) {
546556
})
547557
}
548558

559+
// flagIgnore implements the -ignore flag.
560+
func flagIgnore(arg string) {
561+
edits = append(edits, func(f *modfile.File) {
562+
if err := f.AddIgnore(arg); err != nil {
563+
base.Fatalf("go: -ignore=%s: %v", arg, err)
564+
}
565+
})
566+
}
567+
568+
// flagDropIgnore implements the -dropignore flag.
569+
func flagDropIgnore(arg string) {
570+
edits = append(edits, func(f *modfile.File) {
571+
if err := f.DropIgnore(arg); err != nil {
572+
base.Fatalf("go: -dropignore=%s: %v", arg, err)
573+
}
574+
})
575+
}
576+
549577
// fileJSON is the -json output data structure.
550578
type fileJSON struct {
551579
Module editModuleJSON
@@ -556,6 +584,7 @@ type fileJSON struct {
556584
Replace []replaceJSON
557585
Retract []retractJSON
558586
Tool []toolJSON
587+
Ignore []ignoreJSON
559588
}
560589

561590
type editModuleJSON struct {
@@ -584,6 +613,10 @@ type toolJSON struct {
584613
Path string
585614
}
586615

616+
type ignoreJSON struct {
617+
Path string
618+
}
619+
587620
// editPrintJSON prints the -json output.
588621
func editPrintJSON(modFile *modfile.File) {
589622
var f fileJSON
@@ -614,6 +647,9 @@ func editPrintJSON(modFile *modfile.File) {
614647
for _, t := range modFile.Tool {
615648
f.Tool = append(f.Tool, toolJSON{t.Path})
616649
}
650+
for _, i := range modFile.Ignore {
651+
f.Ignore = append(f.Ignore, ignoreJSON{i.Path})
652+
}
617653
data, err := json.MarshalIndent(&f, "", "\t")
618654
if err != nil {
619655
base.Fatalf("go: internal error: %v", err)

src/cmd/go/internal/modload/modfile.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ type modFileIndex struct {
9494
require map[module.Version]requireMeta
9595
replace map[module.Version]module.Version
9696
exclude map[module.Version]bool
97+
ignore []string
9798
}
9899

99100
type requireMeta struct {
@@ -455,7 +456,11 @@ func indexModFile(data []byte, modFile *modfile.File, mod module.Version, needsF
455456
for _, x := range modFile.Exclude {
456457
i.exclude[x.Mod] = true
457458
}
458-
459+
if modFile.Ignore != nil {
460+
for _, x := range modFile.Ignore {
461+
i.ignore = append(i.ignore, x.Path)
462+
}
463+
}
459464
return i
460465
}
461466

@@ -539,6 +544,7 @@ type modFileSummary struct {
539544
module module.Version
540545
goVersion string
541546
toolchain string
547+
ignore []string
542548
pruning modPruning
543549
require []module.Version
544550
retract []retraction
@@ -714,6 +720,11 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
714720
if f.Toolchain != nil {
715721
summary.toolchain = f.Toolchain.Name
716722
}
723+
if f.Ignore != nil {
724+
for _, i := range f.Ignore {
725+
summary.ignore = append(summary.ignore, i.Path)
726+
}
727+
}
717728
if len(f.Require) > 0 {
718729
summary.require = make([]module.Version, 0, len(f.Require)+1)
719730
for _, req := range f.Require {

src/cmd/go/internal/modload/search.go

+50-3
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,16 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
7474
)
7575

7676
q := par.NewQueue(runtime.GOMAXPROCS(0))
77-
77+
ignorePatternsMap := parseIgnorePatterns(ctx, treeCanMatch, modules)
7878
walkPkgs := func(root, importPathRoot string, prune pruning) {
7979
_, span := trace.StartSpan(ctx, "walkPkgs "+root)
8080
defer span.Done()
8181

8282
// If the root itself is a symlink to a directory,
8383
// we want to follow it (see https://go.dev/issue/50807).
8484
// Add a trailing separator to force that to happen.
85-
root = str.WithFilePathSeparator(filepath.Clean(root))
85+
cleanRoot := filepath.Clean(root)
86+
root = str.WithFilePathSeparator(cleanRoot)
8687
err := fsys.WalkDir(root, func(pkgDir string, d fs.DirEntry, err error) error {
8788
if err != nil {
8889
m.AddError(err)
@@ -91,6 +92,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
9192

9293
want := true
9394
elem := ""
95+
relPkgDir := filepath.ToSlash(pkgDir[len(root):])
9496

9597
// Don't use GOROOT/src but do walk down into it.
9698
if pkgDir == root {
@@ -102,10 +104,15 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
102104
_, elem = filepath.Split(pkgDir)
103105
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
104106
want = false
107+
} else if ignorePatternsMap[cleanRoot] != nil && ignorePatternsMap[cleanRoot].ShouldIgnore(relPkgDir) {
108+
if cfg.BuildX {
109+
fmt.Fprintf(os.Stderr, "# ignoring directory %s\n", pkgDir)
110+
}
111+
want = false
105112
}
106113
}
107114

108-
name := path.Join(importPathRoot, filepath.ToSlash(pkgDir[len(root):]))
115+
name := path.Join(importPathRoot, relPkgDir)
109116
if !treeCanMatch(name) {
110117
want = false
111118
}
@@ -303,3 +310,43 @@ func MatchInModule(ctx context.Context, pattern string, m module.Version, tags m
303310
}
304311
return match
305312
}
313+
314+
// parseIgnorePatterns collects all ignore patterns associated with the
315+
// provided list of modules.
316+
// It returns a map of module root -> *search.IgnorePatterns.
317+
func parseIgnorePatterns(ctx context.Context, treeCanMatch func(string) bool, modules []module.Version) map[string]*search.IgnorePatterns {
318+
ignorePatternsMap := make(map[string]*search.IgnorePatterns)
319+
for _, mod := range modules {
320+
if gover.IsToolchain(mod.Path) || !treeCanMatch(mod.Path) {
321+
continue
322+
}
323+
var modRoot string
324+
var ignorePatterns []string
325+
if MainModules.Contains(mod.Path) {
326+
modRoot = MainModules.ModRoot(mod)
327+
if modRoot == "" {
328+
continue
329+
}
330+
modIndex := MainModules.Index(mod)
331+
if modIndex == nil {
332+
continue
333+
}
334+
ignorePatterns = modIndex.ignore
335+
} else if cfg.BuildMod != "vendor" {
336+
// Skip getting ignore patterns for vendored modules because they
337+
// do not have go.mod files.
338+
var err error
339+
modRoot, _, err = fetch(ctx, mod)
340+
if err != nil {
341+
continue
342+
}
343+
summary, err := goModSummary(mod)
344+
if err != nil {
345+
continue
346+
}
347+
ignorePatterns = summary.ignore
348+
}
349+
ignorePatternsMap[modRoot] = search.NewIgnorePatterns(ignorePatterns)
350+
}
351+
return ignorePatternsMap
352+
}

0 commit comments

Comments
 (0)