File size: 3,997 Bytes
e36aeda | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | // Copyright 2024 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 scripttest adapts the script engine for use in tests.
package scripttest
import (
"internal/testenv"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
)
// SetupTestGoRoot sets up a temporary GOROOT for use with script test
// execution. It copies the existing goroot bin and pkg dirs using
// symlinks (if possible) or raw copying. Return value is the path to
// the newly created testgoroot dir.
func SetupTestGoRoot(t *testing.T, tmpdir string, goroot string) string {
mustMkdir := func(path string) {
if err := os.MkdirAll(path, 0777); err != nil {
t.Fatalf("SetupTestGoRoot mkdir %s failed: %v", path, err)
}
}
replicateDir := func(srcdir, dstdir string) {
files, err := os.ReadDir(srcdir)
if err != nil {
t.Fatalf("inspecting %s: %v", srcdir, err)
}
for _, file := range files {
fn := file.Name()
linkOrCopy(t, filepath.Join(srcdir, fn), filepath.Join(dstdir, fn))
}
}
// Create various dirs in testgoroot.
findToolOnce.Do(func() { findToolSub(t) })
if toolsub == "" {
t.Fatal("failed to find toolsub")
}
tomake := []string{
"bin",
"src",
"pkg",
filepath.Join("pkg", "include"),
toolsub,
}
made := []string{}
tgr := filepath.Join(tmpdir, "testgoroot")
mustMkdir(tgr)
for _, targ := range tomake {
path := filepath.Join(tgr, targ)
mustMkdir(path)
made = append(made, path)
}
// Replicate selected portions of the content.
replicateDir(filepath.Join(goroot, "bin"), made[0])
replicateDir(filepath.Join(goroot, "src"), made[1])
replicateDir(filepath.Join(goroot, "pkg", "include"), made[3])
replicateDir(filepath.Join(goroot, toolsub), made[4])
return tgr
}
// ReplaceGoToolInTestGoRoot replaces the go tool binary toolname with
// an alternate executable newtoolpath within a test GOROOT directory
// previously created by SetupTestGoRoot.
func ReplaceGoToolInTestGoRoot(t *testing.T, testgoroot, toolname, newtoolpath string) {
findToolOnce.Do(func() { findToolSub(t) })
if toolsub == "" {
t.Fatal("failed to find toolsub")
}
exename := toolname
if runtime.GOOS == "windows" {
exename += ".exe"
}
toolpath := filepath.Join(testgoroot, toolsub, exename)
if err := os.Remove(toolpath); err != nil {
t.Fatalf("removing %s: %v", toolpath, err)
}
linkOrCopy(t, newtoolpath, toolpath)
}
// toolsub is the tool subdirectory underneath GOROOT.
var toolsub string
// findToolOnce runs findToolSub only once.
var findToolOnce sync.Once
// findToolSub sets toolsub to the value used by the current go command.
func findToolSub(t *testing.T) {
gocmd := testenv.Command(t, testenv.GoToolPath(t), "env", "GOHOSTARCH")
gocmd = testenv.CleanCmdEnv(gocmd)
goHostArchBytes, err := gocmd.CombinedOutput()
if err != nil {
t.Fatalf("%s failed: %v\n%s", gocmd, err, goHostArchBytes)
}
goHostArch := strings.TrimSpace(string(goHostArchBytes))
toolsub = filepath.Join("pkg", "tool", runtime.GOOS+"_"+goHostArch)
}
// linkOrCopy creates a link to src at dst, or if the symlink fails
// (platform doesn't support) then copies src to dst.
func linkOrCopy(t *testing.T, src, dst string) {
err := os.Symlink(src, dst)
if err == nil {
return
}
fi, err := os.Stat(src)
if err != nil {
t.Fatalf("copying %s to %s: %v", src, dst, err)
}
if fi.IsDir() {
if err := os.CopyFS(dst, os.DirFS(src)); err != nil {
t.Fatalf("copying %s to %s: %v", src, dst, err)
}
return
}
srcf, err := os.Open(src)
if err != nil {
t.Fatalf("copying %s to %s: %v", src, dst, err)
}
defer srcf.Close()
perm := os.O_WRONLY | os.O_CREATE | os.O_EXCL
dstf, err := os.OpenFile(dst, perm, 0o777)
if err != nil {
t.Fatalf("copying %s to %s: %v", src, dst, err)
}
_, err = io.Copy(dstf, srcf)
if closeErr := dstf.Close(); err == nil {
err = closeErr
}
if err != nil {
t.Fatalf("copying %s to %s: %v", src, dst, err)
}
}
|