--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func Main() { main() }
"fmt"
"go/format"
"internal/godebug"
- "internal/race"
"internal/testenv"
"io"
"io/fs"
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/robustio"
+ "cmd/go/internal/search"
+ "cmd/go/internal/work"
"cmd/internal/sys"
+
+ cmdgo "cmd/go"
)
func init() {
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
+ // When CMDGO_TEST_RUN_MAIN is set, we're reusing the test binary as cmd/go.
+ // Enable the special behavior needed in cmd/go/internal/work,
+ // run the main func exported via export_test.go, and exit.
+ // We set CMDGO_TEST_RUN_MAIN via os.Setenv and testScript.setup.
+ if os.Getenv("CMDGO_TEST_RUN_MAIN") != "" {
+ if v := os.Getenv("TESTGO_VERSION"); v != "" {
+ work.RuntimeVersion = v
+ }
+
+ if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" {
+ // Disallow installs to the GOROOT from which testgo was built.
+ // Installs to other GOROOTs — such as one set explicitly within a test — are ok.
+ work.AllowInstall = func(a *work.Action) error {
+ if cfg.BuildN {
+ return nil
+ }
+
+ rel := search.InDir(a.Target, testGOROOT)
+ if rel == "" {
+ return nil
+ }
+
+ callerPos := ""
+ if _, file, line, ok := runtime.Caller(1); ok {
+ if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" {
+ file = shortFile
+ }
+ callerPos = fmt.Sprintf("%s:%d: ", file, line)
+ }
+ return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel))
+ }
+ }
+ cmdgo.Main()
+ os.Exit(0)
+ }
+ os.Setenv("CMDGO_TEST_RUN_MAIN", "true")
+
// $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc.
// It is not a standard go command flag; use os.Getenv, not cfg.Getenv.
if os.Getenv("GO_GCFLAGS") != "" {
log.Fatal(err)
}
testGo = filepath.Join(testBin, "go"+exeSuffix)
- args := []string{"build", "-tags", "testgo", "-o", testGo}
- if race.Enabled {
- args = append(args, "-race")
- }
gotool, err := testenv.GoTool()
if err != nil {
fmt.Fprintln(os.Stderr, "locating go tool: ", err)
return
}
- buildCmd := exec.Command(gotool, args...)
- buildCmd.Env = append(os.Environ(), "GOFLAGS=-mod=vendor")
- out, err := buildCmd.CombinedOutput()
+ // Duplicate the test executable into the path at testGo, for $PATH.
+ // If the OS supports symlinks, use them instead of copying bytes.
+ testExe, err := os.Executable()
if err != nil {
- fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
- os.Exit(2)
+ log.Fatal(err)
+ }
+ if err := os.Symlink(testExe, testGo); err != nil {
+ // Otherwise, copy the bytes.
+ src, err := os.Open(testExe)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer src.Close()
+
+ dst, err := os.OpenFile(testGo, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o777)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = io.Copy(dst, src)
+ if closeErr := dst.Close(); err == nil {
+ err = closeErr
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
}
cmd := exec.Command(testGo, "env", "CGO_ENABLED")
}
}
- out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
+ out, err := exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out)
os.Exit(2)
var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
-var runtimeVersion = runtime.Version()
+var RuntimeVersion = runtime.Version()
func runBuild(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
return nil
}
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
return err
}
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
}
func (b *Builder) installShlibname(ctx context.Context, a *Action) error {
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
}
defer b.flushOutput(a)
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
if !a.buggyInstall && !b.IsCmdList {
if cfg.BuildN {
b.Showcmd("", "touch %s", a.Target)
- } else if err := allowInstall(a); err == nil {
+ } else if err := AllowInstall(a); err == nil {
now := time.Now()
os.Chtimes(a.Target, now, now)
}
a.built = a1.built
return nil
}
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
return b.moveOrCopyFile(a.Target, a1.built, perm, false)
}
-// allowInstall returns a non-nil error if this invocation of the go command is
+// AllowInstall returns a non-nil error if this invocation of the go command is
// allowed to install a.Target.
//
-// (The build of cmd/go running under its own test is forbidden from installing
-// to its original GOROOT.)
-var allowInstall = func(*Action) error { return nil }
+// The build of cmd/go running under its own test is forbidden from installing
+// to its original GOROOT. The var is exported so it can be set by TestMain.
+var AllowInstall = func(*Action) error { return nil }
// cleanup removes a's object dir to keep the amount of
// on-disk garbage down in a large build. On an operating system
return nil
}
- if err := allowInstall(a); err != nil {
+ if err := AllowInstall(a); err != nil {
return err
}
if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
defaultGcFlags = append(defaultGcFlags, "-dwarf=false")
}
- if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
- defaultGcFlags = append(defaultGcFlags, "-goversion", runtimeVersion)
+ if strings.HasPrefix(RuntimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
+ defaultGcFlags = append(defaultGcFlags, "-goversion", RuntimeVersion)
}
if symabis != "" {
defaultGcFlags = append(defaultGcFlags, "-symabis", symabis)
+++ /dev/null
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file contains extra hooks for testing the go command.
-
-//go:build testgo
-
-package work
-
-import (
- "cmd/go/internal/cfg"
- "cmd/go/internal/search"
- "fmt"
- "os"
- "path/filepath"
- "runtime"
-)
-
-func init() {
- if v := os.Getenv("TESTGO_VERSION"); v != "" {
- runtimeVersion = v
- }
-
- if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" {
- // Disallow installs to the GOROOT from which testgo was built.
- // Installs to other GOROOTs — such as one set explicitly within a test — are ok.
- allowInstall = func(a *Action) error {
- if cfg.BuildN {
- return nil
- }
-
- rel := search.InDir(a.Target, testGOROOT)
- if rel == "" {
- return nil
- }
-
- callerPos := ""
- if _, file, line, ok := runtime.Caller(1); ok {
- if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" {
- file = shortFile
- }
- callerPos = fmt.Sprintf("%s:%d: ", file, line)
- }
- return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel))
- }
- }
-}
"goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator),
"/=" + string(os.PathSeparator),
+ "CMDGO_TEST_RUN_MAIN=true",
}
if !testenv.HasExternalNetwork() {
ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")