blob: 3fc2b6dd6923971c6a525e128d41aa1505fe2b25 [file] [log] [blame] [edit]
// Copyright 2021 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 common
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"golang.org/x/benchmarks/sweet/common/log"
)
type Go struct {
Tool string
Env *Env
PassOutput bool
}
func SystemGoTool() (*Go, error) {
tool, err := exec.LookPath("go")
if err != nil {
return nil, fmt.Errorf("looking for system Go: %w", err)
}
return &Go{
Tool: tool,
Env: NewEnvFromEnviron().MustSet("GOROOT=" + filepath.Dir(filepath.Dir(tool))),
}, nil
}
func (g *Go) Do(dir string, args ...string) error {
cmd := exec.Command(g.Tool, args...)
if dir != "" {
cmd.Dir = dir
}
cmd.Env = g.Env.Collapse()
if g.PassOutput {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
log.TraceCommand(cmd, false)
if g.PassOutput {
return cmd.Run()
}
// Use cmd.Output to get an ExitError with Stderr populated.
_, err := cmd.Output()
if ee, ok := err.(*exec.ExitError); ok {
// ExitError includes stderr, but doesn't inclue it in Error.
// Create a new error that does display stderr.
return fmt.Errorf("%w. stderr:\n%s", err, ee.Stderr)
}
return err
}
func (g *Go) List(args ...string) ([]byte, error) {
cmd := exec.Command(g.Tool, append([]string{"list"}, args...)...)
cmd.Env = g.Env.Collapse()
log.TraceCommand(cmd, false)
return cmd.Output()
}
func (g *Go) GOROOT() string {
return filepath.Dir(filepath.Dir(g.Tool))
}
func (g *Go) BuildPackage(pkg, out string) error {
if pkg[0] == '/' || pkg[0] == '.' {
return fmt.Errorf("path used as package in go build")
}
return g.Do("", "build", "-o", out, pkg)
}
func (g *Go) Version() (string, error) {
cmd := exec.Command(g.Tool, "version")
cmd.Env = g.Env.Collapse()
log.TraceCommand(cmd, false)
out, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("error running 'go version': %w", err)
}
return string(out), nil
}
func (g *Go) BuildPath(path, out string, args ...string) error {
if path[0] != '/' && path[0] != '.' {
path = "./" + path
}
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("failed to get current working directory: %w", err)
}
defer chdir(cwd)
if err := chdir(path); err != nil {
return fmt.Errorf("failed to enter build directory: %w", err)
}
args = append([]string{"build", "-o", out}, args...)
return g.Do("", args...)
}
func chdir(path string) error {
log.CommandPrintf("cd %s", path)
return os.Chdir(path)
}