1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
package packp
import (
"bytes"
"fmt"
"io"
"time"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/pktline"
)
// Encode writes the UlReq encoding of u to the stream.
//
// All the payloads will end with a newline character. Wants and
// shallows are sorted alphabetically. A depth of 0 means no depth
// request is sent.
func (req *UploadRequest) Encode(w io.Writer) error {
e := newUlReqEncoder(w)
return e.Encode(req)
}
type ulReqEncoder struct {
pe *pktline.Encoder // where to write the encoded data
data *UploadRequest // the data to encode
err error // sticky error
}
func newUlReqEncoder(w io.Writer) *ulReqEncoder {
return &ulReqEncoder{
pe: pktline.NewEncoder(w),
}
}
func (e *ulReqEncoder) Encode(v *UploadRequest) error {
e.data = v
if len(v.Wants) == 0 {
return fmt.Errorf("empty wants provided")
}
plumbing.HashesSort(e.data.Wants)
for state := e.encodeFirstWant; state != nil; {
state = state()
}
return e.err
}
func (e *ulReqEncoder) encodeFirstWant() stateFn {
var err error
if e.data.Capabilities.IsEmpty() {
err = e.pe.Encodef("want %s\n", e.data.Wants[0])
} else {
err = e.pe.Encodef(
"want %s %s\n",
e.data.Wants[0],
e.data.Capabilities.String(),
)
}
if err != nil {
e.err = fmt.Errorf("encoding first want line: %s", err)
return nil
}
return e.encodeAdditionalWants
}
func (e *ulReqEncoder) encodeAdditionalWants() stateFn {
last := e.data.Wants[0]
for _, w := range e.data.Wants[1:] {
if bytes.Equal(last[:], w[:]) {
continue
}
if err := e.pe.Encodef("want %s\n", w); err != nil {
e.err = fmt.Errorf("encoding want %q: %s", w, err)
return nil
}
last = w
}
return e.encodeShallows
}
func (e *ulReqEncoder) encodeShallows() stateFn {
plumbing.HashesSort(e.data.Shallows)
var last plumbing.Hash
for _, s := range e.data.Shallows {
if bytes.Equal(last[:], s[:]) {
continue
}
if err := e.pe.Encodef("shallow %s\n", s); err != nil {
e.err = fmt.Errorf("encoding shallow %q: %s", s, err)
return nil
}
last = s
}
return e.encodeDepth
}
func (e *ulReqEncoder) encodeDepth() stateFn {
switch depth := e.data.Depth.(type) {
case DepthCommits:
if depth != 0 {
commits := int(depth)
if err := e.pe.Encodef("deepen %d\n", commits); err != nil {
e.err = fmt.Errorf("encoding depth %d: %s", depth, err)
return nil
}
}
case DepthSince:
when := time.Time(depth).UTC()
if err := e.pe.Encodef("deepen-since %d\n", when.Unix()); err != nil {
e.err = fmt.Errorf("encoding depth %s: %s", when, err)
return nil
}
case DepthReference:
reference := string(depth)
if err := e.pe.Encodef("deepen-not %s\n", reference); err != nil {
e.err = fmt.Errorf("encoding depth %s: %s", reference, err)
return nil
}
default:
e.err = fmt.Errorf("unsupported depth type")
return nil
}
return e.encodeFilter
}
func (e *ulReqEncoder) encodeFilter() stateFn {
if filter := e.data.Filter; filter != "" {
if err := e.pe.Encodef("filter %s\n", filter); err != nil {
e.err = fmt.Errorf("encoding filter %s: %s", filter, err)
return nil
}
}
return e.encodeFlush
}
func (e *ulReqEncoder) encodeFlush() stateFn {
if err := e.pe.Flush(); err != nil {
e.err = fmt.Errorf("encoding flush-pkt: %s", err)
return nil
}
return nil
}
|