Kurt Peek
Kurt Peek

Reputation: 57471

Understanding Go's exec.Output() function

I was reading the source code for the Output() method of the Cmd type in Go's exec module (https://golang.org/pkg/os/exec/#Cmd.Output):

// Output runs the command and returns its standard output.
// Any returned error will usually be of type *ExitError.
// If c.Stderr was nil, Output populates ExitError.Stderr.
func (c *Cmd) Output() ([]byte, error) {
    if c.Stdout != nil {
        return nil, errors.New("exec: Stdout already set")
    }
    var stdout bytes.Buffer
    c.Stdout = &stdout

    captureErr := c.Stderr == nil
    if captureErr {
        c.Stderr = &prefixSuffixSaver{N: 32 << 10}
    }

    err := c.Run()
    if err != nil && captureErr {
        if ee, ok := err.(*ExitError); ok {
            ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
        }
    }
    return stdout.Bytes(), err
}

I'm struggling a bit to understand this part:

    if ee, ok := err.(*ExitError); ok {
        ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
    }

As I understand it, the ee pointer will no longer be in scope at the end of the if block, and since the body of the if block is just setting the Stderr field of this instance, the only way this could be useful is through a side effect (like actually writing the prettified error). I don't immediately grasp how this is happening, though.

What does this bit of code do, essentially?

Upvotes: 0

Views: 595

Answers (1)

Burak Serdar
Burak Serdar

Reputation: 51587

if ee, ok := err.(*ExitError); ok {

If err is of type *ExitError, then ee will be a pointer to the ExitError stored in err. So, even though ee will go out of scope, the *ExitError will still be there, pointed to by err, and any changes made to it will stick.

Upvotes: 3

Related Questions