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.

advrefs.go 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package packp
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "github.com/go-git/go-git/v5/plumbing"
  7. "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
  8. "github.com/go-git/go-git/v5/plumbing/storer"
  9. "github.com/go-git/go-git/v5/storage/memory"
  10. )
  11. // AdvRefs values represent the information transmitted on an
  12. // advertised-refs message. Values from this type are not zero-value
  13. // safe, use the New function instead.
  14. type AdvRefs struct {
  15. // Prefix stores prefix payloads.
  16. //
  17. // When using this message over (smart) HTTP, you have to add a pktline
  18. // before the whole thing with the following payload:
  19. //
  20. // '# service=$servicename" LF
  21. //
  22. // Moreover, some (all) git HTTP smart servers will send a flush-pkt
  23. // just after the first pkt-line.
  24. //
  25. // To accommodate both situations, the Prefix field allow you to store
  26. // any data you want to send before the actual pktlines. It will also
  27. // be filled up with whatever is found on the line.
  28. Prefix [][]byte
  29. // Head stores the resolved HEAD reference if present.
  30. // This can be present with git-upload-pack, not with git-receive-pack.
  31. Head *plumbing.Hash
  32. // Capabilities are the capabilities.
  33. Capabilities *capability.List
  34. // References are the hash references.
  35. References map[string]plumbing.Hash
  36. // Peeled are the peeled hash references.
  37. Peeled map[string]plumbing.Hash
  38. // Shallows are the shallow object ids.
  39. Shallows []plumbing.Hash
  40. }
  41. // NewAdvRefs returns a pointer to a new AdvRefs value, ready to be used.
  42. func NewAdvRefs() *AdvRefs {
  43. return &AdvRefs{
  44. Prefix: [][]byte{},
  45. Capabilities: capability.NewList(),
  46. References: make(map[string]plumbing.Hash),
  47. Peeled: make(map[string]plumbing.Hash),
  48. Shallows: []plumbing.Hash{},
  49. }
  50. }
  51. func (a *AdvRefs) AddReference(r *plumbing.Reference) error {
  52. switch r.Type() {
  53. case plumbing.SymbolicReference:
  54. v := fmt.Sprintf("%s:%s", r.Name().String(), r.Target().String())
  55. a.Capabilities.Add(capability.SymRef, v)
  56. case plumbing.HashReference:
  57. a.References[r.Name().String()] = r.Hash()
  58. default:
  59. return plumbing.ErrInvalidType
  60. }
  61. return nil
  62. }
  63. func (a *AdvRefs) AllReferences() (memory.ReferenceStorage, error) {
  64. s := memory.ReferenceStorage{}
  65. if err := a.addRefs(s); err != nil {
  66. return s, plumbing.NewUnexpectedError(err)
  67. }
  68. return s, nil
  69. }
  70. func (a *AdvRefs) addRefs(s storer.ReferenceStorer) error {
  71. for name, hash := range a.References {
  72. ref := plumbing.NewReferenceFromStrings(name, hash.String())
  73. if err := s.SetReference(ref); err != nil {
  74. return err
  75. }
  76. }
  77. if a.supportSymrefs() {
  78. return a.addSymbolicRefs(s)
  79. }
  80. return a.resolveHead(s)
  81. }
  82. // If the server does not support symrefs capability,
  83. // we need to guess the reference where HEAD is pointing to.
  84. //
  85. // Git versions prior to 1.8.4.3 has an special procedure to get
  86. // the reference where is pointing to HEAD:
  87. // - Check if a reference called master exists. If exists and it
  88. // has the same hash as HEAD hash, we can say that HEAD is pointing to master
  89. // - If master does not exists or does not have the same hash as HEAD,
  90. // order references and check in that order if that reference has the same
  91. // hash than HEAD. If yes, set HEAD pointing to that branch hash
  92. // - If no reference is found, throw an error
  93. func (a *AdvRefs) resolveHead(s storer.ReferenceStorer) error {
  94. if a.Head == nil {
  95. return nil
  96. }
  97. ref, err := s.Reference(plumbing.Master)
  98. // check first if HEAD is pointing to master
  99. if err == nil {
  100. ok, err := a.createHeadIfCorrectReference(ref, s)
  101. if err != nil {
  102. return err
  103. }
  104. if ok {
  105. return nil
  106. }
  107. }
  108. if err != nil && err != plumbing.ErrReferenceNotFound {
  109. return err
  110. }
  111. // From here we are trying to guess the branch that HEAD is pointing
  112. refIter, err := s.IterReferences()
  113. if err != nil {
  114. return err
  115. }
  116. var refNames []string
  117. err = refIter.ForEach(func(r *plumbing.Reference) error {
  118. refNames = append(refNames, string(r.Name()))
  119. return nil
  120. })
  121. if err != nil {
  122. return err
  123. }
  124. sort.Strings(refNames)
  125. var headSet bool
  126. for _, refName := range refNames {
  127. ref, err := s.Reference(plumbing.ReferenceName(refName))
  128. if err != nil {
  129. return err
  130. }
  131. ok, err := a.createHeadIfCorrectReference(ref, s)
  132. if err != nil {
  133. return err
  134. }
  135. if ok {
  136. headSet = true
  137. break
  138. }
  139. }
  140. if !headSet {
  141. return plumbing.ErrReferenceNotFound
  142. }
  143. return nil
  144. }
  145. func (a *AdvRefs) createHeadIfCorrectReference(
  146. reference *plumbing.Reference,
  147. s storer.ReferenceStorer) (bool, error) {
  148. if reference.Hash() == *a.Head {
  149. headRef := plumbing.NewSymbolicReference(plumbing.HEAD, reference.Name())
  150. if err := s.SetReference(headRef); err != nil {
  151. return false, err
  152. }
  153. return true, nil
  154. }
  155. return false, nil
  156. }
  157. func (a *AdvRefs) addSymbolicRefs(s storer.ReferenceStorer) error {
  158. for _, symref := range a.Capabilities.Get(capability.SymRef) {
  159. chunks := strings.Split(symref, ":")
  160. if len(chunks) != 2 {
  161. err := fmt.Errorf("bad number of `:` in symref value (%q)", symref)
  162. return plumbing.NewUnexpectedError(err)
  163. }
  164. name := plumbing.ReferenceName(chunks[0])
  165. target := plumbing.ReferenceName(chunks[1])
  166. ref := plumbing.NewSymbolicReference(name, target)
  167. if err := s.SetReference(ref); err != nil {
  168. return nil
  169. }
  170. }
  171. return nil
  172. }
  173. func (a *AdvRefs) supportSymrefs() bool {
  174. return a.Capabilities.Supports(capability.SymRef)
  175. }
  176. // IsEmpty returns true if doesn't contain any reference.
  177. func (a *AdvRefs) IsEmpty() bool {
  178. return a.Head == nil &&
  179. len(a.References) == 0 &&
  180. len(a.Peeled) == 0 &&
  181. len(a.Shallows) == 0
  182. }