+99
-9
plumbing/protocol/packp/advrefs.go
+99
-9
plumbing/protocol/packp/advrefs.go
···
2
2
3
3
import (
4
4
"fmt"
5
+
"sort"
5
6
"strings"
6
7
7
8
"gopkg.in/src-d/go-git.v4/plumbing"
···
68
69
69
70
func (a *AdvRefs) AllReferences() (memory.ReferenceStorage, error) {
70
71
s := memory.ReferenceStorage{}
71
-
if err := addRefs(s, a); err != nil {
72
+
if err := a.addRefs(s); err != nil {
72
73
return s, plumbing.NewUnexpectedError(err)
73
74
}
74
75
75
76
return s, nil
76
77
}
77
78
78
-
func addRefs(s storer.ReferenceStorer, ar *AdvRefs) error {
79
-
for name, hash := range ar.References {
79
+
func (a *AdvRefs) addRefs(s storer.ReferenceStorer) error {
80
+
for name, hash := range a.References {
80
81
ref := plumbing.NewReferenceFromStrings(name, hash.String())
81
82
if err := s.SetReference(ref); err != nil {
82
83
return err
83
84
}
84
85
}
85
86
86
-
return addSymbolicRefs(s, ar)
87
+
if a.supportSymrefs() {
88
+
return a.addSymbolicRefs(s)
89
+
}
90
+
91
+
return a.resolveHead(s)
87
92
}
88
93
89
-
func addSymbolicRefs(s storer.ReferenceStorer, ar *AdvRefs) error {
90
-
if !hasSymrefs(ar) {
94
+
// If the server does not support symrefs capability,
95
+
// we need to guess the reference where HEAD is pointing to.
96
+
//
97
+
// Git versions prior to 1.8.4.3 has an special procedure to get
98
+
// the reference where is pointing to HEAD:
99
+
// - Check if a reference called master exists. If exists and it
100
+
// has the same hash as HEAD hash, we can say that HEAD is pointing to master
101
+
// - If master does not exists or does not have the same hash as HEAD,
102
+
// order references and check in that order if that reference has the same
103
+
// hash than HEAD. If yes, set HEAD pointing to that branch hash
104
+
// - If no reference is found, throw an error
105
+
func (a *AdvRefs) resolveHead(s storer.ReferenceStorer) error {
106
+
if a.Head == nil {
91
107
return nil
92
108
}
93
109
94
-
for _, symref := range ar.Capabilities.Get(capability.SymRef) {
110
+
ref, err := s.Reference(plumbing.ReferenceName(plumbing.Master))
111
+
112
+
// check first if HEAD is pointing to master
113
+
if err == nil {
114
+
ok, err := a.createHeadIfCorrectReference(ref, s)
115
+
if err != nil {
116
+
return err
117
+
}
118
+
119
+
if ok {
120
+
return nil
121
+
}
122
+
}
123
+
124
+
if err != nil && err != plumbing.ErrReferenceNotFound {
125
+
return err
126
+
}
127
+
128
+
// From here we are trying to guess the branch that HEAD is pointing
129
+
refIter, err := s.IterReferences()
130
+
if err != nil {
131
+
return err
132
+
}
133
+
134
+
var refNames []string
135
+
err = refIter.ForEach(func(r *plumbing.Reference) error {
136
+
refNames = append(refNames, string(r.Name()))
137
+
return nil
138
+
})
139
+
if err != nil {
140
+
return err
141
+
}
142
+
143
+
sort.Strings(refNames)
144
+
145
+
var headSet bool
146
+
for _, refName := range refNames {
147
+
ref, err := s.Reference(plumbing.ReferenceName(refName))
148
+
if err != nil {
149
+
return err
150
+
}
151
+
ok, err := a.createHeadIfCorrectReference(ref, s)
152
+
if err != nil {
153
+
return err
154
+
}
155
+
if ok {
156
+
headSet = true
157
+
break
158
+
}
159
+
}
160
+
161
+
if !headSet {
162
+
return plumbing.ErrReferenceNotFound
163
+
}
164
+
165
+
return nil
166
+
}
167
+
168
+
func (a *AdvRefs) createHeadIfCorrectReference(
169
+
reference *plumbing.Reference,
170
+
s storer.ReferenceStorer) (bool, error) {
171
+
if reference.Hash() == *a.Head {
172
+
headRef := plumbing.NewSymbolicReference(plumbing.HEAD, reference.Name())
173
+
if err := s.SetReference(headRef); err != nil {
174
+
return false, err
175
+
}
176
+
177
+
return true, nil
178
+
}
179
+
180
+
return false, nil
181
+
}
182
+
183
+
func (a *AdvRefs) addSymbolicRefs(s storer.ReferenceStorer) error {
184
+
for _, symref := range a.Capabilities.Get(capability.SymRef) {
95
185
chunks := strings.Split(symref, ":")
96
186
if len(chunks) != 2 {
97
187
err := fmt.Errorf("bad number of `:` in symref value (%q)", symref)
···
108
198
return nil
109
199
}
110
200
111
-
func hasSymrefs(ar *AdvRefs) bool {
112
-
return ar.Capabilities.Supports(capability.SymRef)
201
+
func (a *AdvRefs) supportSymrefs() bool {
202
+
return a.Capabilities.Supports(capability.SymRef)
113
203
}
+73
plumbing/protocol/packp/advrefs_test.go
+73
plumbing/protocol/packp/advrefs_test.go
···
79
79
c.Assert(err, NotNil)
80
80
}
81
81
82
+
func (s *AdvRefSuite) TestNoSymRefCapabilityHeadToMaster(c *C) {
83
+
a := NewAdvRefs()
84
+
headHash := plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c")
85
+
a.Head = &headHash
86
+
ref := plumbing.NewHashReference(plumbing.Master, plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c"))
87
+
88
+
err := a.AddReference(ref)
89
+
c.Assert(err, IsNil)
90
+
91
+
storage, err := a.AllReferences()
92
+
c.Assert(err, IsNil)
93
+
94
+
head, err := storage.Reference(plumbing.HEAD)
95
+
c.Assert(err, IsNil)
96
+
c.Assert(head.Target(), Equals, ref.Name())
97
+
}
98
+
99
+
func (s *AdvRefSuite) TestNoSymRefCapabilityHeadToOtherThanMaster(c *C) {
100
+
a := NewAdvRefs()
101
+
headHash := plumbing.NewHash("0000000000000000000000000000000000000000")
102
+
a.Head = &headHash
103
+
ref1 := plumbing.NewHashReference(plumbing.Master, plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c"))
104
+
ref2 := plumbing.NewHashReference("other/ref", plumbing.NewHash("0000000000000000000000000000000000000000"))
105
+
106
+
err := a.AddReference(ref1)
107
+
c.Assert(err, IsNil)
108
+
err = a.AddReference(ref2)
109
+
c.Assert(err, IsNil)
110
+
111
+
storage, err := a.AllReferences()
112
+
c.Assert(err, IsNil)
113
+
114
+
head, err := storage.Reference(plumbing.HEAD)
115
+
c.Assert(err, IsNil)
116
+
c.Assert(head.Hash(), Equals, ref2.Hash())
117
+
}
118
+
119
+
func (s *AdvRefSuite) TestNoSymRefCapabilityHeadToNoRef(c *C) {
120
+
a := NewAdvRefs()
121
+
headHash := plumbing.NewHash("0000000000000000000000000000000000000000")
122
+
a.Head = &headHash
123
+
ref := plumbing.NewHashReference(plumbing.Master, plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c"))
124
+
125
+
err := a.AddReference(ref)
126
+
c.Assert(err, IsNil)
127
+
128
+
_, err = a.AllReferences()
129
+
c.Assert(err, NotNil)
130
+
}
131
+
132
+
func (s *AdvRefSuite) TestNoSymRefCapabilityHeadToNoMasterAlphabeticallyOrdered(c *C) {
133
+
a := NewAdvRefs()
134
+
headHash := plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c")
135
+
a.Head = &headHash
136
+
ref1 := plumbing.NewHashReference(plumbing.Master, plumbing.NewHash("0000000000000000000000000000000000000000"))
137
+
ref2 := plumbing.NewHashReference("aaaaaaaaaaaaaaa", plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c"))
138
+
ref3 := plumbing.NewHashReference("bbbbbbbbbbbbbbb", plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c"))
139
+
140
+
err := a.AddReference(ref1)
141
+
c.Assert(err, IsNil)
142
+
err = a.AddReference(ref3)
143
+
c.Assert(err, IsNil)
144
+
err = a.AddReference(ref2)
145
+
c.Assert(err, IsNil)
146
+
147
+
storage, err := a.AllReferences()
148
+
c.Assert(err, IsNil)
149
+
150
+
head, err := storage.Reference(plumbing.HEAD)
151
+
c.Assert(err, IsNil)
152
+
c.Assert(head.Target(), Equals, ref2.Name())
153
+
}
154
+
82
155
type AdvRefsDecodeEncodeSuite struct{}
83
156
84
157
var _ = Suite(&AdvRefsDecodeEncodeSuite{})