package run

import (
	"fmt"
	"os/exec"

	"github.com/pingcap/errors"
)

// cmd := exec.Command(program, args...)

// CombinedString returns the combined output as a string
// The error is annotated with the program args and output
func CombinedString(cmd *exec.Cmd) (string, error) {
	out, err := cmd.CombinedOutput()

	if err != nil {
		return "", Error{
			Err:    errors.AddStack(err),
			Path:   cmd.Path,
			Args:   cmd.Args,
			Stdout: string(out),
			Stderr: "",
		}
	}
	return string(out), nil
}

// Error is the error returned from this package.
type Error struct {
	Err    error
	Path   string
	Args   []string
	Stdout string
	Stderr string
}

// Cause fulfills the Causer interface
func (re Error) Cause() error { return re.Err }
func (re Error) Error() string {
	return fmt.Sprintf("StdoutBin failed: %s %v: %s\n%s", re.Path, re.Args, re.Stdout, re.Stderr)
}

// StdoutBin returns only the stdout as byte[].
// The concrete error type returned is Error
func StdoutBin(cmd *exec.Cmd) ([]byte, error) {
	out, err := cmd.Output()
	var stderr []byte
	if exErr, ok := err.(*exec.ExitError); ok {
		stderr = exErr.Stderr
	}
	if err != nil {
		return out, Error{
			Err:    errors.AddStack(err),
			Path:   cmd.Path,
			Args:   cmd.Args,
			Stdout: string(out),
			Stderr: string(stderr),
		}
	}
	return out, nil
}
