github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/errors/clean_up.go (about)

     1  package errors
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  )
     7  
     8  // CleanUp is defer-able syntactic sugar that calls f and reports an error, if any,
     9  // to *err. Pass the caller's named return error. Example usage:
    10  //
    11  //   func processFile(filename string) (_ int, err error) {
    12  //     f, err := os.Open(filename)
    13  //     if err != nil { ... }
    14  //     defer errors.CleanUp(f.Close, &err)
    15  //     ...
    16  //   }
    17  //
    18  // If the caller returns with its own error, any error from cleanUp will be chained.
    19  func CleanUp(cleanUp func() error, dst *error) {
    20  	addErr(cleanUp(), dst)
    21  }
    22  
    23  // CleanUpCtx is CleanUp for a context-ful cleanUp.
    24  func CleanUpCtx(ctx context.Context, cleanUp func(context.Context) error, dst *error) {
    25  	addErr(cleanUp(ctx), dst)
    26  }
    27  
    28  func addErr(err2 error, dst *error) {
    29  	if err2 == nil {
    30  		return
    31  	}
    32  	if *dst == nil {
    33  		*dst = err2
    34  		return
    35  	}
    36  	// Note: We don't chain err2 as *dst's cause because *dst may already have a meaningful cause.
    37  	// Also, even if *dst didn't, err2 may be something entirely different, and suggesting it's
    38  	// the cause could be misleading.
    39  	// TODO: Consider using a standardized multiple-errors representation like sync/multierror's.
    40  	*dst = E(*dst, fmt.Sprintf("second error in Close: %v", err2))
    41  }