@@ -347,6 +347,18 @@ func (c *Cmd) Start() error {
347347// An ExitError reports an unsuccessful exit by a command.
348348type ExitError struct {
349349 * os.ProcessState
350+
351+ // Stderr holds a subset of the standard error output from the
352+ // Cmd.Output method if standard error was not otherwise being
353+ // collected.
354+ //
355+ // If the error output is long, Stderr may contain only a prefix
356+ // and suffix of the output, with the middle replaced with
357+ // text about the number of omitted bytes.
358+ //
359+ // Stderr is provided for debugging, for inclusion in error messages.
360+ // Users with other needs should redirect Cmd.Stderr as needed.
361+ Stderr []byte
350362}
351363
352364func (e * ExitError ) Error () string {
@@ -392,21 +404,34 @@ func (c *Cmd) Wait() error {
392404 if err != nil {
393405 return err
394406 } else if ! state .Success () {
395- return & ExitError {state }
407+ return & ExitError {ProcessState : state }
396408 }
397409
398410 return copyError
399411}
400412
401413// Output runs the command and returns its standard output.
414+ // Any returned error will usually be of type *ExitError.
415+ // If c.Stderr was nil, Output populates ExitError.Stderr.
402416func (c * Cmd ) Output () ([]byte , error ) {
403417 if c .Stdout != nil {
404418 return nil , errors .New ("exec: Stdout already set" )
405419 }
406- var b bytes.Buffer
407- c .Stdout = & b
420+ var stdout bytes.Buffer
421+ c .Stdout = & stdout
422+
423+ captureErr := c .Stderr == nil
424+ if captureErr {
425+ c .Stderr = & prefixSuffixSaver {N : 32 << 10 }
426+ }
427+
408428 err := c .Run ()
409- return b .Bytes (), err
429+ if err != nil && captureErr {
430+ if ee , ok := err .(* ExitError ); ok {
431+ ee .Stderr = c .Stderr .(* prefixSuffixSaver ).Bytes ()
432+ }
433+ }
434+ return stdout .Bytes (), err
410435}
411436
412437// CombinedOutput runs the command and returns its combined standard
@@ -514,3 +539,80 @@ func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
514539 c .closeAfterWait = append (c .closeAfterWait , pr )
515540 return pr , nil
516541}
542+
543+ // prefixSuffixSaver is an io.Writer which retains the first N bytes
544+ // and the last N bytes written to it. The Bytes() methods reconstructs
545+ // it with a pretty error message.
546+ type prefixSuffixSaver struct {
547+ N int // max size of prefix or suffix
548+ prefix []byte
549+ suffix []byte // ring buffer once len(suffix) == N
550+ suffixOff int // offset to write into suffix
551+ skipped int64
552+
553+ // TODO(bradfitz): we could keep one large []byte and use part of it for
554+ // the prefix, reserve space for the '... Omitting N bytes ...' message,
555+ // then the ring buffer suffix, and just rearrange the ring buffer
556+ // suffix when Bytes() is called, but it doesn't seem worth it for
557+ // now just for error messages. It's only ~64KB anyway.
558+ }
559+
560+ func (w * prefixSuffixSaver ) Write (p []byte ) (n int , err error ) {
561+ lenp := len (p )
562+ p = w .fill (& w .prefix , p )
563+
564+ // Only keep the last w.N bytes of suffix data.
565+ if overage := len (p ) - w .N ; overage > 0 {
566+ p = p [overage :]
567+ w .skipped += int64 (overage )
568+ }
569+ p = w .fill (& w .suffix , p )
570+
571+ // w.suffix is full now if p is non-empty. Overwrite it in a circle.
572+ for len (p ) > 0 { // 0, 1, or 2 iterations.
573+ n := copy (w .suffix [w .suffixOff :], p )
574+ p = p [n :]
575+ w .skipped += int64 (n )
576+ w .suffixOff += n
577+ if w .suffixOff == w .N {
578+ w .suffixOff = 0
579+ }
580+ }
581+ return lenp , nil
582+ }
583+
584+ // fill appends up to len(p) bytes of p to *dst, such that *dst does not
585+ // grow larger than w.N. It returns the un-appended suffix of p.
586+ func (w * prefixSuffixSaver ) fill (dst * []byte , p []byte ) (pRemain []byte ) {
587+ if remain := w .N - len (* dst ); remain > 0 {
588+ add := minInt (len (p ), remain )
589+ * dst = append (* dst , p [:add ]... )
590+ p = p [add :]
591+ }
592+ return p
593+ }
594+
595+ func (w * prefixSuffixSaver ) Bytes () []byte {
596+ if w .suffix == nil {
597+ return w .prefix
598+ }
599+ if w .skipped == 0 {
600+ return append (w .prefix , w .suffix ... )
601+ }
602+ var buf bytes.Buffer
603+ buf .Grow (len (w .prefix ) + len (w .suffix ) + 50 )
604+ buf .Write (w .prefix )
605+ buf .WriteString ("\n ... omitting " )
606+ buf .WriteString (strconv .FormatInt (w .skipped , 10 ))
607+ buf .WriteString (" bytes ...\n " )
608+ buf .Write (w .suffix [w .suffixOff :])
609+ buf .Write (w .suffix [:w .suffixOff ])
610+ return buf .Bytes ()
611+ }
612+
613+ func minInt (a , b int ) int {
614+ if a < b {
615+ return a
616+ }
617+ return b
618+ }
0 commit comments