databricks-cli/lib/spawn/exec.go

82 lines
1.5 KiB
Go

package spawn
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"os/exec"
"runtime"
"strings"
)
type cxtKey int
const (
prjRoot cxtKey = iota
)
func WithRoot(ctx context.Context, root string) context.Context {
return context.WithValue(ctx, prjRoot, root)
}
func ExecAndPassErr(ctx context.Context, name string, args ...string) ([]byte, error) {
log.Printf("[DEBUG] Running %s %s", name, strings.Join(args, " "))
reader, writer := io.Pipe()
out := bytes.NewBuffer([]byte{}) // add option to route to Stdout in verbose mode
go io.Copy(out, reader)
cmd := exec.CommandContext(ctx, name, args...)
cmd.Stdout = writer
cmd.Stderr = writer
root, ok := ctx.Value(prjRoot).(string)
if ok {
cmd.Dir = root
}
err := cmd.Run()
_ = writer.Close()
_ = reader.Close()
if err != nil {
return nil, fmt.Errorf(trimmedS(out.Bytes()))
}
return []byte(trimmedS(out.Bytes())), nil
}
func DetectExecutable(ctx context.Context, exec string) (string, error) {
detector := "which"
if runtime.GOOS == "windows" {
detector = "where.exe"
}
out, err := ExecAndPassErr(ctx, detector, exec)
if err != nil {
return "", err
}
return trimmedS(out), nil
}
func nicerErr(err error) error {
if err == nil {
return nil
}
if ee, ok := err.(*exec.ExitError); ok {
errMsg := trimmedS(ee.Stderr)
if errMsg == "" {
errMsg = err.Error()
}
return errors.New(errMsg)
}
return err
}
func trimmedS(bytes []byte) string {
return strings.Trim(string(bytes), "\n\r")
}