Commit 4efe9250 authored by Russ Cox's avatar Russ Cox

cmd/go: split out cmd/go/internal/test

This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

Change-Id: I2d0ccdb84814537ab8b8842aa1b5f5bc0a88a0fc
Reviewed-on: https://go-review.googlesource.com/36198Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent 3c667ef4
...@@ -6,8 +6,6 @@ package main ...@@ -6,8 +6,6 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -17,6 +15,9 @@ import ( ...@@ -17,6 +15,9 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
) )
var cmdBug = &base.Command{ var cmdBug = &base.Command{
......
...@@ -397,7 +397,7 @@ func (g *Generator) exec(words []string) { ...@@ -397,7 +397,7 @@ func (g *Generator) exec(words []string) {
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
// Run the command in the package directory. // Run the command in the package directory.
cmd.Dir = g.dir cmd.Dir = g.dir
cmd.Env = mergeEnvLists(g.env, cfg.OrigEnv) cmd.Env = base.MergeEnvLists(g.env, cfg.OrigEnv)
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
g.errorf("running %q: %s", words[0], err) g.errorf("running %q: %s", words[0], err)
......
...@@ -6,7 +6,7 @@ package base ...@@ -6,7 +6,7 @@ package base
import "strings" import "strings"
// envForDir returns a copy of the environment // EnvForDir returns a copy of the environment
// suitable for running in the given directory. // suitable for running in the given directory.
// The environment is the current process's environment // The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the // but with an updated $PWD, so that an os.Getwd in the
......
...@@ -2,15 +2,10 @@ ...@@ -2,15 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package test
import ( import (
"bytes" "bytes"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/go/internal/work"
"errors" "errors"
"fmt" "fmt"
"go/ast" "go/ast"
...@@ -30,16 +25,22 @@ import ( ...@@ -30,16 +25,22 @@ import (
"time" "time"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/go/internal/work"
) )
// Break init loop. // Break init loop.
func init() { func init() {
cmdTest.Run = runTest CmdTest.Run = runTest
} }
const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]" const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
var cmdTest = &base.Command{ var CmdTest = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: testUsage, UsageLine: testUsage,
Short: "test packages", Short: "test packages",
...@@ -112,7 +113,15 @@ The test binary also accepts flags that control execution of the test; these ...@@ -112,7 +113,15 @@ The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. flags are also accessible by 'go test'.
` `
var helpTestflag = &base.Command{ // Usage prints the usage message for 'go test -h' and exits.
func Usage() {
os.Stderr.WriteString(testUsage + "\n\n" +
strings.TrimSpace(testFlag1) + "\n\n\t" +
strings.TrimSpace(testFlag2) + "\n")
os.Exit(2)
}
var HelpTestflag = &base.Command{
UsageLine: "testflag", UsageLine: "testflag",
Short: "description of testing flags", Short: "description of testing flags",
Long: ` Long: `
...@@ -317,7 +326,7 @@ In the second example, the argument math is passed through to the test ...@@ -317,7 +326,7 @@ In the second example, the argument math is passed through to the test
binary, instead of being interpreted as the package list. binary, instead of being interpreted as the package list.
` `
var helpTestfunc = &base.Command{ var HelpTestfunc = &base.Command{
UsageLine: "testfunc", UsageLine: "testfunc",
Short: "description of testing functions", Short: "description of testing functions",
Long: ` Long: `
...@@ -408,7 +417,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -408,7 +417,7 @@ func runTest(cmd *base.Command, args []string) {
var pkgArgs []string var pkgArgs []string
pkgArgs, testArgs = testFlags(args) pkgArgs, testArgs = testFlags(args)
findExecCmd() // initialize cached result work.FindExecCmd() // initialize cached result
work.InstrumentInit() work.InstrumentInit()
work.BuildModeInit() work.BuildModeInit()
...@@ -1107,7 +1116,7 @@ var noTestsToRun = []byte("\ntesting: warning: no tests to run\n") ...@@ -1107,7 +1116,7 @@ var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
// builderRunTest is the action for running a test binary. // builderRunTest is the action for running a test binary.
func builderRunTest(b *work.Builder, a *work.Action) error { func builderRunTest(b *work.Builder, a *work.Action) error {
args := str.StringList(findExecCmd(), a.Deps[0].Target, testArgs) args := str.StringList(work.FindExecCmd(), a.Deps[0].Target, testArgs)
a.TestOutput = new(bytes.Buffer) a.TestOutput = new(bytes.Buffer)
if cfg.BuildN || cfg.BuildX { if cfg.BuildN || cfg.BuildX {
...@@ -1127,7 +1136,7 @@ func builderRunTest(b *work.Builder, a *work.Action) error { ...@@ -1127,7 +1136,7 @@ func builderRunTest(b *work.Builder, a *work.Action) error {
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = a.Package.Dir cmd.Dir = a.Package.Dir
cmd.Env = envForDir(cmd.Dir, cfg.OrigEnv) cmd.Env = base.EnvForDir(cmd.Dir, cfg.OrigEnv)
var buf bytes.Buffer var buf bytes.Buffer
if testStreamOutput { if testStreamOutput {
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package test
import ( import (
"flag" "flag"
...@@ -138,7 +138,6 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -138,7 +138,6 @@ func testFlags(args []string) (packageNames, passToTest []string) {
} else { } else {
// Test-only flags. // Test-only flags.
// Arguably should be handled by f.flagValue, but aren't. // Arguably should be handled by f.flagValue, but aren't.
var err error
switch f.name { switch f.name {
// bool flags. // bool flags.
case "c", "i", "v", "cover": case "c", "i", "v", "cover":
...@@ -147,10 +146,11 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -147,10 +146,11 @@ func testFlags(args []string) (packageNames, passToTest []string) {
testO = value testO = value
testNeedBinary = true testNeedBinary = true
case "exec": case "exec":
execCmd, err = str.SplitQuotedFields(value) xcmd, err := str.SplitQuotedFields(value)
if err != nil { if err != nil {
base.Fatalf("invalid flag argument for -%s: %v", f.name, err) base.Fatalf("invalid flag argument for -%s: %v", f.name, err)
} }
work.ExecCmd = xcmd
case "bench": case "bench":
// record that we saw the flag; don't care about the value // record that we saw the flag; don't care about the value
testBench = true testBench = true
......
...@@ -3622,3 +3622,28 @@ func InstrumentInit() { ...@@ -3622,3 +3622,28 @@ func InstrumentInit() {
cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "msan") cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "msan")
} }
} }
// ExecCmd is the command to use to run user binaries.
// Normally it is empty, meaning run the binaries directly.
// If cross-compiling and running on a remote system or
// simulator, it is typically go_GOOS_GOARCH_exec, with
// the target GOOS and GOARCH substituted.
// The -exec flag overrides these defaults.
var ExecCmd []string
// FindExecCmd derives the value of ExecCmd to use.
// It returns that value and leaves ExecCmd set for direct use.
func FindExecCmd() []string {
if ExecCmd != nil {
return ExecCmd
}
ExecCmd = []string{} // avoid work the second time
if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
return ExecCmd
}
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
if err == nil {
ExecCmd = []string{path}
}
return ExecCmd
}
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/help" "cmd/go/internal/help"
"cmd/go/internal/test"
"cmd/go/internal/work" "cmd/go/internal/work"
) )
...@@ -33,7 +34,7 @@ func init() { ...@@ -33,7 +34,7 @@ func init() {
work.CmdInstall, work.CmdInstall,
cmdList, cmdList,
cmdRun, cmdRun,
cmdTest, test.CmdTest,
cmdTool, cmdTool,
cmdVersion, cmdVersion,
cmdVet, cmdVet,
...@@ -45,8 +46,8 @@ func init() { ...@@ -45,8 +46,8 @@ func init() {
help.HelpEnvironment, help.HelpEnvironment,
help.HelpImportPath, help.HelpImportPath,
help.HelpPackages, help.HelpPackages,
helpTestflag, test.HelpTestflag,
helpTestfunc, test.HelpTestfunc,
} }
} }
...@@ -134,41 +135,8 @@ func init() { ...@@ -134,41 +135,8 @@ func init() {
func mainUsage() { func mainUsage() {
// special case "go test -h" // special case "go test -h"
if len(os.Args) > 1 && os.Args[1] == "test" { if len(os.Args) > 1 && os.Args[1] == "test" {
os.Stderr.WriteString(testUsage + "\n\n" + test.Usage()
strings.TrimSpace(testFlag1) + "\n\n\t" +
strings.TrimSpace(testFlag2) + "\n")
os.Exit(2)
} }
help.PrintUsage(os.Stderr) help.PrintUsage(os.Stderr)
os.Exit(2) os.Exit(2)
} }
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the
// child will be faster.
func envForDir(dir string, base []string) []string {
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
return mergeEnvLists([]string{"PWD=" + dir}, base)
}
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
out = append([]string(nil), out...)
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
for i, outkv := range out {
if strings.HasPrefix(outkv, k) {
out[i] = inkv
continue NextVar
}
}
out = append(out, inkv)
}
return out
}
...@@ -7,8 +7,6 @@ package main ...@@ -7,8 +7,6 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"os/exec"
"runtime"
"strings" "strings"
"cmd/go/internal/base" "cmd/go/internal/base"
...@@ -18,23 +16,6 @@ import ( ...@@ -18,23 +16,6 @@ import (
"cmd/go/internal/work" "cmd/go/internal/work"
) )
var execCmd []string // -exec flag, for run and test
func findExecCmd() []string {
if execCmd != nil {
return execCmd
}
execCmd = []string{} // avoid work the second time
if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
return execCmd
}
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
if err == nil {
execCmd = []string{path}
}
return execCmd
}
var cmdRun = &base.Command{ var cmdRun = &base.Command{
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]", UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program", Short: "compile and run Go program",
...@@ -62,7 +43,7 @@ func init() { ...@@ -62,7 +43,7 @@ func init() {
cmdRun.Run = runRun // break init loop cmdRun.Run = runRun // break init loop
work.AddBuildFlags(cmdRun) work.AddBuildFlags(cmdRun)
cmdRun.Flag.Var((*base.StringsFlag)(&execCmd), "exec", "") cmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
} }
func printStderr(args ...interface{}) (int, error) { func printStderr(args ...interface{}) (int, error) {
...@@ -136,7 +117,7 @@ func runRun(cmd *base.Command, args []string) { ...@@ -136,7 +117,7 @@ func runRun(cmd *base.Command, args []string) {
// buildRunProgram is the action for running a binary that has already // buildRunProgram is the action for running a binary that has already
// been compiled. We ignore exit status. // been compiled. We ignore exit status.
func buildRunProgram(b *work.Builder, a *work.Action) error { func buildRunProgram(b *work.Builder, a *work.Action) error {
cmdline := str.StringList(findExecCmd(), a.Deps[0].Target, a.Args) cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
if cfg.BuildN || cfg.BuildX { if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "%s", strings.Join(cmdline, " ")) b.Showcmd("", "%s", strings.Join(cmdline, " "))
if cfg.BuildN { if cfg.BuildN {
......
...@@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) { ...@@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) {
Stdout: os.Stdout, Stdout: os.Stdout,
Stderr: os.Stderr, Stderr: os.Stderr,
// Set $GOROOT, mainly for go tool dist. // Set $GOROOT, mainly for go tool dist.
Env: mergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()), Env: base.MergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()),
} }
err := toolCmd.Run() err := toolCmd.Run()
if err != nil { if err != nil {
......
...@@ -6,7 +6,6 @@ package main ...@@ -6,7 +6,6 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
...@@ -19,6 +18,9 @@ import ( ...@@ -19,6 +18,9 @@ import (
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
) )
// A vcsCmd describes how to use a version control system // A vcsCmd describes how to use a version control system
...@@ -373,7 +375,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ...@@ -373,7 +375,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
cmd := exec.Command(v.cmd, args...) cmd := exec.Command(v.cmd, args...)
cmd.Dir = dir cmd.Dir = dir
cmd.Env = envForDir(cmd.Dir, os.Environ()) cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
if cfg.BuildX { if cfg.BuildX {
fmt.Printf("cd %s\n", dir) fmt.Printf("cd %s\n", dir)
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " ")) fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment