本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
4.8KB

  1. package packp
  2. import (
  3. "fmt"
  4. "time"
  5. "gopkg.in/src-d/go-git.v4/plumbing"
  6. "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
  7. )
  8. // UploadRequest values represent the information transmitted on a
  9. // upload-request message. Values from this type are not zero-value
  10. // safe, use the New function instead.
  11. // This is a low level type, use UploadPackRequest instead.
  12. type UploadRequest struct {
  13. Capabilities *capability.List
  14. Wants []plumbing.Hash
  15. Shallows []plumbing.Hash
  16. Depth Depth
  17. }
  18. // Depth values stores the desired depth of the requested packfile: see
  19. // DepthCommit, DepthSince and DepthReference.
  20. type Depth interface {
  21. isDepth()
  22. IsZero() bool
  23. }
  24. // DepthCommits values stores the maximum number of requested commits in
  25. // the packfile. Zero means infinite. A negative value will have
  26. // undefined consequences.
  27. type DepthCommits int
  28. func (d DepthCommits) isDepth() {}
  29. func (d DepthCommits) IsZero() bool {
  30. return d == 0
  31. }
  32. // DepthSince values requests only commits newer than the specified time.
  33. type DepthSince time.Time
  34. func (d DepthSince) isDepth() {}
  35. func (d DepthSince) IsZero() bool {
  36. return time.Time(d).IsZero()
  37. }
  38. // DepthReference requests only commits not to found in the specified reference.
  39. type DepthReference string
  40. func (d DepthReference) isDepth() {}
  41. func (d DepthReference) IsZero() bool {
  42. return string(d) == ""
  43. }
  44. // NewUploadRequest returns a pointer to a new UploadRequest value, ready to be
  45. // used. It has no capabilities, wants or shallows and an infinite depth. Please
  46. // note that to encode an upload-request it has to have at least one wanted hash.
  47. func NewUploadRequest() *UploadRequest {
  48. return &UploadRequest{
  49. Capabilities: capability.NewList(),
  50. Wants: []plumbing.Hash{},
  51. Shallows: []plumbing.Hash{},
  52. Depth: DepthCommits(0),
  53. }
  54. }
  55. // NewUploadRequestFromCapabilities returns a pointer to a new UploadRequest
  56. // value, the request capabilities are filled with the most optiomal ones, based
  57. // on the adv value (advertaised capabilities), the UploadRequest generated it
  58. // has no wants or shallows and an infinite depth.
  59. func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest {
  60. r := NewUploadRequest()
  61. if adv.Supports(capability.MultiACKDetailed) {
  62. r.Capabilities.Set(capability.MultiACKDetailed)
  63. } else if adv.Supports(capability.MultiACK) {
  64. r.Capabilities.Set(capability.MultiACK)
  65. }
  66. if adv.Supports(capability.Sideband64k) {
  67. r.Capabilities.Set(capability.Sideband64k)
  68. } else if adv.Supports(capability.Sideband) {
  69. r.Capabilities.Set(capability.Sideband)
  70. }
  71. if adv.Supports(capability.ThinPack) {
  72. r.Capabilities.Set(capability.ThinPack)
  73. }
  74. if adv.Supports(capability.OFSDelta) {
  75. r.Capabilities.Set(capability.OFSDelta)
  76. }
  77. if adv.Supports(capability.Agent) {
  78. r.Capabilities.Set(capability.Agent, capability.DefaultAgent)
  79. }
  80. return r
  81. }
  82. // Validate validates the content of UploadRequest, following the next rules:
  83. // - Wants MUST have at least one reference
  84. // - capability.Shallow MUST be present if Shallows is not empty
  85. // - is a non-zero DepthCommits is given capability.Shallow MUST be present
  86. // - is a DepthSince is given capability.Shallow MUST be present
  87. // - is a DepthReference is given capability.DeepenNot MUST be present
  88. // - MUST contain only maximum of one of capability.Sideband and capability.Sideband64k
  89. // - MUST contain only maximum of one of capability.MultiACK and capability.MultiACKDetailed
  90. func (r *UploadRequest) Validate() error {
  91. if len(r.Wants) == 0 {
  92. return fmt.Errorf("want can't be empty")
  93. }
  94. if err := r.validateRequiredCapabilities(); err != nil {
  95. return err
  96. }
  97. if err := r.validateConflictCapabilities(); err != nil {
  98. return err
  99. }
  100. return nil
  101. }
  102. func (r *UploadRequest) validateRequiredCapabilities() error {
  103. msg := "missing capability %s"
  104. if len(r.Shallows) != 0 && !r.Capabilities.Supports(capability.Shallow) {
  105. return fmt.Errorf(msg, capability.Shallow)
  106. }
  107. switch r.Depth.(type) {
  108. case DepthCommits:
  109. if r.Depth != DepthCommits(0) {
  110. if !r.Capabilities.Supports(capability.Shallow) {
  111. return fmt.Errorf(msg, capability.Shallow)
  112. }
  113. }
  114. case DepthSince:
  115. if !r.Capabilities.Supports(capability.DeepenSince) {
  116. return fmt.Errorf(msg, capability.DeepenSince)
  117. }
  118. case DepthReference:
  119. if !r.Capabilities.Supports(capability.DeepenNot) {
  120. return fmt.Errorf(msg, capability.DeepenNot)
  121. }
  122. }
  123. return nil
  124. }
  125. func (r *UploadRequest) validateConflictCapabilities() error {
  126. msg := "capabilities %s and %s are mutually exclusive"
  127. if r.Capabilities.Supports(capability.Sideband) &&
  128. r.Capabilities.Supports(capability.Sideband64k) {
  129. return fmt.Errorf(msg, capability.Sideband, capability.Sideband64k)
  130. }
  131. if r.Capabilities.Supports(capability.MultiACK) &&
  132. r.Capabilities.Supports(capability.MultiACKDetailed) {
  133. return fmt.Errorf(msg, capability.MultiACK, capability.MultiACKDetailed)
  134. }
  135. return nil
  136. }
上海开阖软件有限公司 沪ICP备12045867号-1