errors.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package v2
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // ErrorCode represents the error type. The errors are serialized via strings
  7. // and the integer format may change and should *never* be exported.
  8. type ErrorCode int
  9. const (
  10. // ErrorCodeUnknown is a catch-all for errors not defined below.
  11. ErrorCodeUnknown ErrorCode = iota
  12. // ErrorCodeDigestInvalid is returned when uploading a blob if the
  13. // provided digest does not match the blob contents.
  14. ErrorCodeDigestInvalid
  15. // ErrorCodeSizeInvalid is returned when uploading a blob if the provided
  16. // size does not match the content length.
  17. ErrorCodeSizeInvalid
  18. // ErrorCodeNameInvalid is returned when the name in the manifest does not
  19. // match the provided name.
  20. ErrorCodeNameInvalid
  21. // ErrorCodeTagInvalid is returned when the tag in the manifest does not
  22. // match the provided tag.
  23. ErrorCodeTagInvalid
  24. // ErrorCodeNameUnknown when the repository name is not known.
  25. ErrorCodeNameUnknown
  26. // ErrorCodeManifestUnknown returned when image manifest is unknown.
  27. ErrorCodeManifestUnknown
  28. // ErrorCodeManifestInvalid returned when an image manifest is invalid,
  29. // typically during a PUT operation. This error encompasses all errors
  30. // encountered during manifest validation that aren't signature errors.
  31. ErrorCodeManifestInvalid
  32. // ErrorCodeManifestUnverified is returned when the manifest fails
  33. // signature verfication.
  34. ErrorCodeManifestUnverified
  35. // ErrorCodeBlobUnknown is returned when a blob is unknown to the
  36. // registry. This can happen when the manifest references a nonexistent
  37. // layer or the result is not found by a blob fetch.
  38. ErrorCodeBlobUnknown
  39. // ErrorCodeBlobUploadUnknown is returned when an upload is unknown.
  40. ErrorCodeBlobUploadUnknown
  41. )
  42. // ParseErrorCode attempts to parse the error code string, returning
  43. // ErrorCodeUnknown if the error is not known.
  44. func ParseErrorCode(s string) ErrorCode {
  45. desc, ok := idToDescriptors[s]
  46. if !ok {
  47. return ErrorCodeUnknown
  48. }
  49. return desc.Code
  50. }
  51. // Descriptor returns the descriptor for the error code.
  52. func (ec ErrorCode) Descriptor() ErrorDescriptor {
  53. d, ok := errorCodeToDescriptors[ec]
  54. if !ok {
  55. return ErrorCodeUnknown.Descriptor()
  56. }
  57. return d
  58. }
  59. // String returns the canonical identifier for this error code.
  60. func (ec ErrorCode) String() string {
  61. return ec.Descriptor().Value
  62. }
  63. // Message returned the human-readable error message for this error code.
  64. func (ec ErrorCode) Message() string {
  65. return ec.Descriptor().Message
  66. }
  67. // MarshalText encodes the receiver into UTF-8-encoded text and returns the
  68. // result.
  69. func (ec ErrorCode) MarshalText() (text []byte, err error) {
  70. return []byte(ec.String()), nil
  71. }
  72. // UnmarshalText decodes the form generated by MarshalText.
  73. func (ec *ErrorCode) UnmarshalText(text []byte) error {
  74. desc, ok := idToDescriptors[string(text)]
  75. if !ok {
  76. desc = ErrorCodeUnknown.Descriptor()
  77. }
  78. *ec = desc.Code
  79. return nil
  80. }
  81. // Error provides a wrapper around ErrorCode with extra Details provided.
  82. type Error struct {
  83. Code ErrorCode `json:"code"`
  84. Message string `json:"message,omitempty"`
  85. Detail interface{} `json:"detail,omitempty"`
  86. }
  87. // Error returns a human readable representation of the error.
  88. func (e Error) Error() string {
  89. return fmt.Sprintf("%s: %s",
  90. strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
  91. e.Message)
  92. }
  93. // Errors provides the envelope for multiple errors and a few sugar methods
  94. // for use within the application.
  95. type Errors struct {
  96. Errors []Error `json:"errors,omitempty"`
  97. }
  98. // Push pushes an error on to the error stack, with the optional detail
  99. // argument. It is a programming error (ie panic) to push more than one
  100. // detail at a time.
  101. func (errs *Errors) Push(code ErrorCode, details ...interface{}) {
  102. if len(details) > 1 {
  103. panic("please specify zero or one detail items for this error")
  104. }
  105. var detail interface{}
  106. if len(details) > 0 {
  107. detail = details[0]
  108. }
  109. if err, ok := detail.(error); ok {
  110. detail = err.Error()
  111. }
  112. errs.PushErr(Error{
  113. Code: code,
  114. Message: code.Message(),
  115. Detail: detail,
  116. })
  117. }
  118. // PushErr pushes an error interface onto the error stack.
  119. func (errs *Errors) PushErr(err error) {
  120. switch err.(type) {
  121. case Error:
  122. errs.Errors = append(errs.Errors, err.(Error))
  123. default:
  124. errs.Errors = append(errs.Errors, Error{Message: err.Error()})
  125. }
  126. }
  127. func (errs *Errors) Error() string {
  128. switch errs.Len() {
  129. case 0:
  130. return "<nil>"
  131. case 1:
  132. return errs.Errors[0].Error()
  133. default:
  134. msg := "errors:\n"
  135. for _, err := range errs.Errors {
  136. msg += err.Error() + "\n"
  137. }
  138. return msg
  139. }
  140. }
  141. // Clear clears the errors.
  142. func (errs *Errors) Clear() {
  143. errs.Errors = errs.Errors[:0]
  144. }
  145. // Len returns the current number of errors.
  146. func (errs *Errors) Len() int {
  147. return len(errs.Errors)
  148. }