Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit f861f30

Browse files
alcortesmmcuadros
authored andcommitted
Use advrefs in gituploadpackinfo (#92)
* add advrefs encoder and parser * modify advrefs encoder to resemble json encoder * turn advrefs parser into a decoder * clean code * improve documentation * improve documentation * clean code * upgrade to new pktline.Add and add Flush const to easy integration * gometalinter * Use packp/advrefs for GitUploadPackInfo parsing - GitUploadPackInfo now uses packp/advrefs instead of parsing the message by itself. - Capabilities has been moved from clients/common to packp to avoid a circular import. - Cleaning of advrefs_test code. - Add support for prefix encoding and decoding in advrefs. * clean advrefs test code * clean advrefs test code * clean advrefs test code * gometalinter * add pktline encoder * change pktline.EncodeFlush to pktline.Flush * make scanner tests use the encoder instead of Pktlines * check errors on flush and clean constants * ubstitute the PktLines type with a pktline.Encoder * use pktline.Encoder in all go-git * add example of pktline.Encodef() * add package overview * documentation * support symbolic links other than HEAD * simplify decoding of shallows * packp: fix mcuadros comments - all abbreviates removed (by visual inspection, some may remain) - all empty maps are initialized using make - simplify readRef with a switch - make decodeShallow malformed error more verbose - add pktline.Encoder.encodeLine - remove infamous panic in checkPayloadLength by refactoring out the whole function
1 parent 723ab96 commit f861f30

20 files changed

+2946
-636
lines changed

clients/common/common.go

Lines changed: 62 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package common
33

44
import (
5+
"bytes"
56
"errors"
67
"fmt"
78
"io"
@@ -11,6 +12,8 @@ import (
1112
"strings"
1213

1314
"gopkg.in/src-d/go-git.v4/core"
15+
"gopkg.in/src-d/go-git.v4/formats/packp"
16+
"gopkg.in/src-d/go-git.v4/formats/packp/advrefs"
1417
"gopkg.in/src-d/go-git.v4/formats/packp/pktline"
1518
"gopkg.in/src-d/go-git.v4/storage/memory"
1619
)
@@ -75,246 +78,100 @@ func (e *Endpoint) String() string {
7578
return u.String()
7679
}
7780

78-
// Capabilities contains all the server capabilities
79-
// https://github.com/git/git/blob/master/Documentation/technical/protocol-capabilities.txt
80-
type Capabilities struct {
81-
m map[string]*Capability
82-
o []string
83-
}
84-
85-
// Capability represents a server capability
86-
type Capability struct {
87-
Name string
88-
Values []string
81+
type GitUploadPackInfo struct {
82+
Capabilities *packp.Capabilities
83+
Refs memory.ReferenceStorage
8984
}
9085

91-
// NewCapabilities returns a new Capabilities struct
92-
func NewCapabilities() *Capabilities {
93-
return &Capabilities{
94-
m: make(map[string]*Capability, 0),
95-
}
86+
func NewGitUploadPackInfo() *GitUploadPackInfo {
87+
return &GitUploadPackInfo{Capabilities: packp.NewCapabilities()}
9688
}
9789

98-
// Decode decodes a string
99-
func (c *Capabilities) Decode(raw string) {
100-
params := strings.Split(raw, " ")
101-
for _, p := range params {
102-
s := strings.SplitN(p, "=", 2)
103-
104-
var value string
105-
if len(s) == 2 {
106-
value = s[1]
90+
func (i *GitUploadPackInfo) Decode(r io.Reader) error {
91+
d := advrefs.NewDecoder(r)
92+
ar := advrefs.New()
93+
if err := d.Decode(ar); err != nil {
94+
if err == advrefs.ErrEmpty {
95+
return core.NewPermanentError(err)
10796
}
108-
109-
c.Add(s[0], value)
110-
}
111-
}
112-
113-
// Get returns the values for a capability
114-
func (c *Capabilities) Get(capability string) *Capability {
115-
return c.m[capability]
116-
}
117-
118-
// Set sets a capability removing the values
119-
func (c *Capabilities) Set(capability string, values ...string) {
120-
if _, ok := c.m[capability]; ok {
121-
delete(c.m, capability)
97+
return core.NewUnexpectedError(err)
12298
}
12399

124-
c.Add(capability, values...)
125-
}
126-
127-
// Add adds a capability, values are optional
128-
func (c *Capabilities) Add(capability string, values ...string) {
129-
if !c.Supports(capability) {
130-
c.m[capability] = &Capability{Name: capability}
131-
c.o = append(c.o, capability)
132-
}
100+
i.Capabilities = ar.Capabilities
133101

134-
if len(values) == 0 {
135-
return
102+
if err := i.addRefs(ar); err != nil {
103+
return core.NewUnexpectedError(err)
136104
}
137105

138-
c.m[capability].Values = append(c.m[capability].Values, values...)
139-
}
140-
141-
// Supports returns true if capability is present
142-
func (c *Capabilities) Supports(capability string) bool {
143-
_, ok := c.m[capability]
144-
return ok
106+
return nil
145107
}
146108

147-
// SymbolicReference returns the reference for a given symbolic reference
148-
func (c *Capabilities) SymbolicReference(sym string) string {
149-
if !c.Supports("symref") {
150-
return ""
151-
}
152-
153-
for _, symref := range c.Get("symref").Values {
154-
parts := strings.Split(symref, ":")
155-
if len(parts) != 2 {
156-
continue
157-
}
158-
159-
if parts[0] == sym {
160-
return parts[1]
161-
}
109+
func (i *GitUploadPackInfo) addRefs(ar *advrefs.AdvRefs) error {
110+
i.Refs = make(memory.ReferenceStorage, 0)
111+
for name, hash := range ar.References {
112+
ref := core.NewReferenceFromStrings(name, hash.String())
113+
i.Refs.Set(ref)
162114
}
163115

164-
return ""
116+
return i.addSymbolicRefs(ar)
165117
}
166118

167-
func (c *Capabilities) String() string {
168-
if len(c.o) == 0 {
169-
return ""
170-
}
171-
172-
var o string
173-
for _, key := range c.o {
174-
cap := c.m[key]
175-
176-
added := false
177-
for _, value := range cap.Values {
178-
if value == "" {
179-
continue
180-
}
181-
182-
added = true
183-
o += fmt.Sprintf("%s=%s ", key, value)
184-
}
185-
186-
if len(cap.Values) == 0 || !added {
187-
o += key + " "
188-
}
189-
}
190-
191-
if len(o) == 0 {
192-
return o
119+
func (i *GitUploadPackInfo) addSymbolicRefs(ar *advrefs.AdvRefs) error {
120+
if !hasSymrefs(ar) {
121+
return nil
193122
}
194123

195-
return o[:len(o)-1]
196-
}
197-
198-
type GitUploadPackInfo struct {
199-
Capabilities *Capabilities
200-
Refs memory.ReferenceStorage
201-
}
202-
203-
func NewGitUploadPackInfo() *GitUploadPackInfo {
204-
return &GitUploadPackInfo{Capabilities: NewCapabilities()}
205-
}
206-
207-
func (r *GitUploadPackInfo) Decode(s *pktline.Scanner) error {
208-
if err := r.read(s); err != nil {
209-
if err == ErrEmptyGitUploadPack {
210-
return core.NewPermanentError(err)
124+
for _, symref := range ar.Capabilities.Get("symref").Values {
125+
chunks := strings.Split(symref, ":")
126+
if len(chunks) != 2 {
127+
err := fmt.Errorf("bad number of `:` in symref value (%q)", symref)
128+
return core.NewUnexpectedError(err)
211129
}
212-
213-
return core.NewUnexpectedError(err)
130+
name := core.ReferenceName(chunks[0])
131+
target := core.ReferenceName(chunks[1])
132+
ref := core.NewSymbolicReference(name, target)
133+
i.Refs.Set(ref)
214134
}
215135

216136
return nil
217137
}
218138

219-
func (r *GitUploadPackInfo) read(s *pktline.Scanner) error {
220-
isEmpty := true
221-
r.Refs = make(memory.ReferenceStorage, 0)
222-
smartCommentIgnore := false
223-
for s.Scan() {
224-
line := string(s.Bytes())
225-
226-
if smartCommentIgnore {
227-
// some servers like Github add a flush-pkt after the smart http comment
228-
// that we must ignore to prevent a premature termination of the read.
229-
if len(line) == 0 {
230-
continue
231-
}
232-
smartCommentIgnore = false
233-
}
234-
235-
// exit on first flush-pkt
236-
if len(line) == 0 {
237-
break
238-
}
239-
240-
if isSmartHttpComment(line) {
241-
smartCommentIgnore = true
242-
continue
243-
}
244-
245-
if err := r.readLine(line); err != nil {
246-
return err
247-
}
248-
249-
isEmpty = false
250-
}
251-
252-
if isEmpty {
253-
return ErrEmptyGitUploadPack
254-
}
255-
256-
return s.Err()
139+
func hasSymrefs(ar *advrefs.AdvRefs) bool {
140+
return ar.Capabilities.Supports("symref")
257141
}
258142

259-
func isSmartHttpComment(line string) bool {
260-
return line[0] == '#'
143+
func (i *GitUploadPackInfo) Head() *core.Reference {
144+
ref, _ := core.ResolveReference(i.Refs, core.HEAD)
145+
return ref
261146
}
262147

263-
func (r *GitUploadPackInfo) readLine(line string) error {
264-
hashEnd := strings.Index(line, " ")
265-
hash := line[:hashEnd]
266-
267-
zeroID := strings.Index(line, string([]byte{0}))
268-
if zeroID == -1 {
269-
name := line[hashEnd+1 : len(line)-1]
270-
ref := core.NewReferenceFromStrings(name, hash)
271-
return r.Refs.Set(ref)
272-
}
273-
274-
name := line[hashEnd+1 : zeroID]
275-
r.Capabilities.Decode(line[zeroID+1 : len(line)-1])
276-
if !r.Capabilities.Supports("symref") {
277-
ref := core.NewReferenceFromStrings(name, hash)
278-
return r.Refs.Set(ref)
279-
}
280-
281-
target := r.Capabilities.SymbolicReference(name)
282-
ref := core.NewSymbolicReference(core.ReferenceName(name), core.ReferenceName(target))
283-
return r.Refs.Set(ref)
148+
func (i *GitUploadPackInfo) String() string {
149+
return string(i.Bytes())
284150
}
285151

286-
func (r *GitUploadPackInfo) Head() *core.Reference {
287-
ref, _ := core.ResolveReference(r.Refs, core.HEAD)
288-
return ref
289-
}
152+
func (i *GitUploadPackInfo) Bytes() []byte {
153+
var buf bytes.Buffer
154+
e := pktline.NewEncoder(&buf)
290155

291-
func (r *GitUploadPackInfo) String() string {
292-
return string(r.Bytes())
293-
}
156+
_ = e.EncodeString("# service=git-upload-pack\n")
294157

295-
func (r *GitUploadPackInfo) Bytes() []byte {
296-
p := pktline.New()
297-
_ = p.AddString("# service=git-upload-pack\n")
298158
// inserting a flush-pkt here violates the protocol spec, but some
299159
// servers do it, like Github.com
300-
p.AddFlush()
160+
e.Flush()
301161

302-
firstLine := fmt.Sprintf("%s HEAD\x00%s\n", r.Head().Hash(), r.Capabilities.String())
303-
_ = p.AddString(firstLine)
162+
_ = e.Encodef("%s HEAD\x00%s\n", i.Head().Hash(), i.Capabilities.String())
304163

305-
for _, ref := range r.Refs {
164+
for _, ref := range i.Refs {
306165
if ref.Type() != core.HashReference {
307166
continue
308167
}
309168

310-
ref := fmt.Sprintf("%s %s\n", ref.Hash(), ref.Name())
311-
_ = p.AddString(ref)
169+
_ = e.Encodef("%s %s\n", ref.Hash(), ref.Name())
312170
}
313171

314-
p.AddFlush()
315-
b, _ := ioutil.ReadAll(p)
172+
e.Flush()
316173

317-
return b
174+
return buf.Bytes()
318175
}
319176

320177
type GitUploadPackRequest struct {
@@ -337,24 +194,23 @@ func (r *GitUploadPackRequest) String() string {
337194
}
338195

339196
func (r *GitUploadPackRequest) Reader() *strings.Reader {
340-
p := pktline.New()
197+
var buf bytes.Buffer
198+
e := pktline.NewEncoder(&buf)
341199

342200
for _, want := range r.Wants {
343-
_ = p.AddString(fmt.Sprintf("want %s\n", want))
201+
_ = e.Encodef("want %s\n", want)
344202
}
345203

346204
for _, have := range r.Haves {
347-
_ = p.AddString(fmt.Sprintf("have %s\n", have))
205+
_ = e.Encodef("have %s\n", have)
348206
}
349207

350208
if r.Depth != 0 {
351-
_ = p.AddString(fmt.Sprintf("deepen %d\n", r.Depth))
209+
_ = e.Encodef("deepen %d\n", r.Depth)
352210
}
353211

354-
p.AddFlush()
355-
_ = p.AddString("done\n")
356-
357-
b, _ := ioutil.ReadAll(p)
212+
_ = e.Flush()
213+
_ = e.EncodeString("done\n")
358214

359-
return strings.NewReader(string(b))
215+
return strings.NewReader(buf.String())
360216
}

0 commit comments

Comments
 (0)