@@ -347,6 +347,18 @@ func (c *Cmd) Start() error {
347
347
// An ExitError reports an unsuccessful exit by a command.
348
348
type ExitError struct {
349
349
* 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
350
362
}
351
363
352
364
func (e * ExitError ) Error () string {
@@ -392,21 +404,34 @@ func (c *Cmd) Wait() error {
392
404
if err != nil {
393
405
return err
394
406
} else if ! state .Success () {
395
- return & ExitError {state }
407
+ return & ExitError {ProcessState : state }
396
408
}
397
409
398
410
return copyError
399
411
}
400
412
401
413
// 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.
402
416
func (c * Cmd ) Output () ([]byte , error ) {
403
417
if c .Stdout != nil {
404
418
return nil , errors .New ("exec: Stdout already set" )
405
419
}
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
+
408
428
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
410
435
}
411
436
412
437
// CombinedOutput runs the command and returns its combined standard
@@ -514,3 +539,80 @@ func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
514
539
c .closeAfterWait = append (c .closeAfterWait , pr )
515
540
return pr , nil
516
541
}
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