| package v2 |
| |
| import ( |
| "fmt" |
| "strings" |
| ) |
| |
| // ErrorCode represents the error type. The errors are serialized via strings |
| // and the integer format may change and should *never* be exported. |
| type ErrorCode int |
| |
| const ( |
| // ErrorCodeUnknown is a catch-all for errors not defined below. |
| ErrorCodeUnknown ErrorCode = iota |
| |
| // ErrorCodeDigestInvalid is returned when uploading a blob if the |
| // provided digest does not match the blob contents. |
| ErrorCodeDigestInvalid |
| |
| // ErrorCodeSizeInvalid is returned when uploading a blob if the provided |
| // size does not match the content length. |
| ErrorCodeSizeInvalid |
| |
| // ErrorCodeNameInvalid is returned when the name in the manifest does not |
| // match the provided name. |
| ErrorCodeNameInvalid |
| |
| // ErrorCodeTagInvalid is returned when the tag in the manifest does not |
| // match the provided tag. |
| ErrorCodeTagInvalid |
| |
| // ErrorCodeNameUnknown when the repository name is not known. |
| ErrorCodeNameUnknown |
| |
| // ErrorCodeManifestUnknown returned when image manifest is unknown. |
| ErrorCodeManifestUnknown |
| |
| // ErrorCodeManifestInvalid returned when an image manifest is invalid, |
| // typically during a PUT operation. This error encompasses all errors |
| // encountered during manifest validation that aren't signature errors. |
| ErrorCodeManifestInvalid |
| |
| // ErrorCodeManifestUnverified is returned when the manifest fails |
| // signature verfication. |
| ErrorCodeManifestUnverified |
| |
| // ErrorCodeBlobUnknown is returned when a blob is unknown to the |
| // registry. This can happen when the manifest references a nonexistent |
| // layer or the result is not found by a blob fetch. |
| ErrorCodeBlobUnknown |
| |
| // ErrorCodeBlobUploadUnknown is returned when an upload is unknown. |
| ErrorCodeBlobUploadUnknown |
| ) |
| |
| // ParseErrorCode attempts to parse the error code string, returning |
| // ErrorCodeUnknown if the error is not known. |
| func ParseErrorCode(s string) ErrorCode { |
| desc, ok := idToDescriptors[s] |
| |
| if !ok { |
| return ErrorCodeUnknown |
| } |
| |
| return desc.Code |
| } |
| |
| // Descriptor returns the descriptor for the error code. |
| func (ec ErrorCode) Descriptor() ErrorDescriptor { |
| d, ok := errorCodeToDescriptors[ec] |
| |
| if !ok { |
| return ErrorCodeUnknown.Descriptor() |
| } |
| |
| return d |
| } |
| |
| // String returns the canonical identifier for this error code. |
| func (ec ErrorCode) String() string { |
| return ec.Descriptor().Value |
| } |
| |
| // Message returned the human-readable error message for this error code. |
| func (ec ErrorCode) Message() string { |
| return ec.Descriptor().Message |
| } |
| |
| // MarshalText encodes the receiver into UTF-8-encoded text and returns the |
| // result. |
| func (ec ErrorCode) MarshalText() (text []byte, err error) { |
| return []byte(ec.String()), nil |
| } |
| |
| // UnmarshalText decodes the form generated by MarshalText. |
| func (ec *ErrorCode) UnmarshalText(text []byte) error { |
| desc, ok := idToDescriptors[string(text)] |
| |
| if !ok { |
| desc = ErrorCodeUnknown.Descriptor() |
| } |
| |
| *ec = desc.Code |
| |
| return nil |
| } |
| |
| // Error provides a wrapper around ErrorCode with extra Details provided. |
| type Error struct { |
| Code ErrorCode `json:"code"` |
| Message string `json:"message,omitempty"` |
| Detail interface{} `json:"detail,omitempty"` |
| } |
| |
| // Error returns a human readable representation of the error. |
| func (e Error) Error() string { |
| return fmt.Sprintf("%s: %s", |
| strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)), |
| e.Message) |
| } |
| |
| // Errors provides the envelope for multiple errors and a few sugar methods |
| // for use within the application. |
| type Errors struct { |
| Errors []Error `json:"errors,omitempty"` |
| } |
| |
| // Push pushes an error on to the error stack, with the optional detail |
| // argument. It is a programming error (ie panic) to push more than one |
| // detail at a time. |
| func (errs *Errors) Push(code ErrorCode, details ...interface{}) { |
| if len(details) > 1 { |
| panic("please specify zero or one detail items for this error") |
| } |
| |
| var detail interface{} |
| if len(details) > 0 { |
| detail = details[0] |
| } |
| |
| if err, ok := detail.(error); ok { |
| detail = err.Error() |
| } |
| |
| errs.PushErr(Error{ |
| Code: code, |
| Message: code.Message(), |
| Detail: detail, |
| }) |
| } |
| |
| // PushErr pushes an error interface onto the error stack. |
| func (errs *Errors) PushErr(err error) { |
| switch err.(type) { |
| case Error: |
| errs.Errors = append(errs.Errors, err.(Error)) |
| default: |
| errs.Errors = append(errs.Errors, Error{Message: err.Error()}) |
| } |
| } |
| |
| func (errs *Errors) Error() string { |
| switch errs.Len() { |
| case 0: |
| return "<nil>" |
| case 1: |
| return errs.Errors[0].Error() |
| default: |
| msg := "errors:\n" |
| for _, err := range errs.Errors { |
| msg += err.Error() + "\n" |
| } |
| return msg |
| } |
| } |
| |
| // Clear clears the errors. |
| func (errs *Errors) Clear() { |
| errs.Errors = errs.Errors[:0] |
| } |
| |
| // Len returns the current number of errors. |
| func (errs *Errors) Len() int { |
| return len(errs.Errors) |
| } |