Source file src/cmd/internal/script/scripttest/setup.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package scripttest adapts the script engine for use in tests.
     6  package scripttest
     7  
     8  import (
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"testing"
    14  )
    15  
    16  // SetupTestGoRoot sets up a temporary GOROOT for use with script test
    17  // execution. It copies the existing goroot bin and pkg dirs using
    18  // symlinks (if possible) or raw copying. Return value is the path to
    19  // the newly created testgoroot dir.
    20  func SetupTestGoRoot(t *testing.T, tmpdir string, goroot string) string {
    21  	mustMkdir := func(path string) {
    22  		if err := os.MkdirAll(path, 0777); err != nil {
    23  			t.Fatalf("SetupTestGoRoot mkdir %s failed: %v", path, err)
    24  		}
    25  	}
    26  
    27  	replicateDir := func(srcdir, dstdir string) {
    28  		files, err := os.ReadDir(srcdir)
    29  		if err != nil {
    30  			t.Fatalf("inspecting %s: %v", srcdir, err)
    31  		}
    32  		for _, file := range files {
    33  			fn := file.Name()
    34  			linkOrCopy(t, filepath.Join(srcdir, fn), filepath.Join(dstdir, fn))
    35  		}
    36  	}
    37  
    38  	// Create various dirs in testgoroot.
    39  	toolsub := filepath.Join("tool", runtime.GOOS+"_"+runtime.GOARCH)
    40  	tomake := []string{
    41  		"bin",
    42  		"src",
    43  		"pkg",
    44  		filepath.Join("pkg", "include"),
    45  		filepath.Join("pkg", toolsub),
    46  	}
    47  	made := []string{}
    48  	tgr := filepath.Join(tmpdir, "testgoroot")
    49  	mustMkdir(tgr)
    50  	for _, targ := range tomake {
    51  		path := filepath.Join(tgr, targ)
    52  		mustMkdir(path)
    53  		made = append(made, path)
    54  	}
    55  
    56  	// Replicate selected portions of the content.
    57  	replicateDir(filepath.Join(goroot, "bin"), made[0])
    58  	replicateDir(filepath.Join(goroot, "src"), made[1])
    59  	replicateDir(filepath.Join(goroot, "pkg", "include"), made[3])
    60  	replicateDir(filepath.Join(goroot, "pkg", toolsub), made[4])
    61  
    62  	return tgr
    63  }
    64  
    65  // ReplaceGoToolInTestGoRoot replaces the go tool binary toolname with
    66  // an alternate executable newtoolpath within a test GOROOT directory
    67  // previously created by SetupTestGoRoot.
    68  func ReplaceGoToolInTestGoRoot(t *testing.T, testgoroot, toolname, newtoolpath string) {
    69  	toolsub := filepath.Join("pkg", "tool", runtime.GOOS+"_"+runtime.GOARCH)
    70  	exename := toolname
    71  	if runtime.GOOS == "windows" {
    72  		exename += ".exe"
    73  	}
    74  	toolpath := filepath.Join(testgoroot, toolsub, exename)
    75  	if err := os.Remove(toolpath); err != nil {
    76  		t.Fatalf("removing %s: %v", toolpath, err)
    77  	}
    78  	linkOrCopy(t, newtoolpath, toolpath)
    79  }
    80  
    81  // linkOrCopy creates a link to src at dst, or if the symlink fails
    82  // (platform doesn't support) then copies src to dst.
    83  func linkOrCopy(t *testing.T, src, dst string) {
    84  	err := os.Symlink(src, dst)
    85  	if err == nil {
    86  		return
    87  	}
    88  	srcf, err := os.Open(src)
    89  	if err != nil {
    90  		t.Fatalf("copying %s to %s: %v", src, dst, err)
    91  	}
    92  	defer srcf.Close()
    93  	perm := os.O_WRONLY | os.O_CREATE | os.O_EXCL
    94  	dstf, err := os.OpenFile(dst, perm, 0o777)
    95  	if err != nil {
    96  		t.Fatalf("copying %s to %s: %v", src, dst, err)
    97  	}
    98  	_, err = io.Copy(dstf, srcf)
    99  	if closeErr := dstf.Close(); err == nil {
   100  		err = closeErr
   101  	}
   102  	if err != nil {
   103  		t.Fatalf("copying %s to %s: %v", src, dst, err)
   104  	}
   105  }
   106  

View as plain text