tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.setenv("CGO_ENABLED", "0")
tg.runFail("install", "cgotest")
- tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'")
+ tg.grepStderr("build constraints exclude all Go files", "go install cgotest did not report 'build constraints exclude all Go files'")
}
func TestRelativeGOBINFail(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOBIN", tg.path("gobin"))
tg.runFail("get", "-d", "golang.org/x/tools")
- tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+ tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
tg.runFail("get", "-d", "-u", "golang.org/x/tools")
- tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+ tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
tg.runFail("get", "-d", "golang.org/x/tools")
- tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+ tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
}
func TestGoGetTestOnlyPkg(t *testing.T) {
wd, _ := os.Getwd()
testdata := filepath.Join(wd, "testdata")
-
for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
t.Run(dir, func(t *testing.T) {
tg := testgo(t)
}
}
+func TestNoGoError(t *testing.T) {
+ wd, _ := os.Getwd()
+ testdata := filepath.Join(wd, "testdata")
+ for _, dir := range []string{"empty/test", "empty/xtest", "empty/testxtest", "exclude", "exclude/ignore", "exclude/empty"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", testdata)
+ tg.cd(filepath.Join(testdata, "src"))
+ tg.runFail("build", "./"+dir)
+ var want string
+ if strings.Contains(dir, "test") {
+ want = "no non-test Go files in "
+ } else if dir == "exclude" {
+ want = "build constraints exclude all Go files in "
+ } else {
+ want = "no Go files in "
+ }
+ tg.grepStderr(want, "wrong reason for failure")
+ })
+ }
+}
+
func TestTestRaceInstall(t *testing.T) {
if !canRace {
t.Skip("no race detector")
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "./testdata/testonly")
- tg.grepStderr("no buildable Go", "go build ./testdata/testonly produced unexpected error")
+ tg.grepStderr("no non-test Go files in", "go build ./testdata/testonly produced unexpected error")
}
func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) {
func TestGoTestImportErrorStack(t *testing.T) {
const out = `package testdep/p1 (test)
imports testdep/p2
- imports testdep/p3: no buildable Go source files`
+ imports testdep/p3: build constraints exclude all Go files `
tg := testgo(t)
defer tg.cleanup()
func F() { p1.F(true) }
`)
tg.runFail("install", "p2")
- tg.grepStderr("no buildable Go source files", "did not complain about missing sources")
+ tg.grepStderr("no Go files", "did not complain about missing sources")
tg.tempFile("src/p1/missing.go", `//go:binary-only-package
GobinSubdir bool // install target would be subdir of GOBIN
}
+type NoGoError struct {
+ Package *Package
+}
+
+func (e *NoGoError) Error() string {
+ // Count files beginning with _ and ., which we will pretend don't exist at all.
+ dummy := 0
+ for _, name := range e.Package.IgnoredGoFiles {
+ if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
+ dummy++
+ }
+ }
+
+ if len(e.Package.IgnoredGoFiles) > dummy {
+ // Go files exist, but they were ignored due to build constraints.
+ return "build constraints exclude all Go files in " + e.Package.Dir
+ }
+ if len(e.Package.TestGoFiles)+len(e.Package.XTestGoFiles) > 0 {
+ // Test Go files exist, but we're not interested in them.
+ // The double-negative is unfortunate but we want e.Package.Dir
+ // to appear at the end of error message.
+ return "no non-test Go files in " + e.Package.Dir
+ }
+ return "no Go files in " + e.Package.Dir
+}
+
// Vendored returns the vendor-resolved version of imports,
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
// The imports in p.TestImports and p.XTestImports are not recursively
p.Internal.LocalPrefix = dirToImportPath(p.Dir)
if err != nil {
+ if _, ok := err.(*build.NoGoError); ok {
+ err = &NoGoError{Package: p}
+ }
p.Incomplete = true
err = base.ExpandScanner(err)
p.Error = &PackageError{
var b Builder
b.Init()
- // Set the behavior for `go get` to not error on packages with test files only.
- b.testFilesOnlyOK = forGet
var a *Action
if cfg.BuildBuildmode == "shared" {
if libName, err := libname(args, pkgs); err != nil {
a = &Action{}
var tools []*Action
for _, p := range pkgs {
+ // During 'go get', don't attempt (and fail) to install packages with only tests.
+ // TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760.
+ if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
+ continue
+ }
// If p is a tool, delay the installation until the end of the build.
// This avoids installing assemblers/compilers that are being executed
// by other steps in the build.
flagCache map[string]bool // a cache of supported compiler flags
Print func(args ...interface{}) (int, error)
- testFilesOnlyOK bool // do not error if the packages only have test files
-
output sync.Mutex
scriptDir string // current directory in printed script
if err != nil {
if err == errPrintedOutput {
base.SetExitStatus(2)
- } else if _, ok := err.(*build.NoGoError); ok && len(a.Package.TestGoFiles) > 0 && b.testFilesOnlyOK {
- // Ignore the "no buildable Go source files" error for a package with only test files.
} else {
base.Errorf("%s", err)
}
}
defer func() {
- if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.Package.TestGoFiles) > 0) {
+ if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
}
}()
}
if len(gofiles) == 0 {
- return &build.NoGoError{Dir: a.Package.Dir}
+ return &load.NoGoError{Package: a.Package}
}
// If we're doing coverage, preprocess the .go files and put them in the work directory