Skip to content

Commit dfaceea

Browse files
fmeumtyler-french
authored andcommitted
Forward -testfilter to nogo and fix failure in case of no srcs (#4075)
**What type of PR is this?** Bug fix **What does this PR do? Why is it needed?** Without this, nogo runs on the external test sources when compiling the internal test library, which can result in missing deps errors and is also wasteful. Since filtering out files made certain nogo actions run on no files, also fix a bug that affects this situation by writing out an empty log in addition to an empty facts file. The code that checks imports and builds the importcfg was shared between `compilepkg` and `nogo` and is now extracted into a common method. Along the way, have it output the file into the working directory, which simplifies cleanup, makes the file easier to find and avoids writing files unknown to Bazel into the output directory. Also removes some unused test files. **Which issues(s) does this PR fix?** Fixes #4062 Fixes #4070 Fixes #4073 **Other notes for review**
1 parent e470f85 commit dfaceea

File tree

9 files changed

+213
-137
lines changed

9 files changed

+213
-137
lines changed

go/private/actions/compilepkg.bzl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,13 @@ def emit_compilepkg(
207207
_run_nogo(
208208
go,
209209
sources = sources,
210+
cgo_go_srcs = cgo_go_srcs_for_nogo,
210211
importpath = importpath,
211212
importmap = importmap,
212213
archives = archives + ([cover_archive] if cover_archive else []),
213214
recompile_internal_deps = recompile_internal_deps,
214215
cover_mode = cover_mode,
215-
cgo_go_srcs = cgo_go_srcs_for_nogo,
216+
testfilter = testfilter,
216217
out_facts = out_facts,
217218
out_log = out_nogo_log,
218219
out_validation = out_nogo_validation,
@@ -223,12 +224,13 @@ def _run_nogo(
223224
go,
224225
*,
225226
sources,
227+
cgo_go_srcs,
226228
importpath,
227229
importmap,
228230
archives,
229231
recompile_internal_deps,
230232
cover_mode,
231-
cgo_go_srcs,
233+
testfilter,
232234
out_facts,
233235
out_log,
234236
out_validation,
@@ -256,7 +258,10 @@ def _run_nogo(
256258
args.add("-importpath", go.label.name)
257259
if importmap:
258260
args.add("-p", importmap)
261+
259262
args.add("-package_list", go.package_list)
263+
if testfilter:
264+
args.add("-testfilter", testfilter)
260265

261266
args.add_all(archives, before_each = "-facts", map_each = _facts)
262267
args.add("-out_facts", out_facts)

go/tools/builders/compilepkg.go

Lines changed: 43 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -98,29 +98,9 @@ func compilePkg(args []string) error {
9898
return err
9999
}
100100

101-
// TODO(jayconrod): remove -testfilter flag. The test action should compile
102-
// the main, internal, and external packages by calling compileArchive
103-
// with the correct sources for each.
104-
switch testFilter {
105-
case "off":
106-
case "only":
107-
testSrcs := make([]fileInfo, 0, len(srcs.goSrcs))
108-
for _, f := range srcs.goSrcs {
109-
if strings.HasSuffix(f.pkg, "_test") {
110-
testSrcs = append(testSrcs, f)
111-
}
112-
}
113-
srcs.goSrcs = testSrcs
114-
case "exclude":
115-
libSrcs := make([]fileInfo, 0, len(srcs.goSrcs))
116-
for _, f := range srcs.goSrcs {
117-
if !strings.HasSuffix(f.pkg, "_test") {
118-
libSrcs = append(libSrcs, f)
119-
}
120-
}
121-
srcs.goSrcs = libSrcs
122-
default:
123-
return fmt.Errorf("invalid test filter %q", testFilter)
101+
err = applyTestFilter(testFilter, &srcs)
102+
if err != nil {
103+
return err
124104
}
125105

126106
return compileArchive(
@@ -351,44 +331,10 @@ func compileArchive(
351331
gcFlags = append(gcFlags, createTrimPath(gcFlags, "."))
352332
}
353333

354-
// Check that the filtered sources don't import anything outside of
355-
// the standard library and the direct dependencies.
356-
imports, err := checkImports(srcs.goSrcs, deps, packageListPath, importPath, recompileInternalDeps)
357-
if err != nil {
358-
return err
359-
}
360-
if compilingWithCgo {
361-
// cgo generated code imports some extra packages.
362-
imports["runtime/cgo"] = nil
363-
imports["syscall"] = nil
364-
imports["unsafe"] = nil
365-
}
366-
if coverMode != "" {
367-
if coverMode == "atomic" {
368-
imports["sync/atomic"] = nil
369-
}
370-
const coverdataPath = "github.com/bazelbuild/rules_go/go/tools/coverdata"
371-
var coverdata *archive
372-
for i := range deps {
373-
if deps[i].importPath == coverdataPath {
374-
coverdata = &deps[i]
375-
break
376-
}
377-
}
378-
if coverdata == nil {
379-
return errors.New("coverage requested but coverdata dependency not provided")
380-
}
381-
imports[coverdataPath] = coverdata
382-
}
383-
384-
// Build an importcfg file for the compiler.
385-
importcfgPath, err := buildImportcfgFileForCompile(imports, goenv.installSuffix, filepath.Dir(outLinkObj))
334+
importcfgPath, err := checkImportsAndBuildCfg(goenv, importPath, srcs, deps, packageListPath, recompileInternalDeps, compilingWithCgo, coverMode, workDir)
386335
if err != nil {
387336
return err
388337
}
389-
if !goenv.shouldPreserveWorkDir {
390-
defer os.Remove(importcfgPath)
391-
}
392338

393339
// Build an embedcfg file mapping embed patterns to filenames.
394340
// Embed patterns are relative to any one of a list of root directories
@@ -490,6 +436,45 @@ func compileArchive(
490436
return nil
491437
}
492438

439+
func checkImportsAndBuildCfg(goenv *env, importPath string, srcs archiveSrcs, deps []archive, packageListPath string, recompileInternalDeps []string, compilingWithCgo bool, coverMode string, workDir string) (string, error) {
440+
// Check that the filtered sources don't import anything outside of
441+
// the standard library and the direct dependencies.
442+
imports, err := checkImports(srcs.goSrcs, deps, packageListPath, importPath, recompileInternalDeps)
443+
if err != nil {
444+
return "", err
445+
}
446+
if compilingWithCgo {
447+
// cgo generated code imports some extra packages.
448+
imports["runtime/cgo"] = nil
449+
imports["syscall"] = nil
450+
imports["unsafe"] = nil
451+
}
452+
if coverMode != "" {
453+
if coverMode == "atomic" {
454+
imports["sync/atomic"] = nil
455+
}
456+
const coverdataPath = "github.com/bazelbuild/rules_go/go/tools/coverdata"
457+
var coverdata *archive
458+
for i := range deps {
459+
if deps[i].importPath == coverdataPath {
460+
coverdata = &deps[i]
461+
break
462+
}
463+
}
464+
if coverdata == nil {
465+
return "", errors.New("coverage requested but coverdata dependency not provided")
466+
}
467+
imports[coverdataPath] = coverdata
468+
}
469+
470+
// Build an importcfg file for the compiler.
471+
importcfgPath, err := buildImportcfgFileForCompile(imports, goenv.installSuffix, workDir)
472+
if err != nil {
473+
return "", err
474+
}
475+
return importcfgPath, nil
476+
}
477+
493478
func compileGo(goenv *env, srcs []string, packagePath, importcfgPath, embedcfgPath, asmHdrPath, symabisPath string, gcFlags []string, pgoprofile, outLinkobjPath, outInterfacePath string) error {
494479
args := goenv.goTool("compile")
495480
args = append(args, "-p", packagePath, "-importcfg", importcfgPath, "-pack")

go/tools/builders/filter.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,36 @@ func filterAndSplitFiles(fileNames []string) (archiveSrcs, error) {
112112
return res, nil
113113
}
114114

115+
// applyTestFilter filters out test files from the list of sources in place
116+
// according to the filter.
117+
func applyTestFilter(testFilter string, srcs *archiveSrcs) error {
118+
// TODO(jayconrod): remove -testfilter flag. The test action should compile
119+
// the main, internal, and external packages by calling compileArchive
120+
// with the correct sources for each.
121+
switch testFilter {
122+
case "off":
123+
case "only":
124+
testSrcs := make([]fileInfo, 0, len(srcs.goSrcs))
125+
for _, f := range srcs.goSrcs {
126+
if strings.HasSuffix(f.pkg, "_test") {
127+
testSrcs = append(testSrcs, f)
128+
}
129+
}
130+
srcs.goSrcs = testSrcs
131+
case "exclude":
132+
libSrcs := make([]fileInfo, 0, len(srcs.goSrcs))
133+
for _, f := range srcs.goSrcs {
134+
if !strings.HasSuffix(f.pkg, "_test") {
135+
libSrcs = append(libSrcs, f)
136+
}
137+
}
138+
srcs.goSrcs = libSrcs
139+
default:
140+
return fmt.Errorf("invalid test filter %q", testFilter)
141+
}
142+
return nil
143+
}
144+
115145
// readFileInfo applies build constraints to an input file and returns whether
116146
// it should be compiled.
117147
func readFileInfo(bctx build.Context, input string) (fileInfo, error) {

go/tools/builders/nogo.go

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func nogo(args []string) error {
2323
var unfilteredSrcs, recompileInternalDeps multiFlag
2424
var deps, facts archiveMultiFlag
2525
var importPath, packagePath, nogoPath, packageListPath string
26+
var testFilter string
2627
var outFactsPath, outLogPath string
2728
var coverMode string
2829
fs.Var(&unfilteredSrcs, "src", ".go, .c, .cc, .m, .mm, .s, or .S file to be filtered and compiled")
@@ -33,6 +34,7 @@ func nogo(args []string) error {
3334
fs.StringVar(&packageListPath, "package_list", "", "The file containing the list of standard library packages")
3435
fs.Var(&recompileInternalDeps, "recompile_internal_deps", "The import path of the direct dependencies that needs to be recompiled.")
3536
fs.StringVar(&coverMode, "cover_mode", "", "The coverage mode to use. Empty if coverage instrumentation should not be added.")
37+
fs.StringVar(&testFilter, "testfilter", "off", "Controls test package filtering")
3638
fs.StringVar(&nogoPath, "nogo", "", "The nogo binary")
3739
fs.StringVar(&outFactsPath, "out_facts", "", "The file to emit serialized nogo facts to")
3840
fs.StringVar(&outLogPath, "out_log", "", "The file to emit nogo logs into")
@@ -52,6 +54,11 @@ func nogo(args []string) error {
5254
return err
5355
}
5456

57+
err = applyTestFilter(testFilter, &srcs)
58+
if err != nil {
59+
return err
60+
}
61+
5562
var goSrcs []string
5663
haveCgo := false
5764
for _, src := range srcs.goSrcs {
@@ -68,50 +75,28 @@ func nogo(args []string) error {
6875
}
6976
defer cleanup()
7077

71-
imports, err := checkImports(srcs.goSrcs, deps, packageListPath, importPath, recompileInternalDeps)
78+
compilingWithCgo := os.Getenv("CGO_ENABLED") == "1" && haveCgo
79+
importcfgPath, err := checkImportsAndBuildCfg(goenv, importPath, srcs, deps, packageListPath, recompileInternalDeps, compilingWithCgo, coverMode, workDir)
7280
if err != nil {
7381
return err
7482
}
75-
cgoEnabled := os.Getenv("CGO_ENABLED") == "1"
76-
if haveCgo && cgoEnabled {
77-
// cgo generated code imports some extra packages.
78-
imports["runtime/cgo"] = nil
79-
imports["syscall"] = nil
80-
imports["unsafe"] = nil
81-
}
82-
if coverMode != "" {
83-
if coverMode == "atomic" {
84-
imports["sync/atomic"] = nil
85-
}
86-
const coverdataPath = "github.com/bazelbuild/rules_go/go/tools/coverdata"
87-
var coverdata *archive
88-
for i := range deps {
89-
if deps[i].importPath == coverdataPath {
90-
coverdata = &deps[i]
91-
break
92-
}
93-
}
94-
if coverdata == nil {
95-
return errors.New("coverage requested but coverdata dependency not provided")
96-
}
97-
imports[coverdataPath] = coverdata
98-
}
99-
100-
importcfgPath, err := buildImportcfgFileForCompile(imports, goenv.installSuffix, filepath.Dir(outFactsPath))
101-
if err != nil {
102-
return err
103-
}
104-
if !goenv.shouldPreserveWorkDir {
105-
defer os.Remove(importcfgPath)
106-
}
10783

10884
return runNogo(workDir, nogoPath, goSrcs, facts, importPath, importcfgPath, outFactsPath, outLogPath)
10985
}
11086

11187
func runNogo(workDir string, nogoPath string, srcs []string, facts []archive, packagePath, importcfgPath, outFactsPath string, outLogPath string) error {
11288
if len(srcs) == 0 {
11389
// emit_compilepkg expects a nogo facts file, even if it's empty.
114-
return os.WriteFile(outFactsPath, nil, 0o666)
90+
// We also need to write the validation output log.
91+
err := os.WriteFile(outFactsPath, nil, 0o666)
92+
if err != nil {
93+
return fmt.Errorf("error writing empty nogo facts file: %v", err)
94+
}
95+
err = os.WriteFile(outLogPath, nil, 0o666)
96+
if err != nil {
97+
return fmt.Errorf("error writing empty nogo log file: %v", err)
98+
}
99+
return nil
115100
}
116101
args := []string{nogoPath}
117102
args = append(args, "-p", packagePath)

tests/core/nogo/BUILD.bazel

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/core/nogo/common.bzl

Lines changed: 0 additions & 38 deletions
This file was deleted.

tests/core/nogo/tests/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
2+
3+
go_bazel_test(
4+
name = "tests_test",
5+
srcs = ["tests_test.go"],
6+
)

tests/core/nogo/tests/README.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
nogo for go_test
2+
=============================
3+
4+
.. _nogo: /go/nogo.rst
5+
.. _go_test: /docs/go/core/rules.md#_go_test
6+
7+
Verifies interactions between `nogo`_ and `go_test`_.
8+
9+
10+
tests_test
11+
=============================
12+
13+
Tests that `nogo`_ can handle various edge cases of external tests.

0 commit comments

Comments
 (0)