github.com/haraldrudell/parl@v0.4.176/pio/copy-thread.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pio
     7  
     8  import (
     9  	"context"
    10  	"errors"
    11  	"io"
    12  	"io/fs"
    13  
    14  	"github.com/haraldrudell/parl"
    15  	"github.com/haraldrudell/parl/perrors"
    16  	"github.com/haraldrudell/parl/pruntime"
    17  )
    18  
    19  var cx pruntime.CachedLocation
    20  
    21  // CopyThread copies from an io.Reader to an io.Writer.
    22  //   - label is used for thread identification on panics
    23  //   - errCh receives result and makes thread awaitable
    24  //   - if ctx, a CancelContext, is non-nil and error occurs, ctx is cancelled
    25  //   - CopyThread itself never fails
    26  func CopyThread(
    27  	label string, reader io.Reader, writer io.Writer,
    28  	errCh chan<- error, ctx context.Context,
    29  ) {
    30  	var err error
    31  	defer func() { errCh <- err }()
    32  	if ctx != nil {
    33  		defer parl.CancelOnError(&err, ctx) // cancel the command if copyThread fails
    34  	}
    35  	defer parl.RecoverAnnotation("copy command i/o "+label, &err, parl.NoOnError)
    36  
    37  	if _, err = io.Copy(writer, reader); perrors.Is(&err, "%s %s %w", label, cx.PackFunc(), err) {
    38  
    39  		// if the process terminates quickly, exec.Command might have already closed
    40  		// stdout stderr before the copyThread is scheduled to start
    41  		if errors.Is(err, fs.ErrClosed) {
    42  			err = nil // ignore quickly closed errors
    43  		}
    44  
    45  		return
    46  	}
    47  }