github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/client/status.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"google.golang.org/grpc/status"
     8  	"google.golang.org/protobuf/encoding/prototext"
     9  	"google.golang.org/protobuf/proto"
    10  
    11  	_ "google.golang.org/genproto/googleapis/rpc/errdetails" // the proto needs to be compiled in for unmarshalling of status details.
    12  )
    13  
    14  // StatusError is the same as status.Error except it includes the error details in the error message.
    15  type StatusError struct {
    16  	st      *status.Status
    17  	details string
    18  }
    19  
    20  // StatusDetailedError creates a StatusError from Status, which is the same as st.Err() except it includes the error details in the error message.
    21  func StatusDetailedError(st *status.Status) *StatusError {
    22  	var details []string
    23  	for _, d := range st.Details() {
    24  		s := fmt.Sprintf("%+v", d)
    25  		if pb, ok := d.(proto.Message); ok {
    26  			s = prototext.Format(pb)
    27  		}
    28  		details = append(details, s)
    29  	}
    30  	return &StatusError{st, strings.Join(details, "; ")}
    31  }
    32  
    33  func (e *StatusError) Error() string {
    34  	msg := fmt.Sprintf("rpc error: code = %s desc = %s", e.st.Code(), e.st.Message())
    35  	if e.details != "" {
    36  		msg += " details = " + e.details
    37  	}
    38  	return msg
    39  }
    40  
    41  // GRPCStatus returns the Status represented by e.
    42  func (e *StatusError) GRPCStatus() *status.Status {
    43  	return e.st
    44  }
    45  
    46  // Is implements error.Is functionality.
    47  // A StatusError is equivalent if the code and message are identical.
    48  func (e *StatusError) Is(target error) bool {
    49  	if tse, ok := target.(*StatusError); ok {
    50  		return proto.Equal(e.st.Proto(), tse.st.Proto())
    51  	}
    52  	if tst, ok := status.FromError(target); ok {
    53  		return proto.Equal(e.st.Proto(), tst.Proto())
    54  	}
    55  	return false
    56  }