mirror of https://github.com/golang/go.git
test: make runindir tests pass regardless of whether module mode is in use
The "runindir" tests used "go run", but relied on relative imports (which are not supported by "go run" in module mode). Instead, such tests must use fully-qualified imports, which require either a go.mod file (in module mode) or that the package be in an appropriate subdirectory of GOPATH/src (in GOPATH mode). To set up such a directory, we use yet another copy of the same overlayDir function currently found in the misc subdirectory of this repository. Fixes #33912 Updates #30228 Change-Id: If3d7ea2f7942ba496d98aaaf24a90bcdcf4df9f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/225205 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
16cfab8d89
commit
91b8b130dd
|
|
@ -12,8 +12,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
ssa1 "./p1/ssa"
|
ssa1 "issue29612.dir/p1/ssa"
|
||||||
ssa2 "./p2/ssa"
|
ssa2 "issue29612.dir/p2/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
137
test/run.go
137
test/run.go
|
|
@ -607,20 +607,23 @@ func (t *test) run() {
|
||||||
os.Setenv("GOARCH", runtime.GOARCH)
|
os.Setenv("GOARCH", runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
useTmp := true
|
var (
|
||||||
runInDir := false
|
runInDir = t.tempDir
|
||||||
|
tempDirIsGOPATH = false
|
||||||
|
)
|
||||||
runcmd := func(args ...string) ([]byte, error) {
|
runcmd := func(args ...string) ([]byte, error) {
|
||||||
cmd := exec.Command(args[0], args[1:]...)
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
cmd.Stdout = &buf
|
cmd.Stdout = &buf
|
||||||
cmd.Stderr = &buf
|
cmd.Stderr = &buf
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = append(os.Environ(), "GOENV=off", "GOFLAGS=")
|
||||||
if useTmp {
|
if runInDir != "" {
|
||||||
cmd.Dir = t.tempDir
|
cmd.Dir = runInDir
|
||||||
cmd.Env = envForDir(cmd.Dir)
|
// Set PWD to match Dir to speed up os.Getwd in the child process.
|
||||||
|
cmd.Env = append(cmd.Env, "PWD="+cmd.Dir)
|
||||||
}
|
}
|
||||||
if runInDir {
|
if tempDirIsGOPATH {
|
||||||
cmd.Dir = t.goDirName()
|
cmd.Env = append(cmd.Env, "GOPATH="+t.tempDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
@ -863,13 +866,31 @@ func (t *test) run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
case "runindir":
|
case "runindir":
|
||||||
// run "go run ." in t.goDirName()
|
// Make a shallow copy of t.goDirName() in its own module and GOPATH, and
|
||||||
// It's used when test requires go build and run the binary success.
|
// run "go run ." in it. The module path (and hence import path prefix) of
|
||||||
// Example when long import path require (see issue29612.dir) or test
|
// the copy is equal to the basename of the source directory.
|
||||||
// contains assembly file (see issue15609.dir).
|
//
|
||||||
// Verify the expected output.
|
// It's used when test a requires a full 'go build' in order to compile
|
||||||
useTmp = false
|
// the sources, such as when importing multiple packages (issue29612.dir)
|
||||||
runInDir = true
|
// or compiling a package containing assembly files (see issue15609.dir),
|
||||||
|
// but still needs to be run to verify the expected output.
|
||||||
|
tempDirIsGOPATH = true
|
||||||
|
srcDir := t.goDirName()
|
||||||
|
modName := filepath.Base(srcDir)
|
||||||
|
gopathSrcDir := filepath.Join(t.tempDir, "src", modName)
|
||||||
|
runInDir = gopathSrcDir
|
||||||
|
|
||||||
|
if err := overlayDir(gopathSrcDir, srcDir); err != nil {
|
||||||
|
t.err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
modFile := fmt.Sprintf("module %s\ngo 1.14\n", modName)
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(gopathSrcDir, "go.mod"), []byte(modFile), 0666); err != nil {
|
||||||
|
t.err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
cmd := []string{goTool(), "run", goGcflags()}
|
cmd := []string{goTool(), "run", goGcflags()}
|
||||||
if *linkshared {
|
if *linkshared {
|
||||||
cmd = append(cmd, "-linkshared")
|
cmd = append(cmd, "-linkshared")
|
||||||
|
|
@ -1003,7 +1024,7 @@ func (t *test) run() {
|
||||||
// Run Go file if no special go command flags are provided;
|
// Run Go file if no special go command flags are provided;
|
||||||
// otherwise build an executable and run it.
|
// otherwise build an executable and run it.
|
||||||
// Verify the output.
|
// Verify the output.
|
||||||
useTmp = false
|
runInDir = ""
|
||||||
var out []byte
|
var out []byte
|
||||||
var err error
|
var err error
|
||||||
if len(flags)+len(args) == 0 && goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS {
|
if len(flags)+len(args) == 0 && goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS {
|
||||||
|
|
@ -1051,7 +1072,7 @@ func (t *test) run() {
|
||||||
defer func() {
|
defer func() {
|
||||||
<-rungatec
|
<-rungatec
|
||||||
}()
|
}()
|
||||||
useTmp = false
|
runInDir = ""
|
||||||
cmd := []string{goTool(), "run", goGcflags()}
|
cmd := []string{goTool(), "run", goGcflags()}
|
||||||
if *linkshared {
|
if *linkshared {
|
||||||
cmd = append(cmd, "-linkshared")
|
cmd = append(cmd, "-linkshared")
|
||||||
|
|
@ -1084,7 +1105,7 @@ func (t *test) run() {
|
||||||
case "errorcheckoutput":
|
case "errorcheckoutput":
|
||||||
// Run Go file and write its output into temporary Go file.
|
// Run Go file and write its output into temporary Go file.
|
||||||
// Compile and errorCheck generated Go file.
|
// Compile and errorCheck generated Go file.
|
||||||
useTmp = false
|
runInDir = ""
|
||||||
cmd := []string{goTool(), "run", goGcflags()}
|
cmd := []string{goTool(), "run", goGcflags()}
|
||||||
if *linkshared {
|
if *linkshared {
|
||||||
cmd = append(cmd, "-linkshared")
|
cmd = append(cmd, "-linkshared")
|
||||||
|
|
@ -1752,23 +1773,6 @@ func checkShouldTest() {
|
||||||
assert(shouldTest("// +build !windows !plan9", "windows", "amd64"))
|
assert(shouldTest("// +build !windows !plan9", "windows", "amd64"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) []string {
|
|
||||||
env := os.Environ()
|
|
||||||
for i, kv := range env {
|
|
||||||
if strings.HasPrefix(kv, "PWD=") {
|
|
||||||
env[i] = "PWD=" + dir
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
}
|
|
||||||
env = append(env, "PWD="+dir)
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
|
|
||||||
func getenv(key, def string) string {
|
func getenv(key, def string) string {
|
||||||
value := os.Getenv(key)
|
value := os.Getenv(key)
|
||||||
if value != "" {
|
if value != "" {
|
||||||
|
|
@ -1776,3 +1780,66 @@ func getenv(key, def string) string {
|
||||||
}
|
}
|
||||||
return def
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
|
||||||
|
func overlayDir(dstRoot, srcRoot string) error {
|
||||||
|
dstRoot = filepath.Clean(dstRoot)
|
||||||
|
if err := os.MkdirAll(dstRoot, 0777); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
srcRoot, err := filepath.Abs(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil || srcPath == srcRoot {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix := strings.TrimPrefix(srcPath, srcRoot)
|
||||||
|
for len(suffix) > 0 && suffix[0] == filepath.Separator {
|
||||||
|
suffix = suffix[1:]
|
||||||
|
}
|
||||||
|
dstPath := filepath.Join(dstRoot, suffix)
|
||||||
|
|
||||||
|
perm := info.Mode() & os.ModePerm
|
||||||
|
if info.Mode()&os.ModeSymlink != 0 {
|
||||||
|
info, err = os.Stat(srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
perm = info.Mode() & os.ModePerm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always copy directories (don't symlink them).
|
||||||
|
// If we add a file in the overlay, we don't want to add it in the original.
|
||||||
|
if info.IsDir() {
|
||||||
|
return os.MkdirAll(dstPath, perm|0200)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the OS supports symlinks, use them instead of copying bytes.
|
||||||
|
if err := os.Symlink(srcPath, dstPath); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, copy the bytes.
|
||||||
|
src, err := os.Open(srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
|
dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(dst, src)
|
||||||
|
if closeErr := dst.Close(); err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue