From 0d8aa5737ecdc03b2723a2af35cb7394335e5411 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 25 Jul 2024 17:15:35 +0000 Subject: cmd/internal/script/scriptest: add new apis for tool test use Add top level apis to provide a general-purpose "script test" runner for clients within cmd, e.g. tools such as compile, link, nm, and so on. This patch doesn't add any uses of the new apis, this will happen in follow-on CLs. Updates #68606. Change-Id: Ib7200a75d4dc7dc50897628f1a6269937be15a76 Reviewed-on: https://go-review.googlesource.com/c/go/+/601359 Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/cmd/internal/script/scripttest/setup.go | 105 ++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/cmd/internal/script/scripttest/setup.go (limited to 'src/cmd/internal/script/scripttest/setup.go') diff --git a/src/cmd/internal/script/scripttest/setup.go b/src/cmd/internal/script/scripttest/setup.go new file mode 100644 index 0000000000..d430367c12 --- /dev/null +++ b/src/cmd/internal/script/scripttest/setup.go @@ -0,0 +1,105 @@ +// 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 ( + "io" + "os" + "path/filepath" + "runtime" + "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. + toolsub := filepath.Join("tool", runtime.GOOS+"_"+runtime.GOARCH) + tomake := []string{ + "bin", + "src", + "pkg", + filepath.Join("pkg", "include"), + filepath.Join("pkg", 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, "pkg", 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) { + toolsub := filepath.Join("pkg", "tool", runtime.GOOS+"_"+runtime.GOARCH) + 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) +} + +// 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 + } + 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) + } +} -- cgit v1.3