Path: blob/main/vendor/github.com/onsi/gomega/gexec/build.go
2880 views
// untested sections: 512package gexec34import (5"errors"6"fmt"7"go/build"8"os"9"os/exec"10"path"11"path/filepath"12"runtime"13"strings"14"sync"1516"github.com/onsi/gomega/internal/gutil"17)1819var (20mu sync.Mutex21tmpDir string22)2324/*25Build uses go build to compile the package at packagePath. The resulting binary is saved off in a temporary directory.26A path pointing to this binary is returned.2728Build uses the $GOPATH set in your environment. If $GOPATH is not set and you are using Go 1.8+,29it will use the default GOPATH instead. It passes the variadic args on to `go build`.30*/31func Build(packagePath string, args ...string) (compiledPath string, err error) {32return doBuild(build.Default.GOPATH, packagePath, nil, args...)33}3435/*36BuildWithEnvironment is identical to Build but allows you to specify env vars to be set at build time.37*/38func BuildWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {39return doBuild(build.Default.GOPATH, packagePath, env, args...)40}4142/*43BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).44*/45func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {46return doBuild(gopath, packagePath, nil, args...)47}4849func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) {50executable, err := newExecutablePath(gopath, packagePath)51if err != nil {52return "", err53}5455cmdArgs := append([]string{"build"}, args...)56cmdArgs = append(cmdArgs, "-o", executable, packagePath)5758build := exec.Command("go", cmdArgs...)59build.Env = replaceGoPath(os.Environ(), gopath)60build.Env = append(build.Env, env...)6162output, err := build.CombinedOutput()63if err != nil {64return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))65}6667return executable, nil68}6970/*71CompileTest uses go test to compile the test package at packagePath. The resulting binary is saved off in a temporary directory.72A path pointing to this binary is returned.7374CompileTest uses the $GOPATH set in your environment. If $GOPATH is not set and you are using Go 1.8+,75it will use the default GOPATH instead. It passes the variadic args on to `go test`.7677Deprecated: CompileTest makes GOPATH assumptions that don't translate well to the go modules world.78*/79func CompileTest(packagePath string, args ...string) (compiledPath string, err error) {80return doCompileTest(build.Default.GOPATH, packagePath, nil, args...)81}8283/*84GetAndCompileTest is identical to CompileTest but `go get` the package before compiling tests.8586Deprecated: GetAndCompileTest makes GOPATH assumptions that don't translate well to the go modules world.87*/88func GetAndCompileTest(packagePath string, args ...string) (compiledPath string, err error) {89if err := getForTest(build.Default.GOPATH, packagePath, []string{"GO111MODULE=off"}); err != nil {90return "", err91}9293return doCompileTest(build.Default.GOPATH, packagePath, []string{"GO111MODULE=off"}, args...)94}9596/*97CompileTestWithEnvironment is identical to CompileTest but allows you to specify env vars to be set at build time.9899Deprecated: CompileTestWithEnvironment makes GOPATH assumptions that don't translate well to the go modules world.100*/101func CompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {102return doCompileTest(build.Default.GOPATH, packagePath, env, args...)103}104105/*106GetAndCompileTestWithEnvironment is identical to GetAndCompileTest but allows you to specify env vars to be set at build time.107108Deprecated: GetAndCompileTestWithEnvironment makes GOPATH assumptions that don't translate well to the go modules world.109*/110func GetAndCompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {111if err := getForTest(build.Default.GOPATH, packagePath, append(env, "GO111MODULE=off")); err != nil {112return "", err113}114115return doCompileTest(build.Default.GOPATH, packagePath, append(env, "GO111MODULE=off"), args...)116}117118/*119CompileTestIn is identical to CompileTest but allows you to specify a custom $GOPATH (the first argument).120121Deprecated: CompileTestIn makes GOPATH assumptions that don't translate well to the go modules world.122*/123func CompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {124return doCompileTest(gopath, packagePath, nil, args...)125}126127/*128GetAndCompileTestIn is identical to GetAndCompileTest but allows you to specify a custom $GOPATH (the first argument).129*/130func GetAndCompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {131if err := getForTest(gopath, packagePath, []string{"GO111MODULE=off"}); err != nil {132return "", err133}134135return doCompileTest(gopath, packagePath, []string{"GO111MODULE=off"}, args...)136}137138func isLocalPackage(packagePath string) bool {139return strings.HasPrefix(packagePath, ".")140}141142func getForTest(gopath, packagePath string, env []string) error {143if isLocalPackage(packagePath) {144return nil145}146147return doGet(gopath, packagePath, env, "-t")148}149150func doGet(gopath, packagePath string, env []string, args ...string) error {151args = append(args, packagePath)152args = append([]string{"get"}, args...)153154goGet := exec.Command("go", args...)155goGet.Dir = gopath156goGet.Env = replaceGoPath(os.Environ(), gopath)157goGet.Env = append(goGet.Env, env...)158159output, err := goGet.CombinedOutput()160if err != nil {161return fmt.Errorf("Failed to get %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))162}163164return nil165}166167func doCompileTest(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) {168executable, err := newExecutablePath(gopath, packagePath, ".test")169if err != nil {170return "", err171}172173cmdArgs := append([]string{"test", "-c"}, args...)174cmdArgs = append(cmdArgs, "-o", executable, packagePath)175176build := exec.Command("go", cmdArgs...)177build.Env = replaceGoPath(os.Environ(), gopath)178build.Env = append(build.Env, env...)179180output, err := build.CombinedOutput()181if err != nil {182return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))183}184185return executable, nil186}187188func replaceGoPath(environ []string, newGoPath string) []string {189newEnviron := []string{}190for _, v := range environ {191if !strings.HasPrefix(v, "GOPATH=") {192newEnviron = append(newEnviron, v)193}194}195return append(newEnviron, "GOPATH="+newGoPath)196}197198func newExecutablePath(gopath, packagePath string, suffixes ...string) (string, error) {199tmpDir, err := temporaryDirectory()200if err != nil {201return "", err202}203204if len(gopath) == 0 {205return "", errors.New("$GOPATH not provided when building " + packagePath)206}207208executable := filepath.Join(tmpDir, path.Base(packagePath))209210if runtime.GOOS == "windows" {211executable += ".exe"212}213214return executable, nil215}216217/*218You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by219gexec. In Ginkgo this is typically done in an AfterSuite callback.220*/221func CleanupBuildArtifacts() {222mu.Lock()223defer mu.Unlock()224if tmpDir != "" {225os.RemoveAll(tmpDir)226tmpDir = ""227}228}229230func temporaryDirectory() (string, error) {231var err error232mu.Lock()233defer mu.Unlock()234if tmpDir == "" {235tmpDir, err = gutil.MkdirTemp("", "gexec_artifacts")236if err != nil {237return "", err238}239}240241return gutil.MkdirTemp(tmpDir, "g")242}243244245