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

Commit cb30e88

Browse files
authored
transport: add git-send-pack support to local/ssh. (#163)
* protocol/packp: add Packfile field to ReferenceUpdateRequest. * protocol/packp: add NewReferenceUpdateRequestFromCapabilities. * NewReferenceUpdateRequestFromCapabilities can be used to create a ReferenceUpdateRequest with initial capabilities compatible with the server. * protocol/packp: fix new line handling on report status. * transport/file: test error on unexisting command.
1 parent 963c190 commit cb30e88

19 files changed

+692
-62
lines changed

plumbing/protocol/packp/capability/capability.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ const (
231231
SymRef Capability = "symref"
232232
)
233233

234+
const DefaultAgent = "go-git/4.x"
235+
234236
var valid = map[Capability]bool{
235237
MultiACK: true, MultiACKDetailed: true, NoDone: true, ThinPack: true,
236238
Sideband: true, Sideband64k: true, OFSDelta: true, Agent: true,

plumbing/protocol/packp/report_status.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package packp
22

33
import (
4+
"bytes"
5+
"fmt"
46
"io"
7+
"strings"
58

6-
"fmt"
79
"gopkg.in/src-d/go-git.v4/plumbing"
810
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
9-
"strings"
1011
)
1112

1213
const (
@@ -33,7 +34,7 @@ func (s *ReportStatus) Ok() bool {
3334
// Encode writes the report status to a writer.
3435
func (s *ReportStatus) Encode(w io.Writer) error {
3536
e := pktline.NewEncoder(w)
36-
if err := e.Encodef("unpack %s", s.UnpackStatus); err != nil {
37+
if err := e.Encodef("unpack %s\n", s.UnpackStatus); err != nil {
3738
return err
3839
}
3940

@@ -95,6 +96,8 @@ func (s *ReportStatus) decodeReportStatus(b []byte) error {
9596
return fmt.Errorf("premature flush")
9697
}
9798

99+
b = bytes.TrimSuffix(b, eol)
100+
98101
line := string(b)
99102
fields := strings.SplitN(line, " ", 2)
100103
if len(fields) != 2 || fields[0] != "unpack" {
@@ -106,6 +109,8 @@ func (s *ReportStatus) decodeReportStatus(b []byte) error {
106109
}
107110

108111
func (s *ReportStatus) decodeCommandStatus(b []byte) error {
112+
b = bytes.TrimSuffix(b, eol)
113+
109114
line := string(b)
110115
fields := strings.SplitN(line, " ", 3)
111116
status := ok
@@ -138,8 +143,8 @@ func (s *CommandStatus) Ok() bool {
138143
func (s *CommandStatus) encode(w io.Writer) error {
139144
e := pktline.NewEncoder(w)
140145
if s.Ok() {
141-
return e.Encodef("ok %s", s.ReferenceName.String())
146+
return e.Encodef("ok %s\n", s.ReferenceName.String())
142147
}
143148

144-
return e.Encodef("ng %s %s", s.ReferenceName.String(), s.Status)
149+
return e.Encodef("ng %s %s\n", s.ReferenceName.String(), s.Status)
145150
}

plumbing/protocol/packp/report_status_test.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkOneReference(c *C) {
6969
}}
7070

7171
s.testEncodeDecodeOk(c, rs,
72-
"unpack ok",
73-
"ok refs/heads/master",
72+
"unpack ok\n",
73+
"ok refs/heads/master\n",
7474
pktline.FlushString,
7575
)
7676
}
@@ -84,8 +84,8 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkOneReferenceFailed(c *C) {
8484
}}
8585

8686
s.testEncodeDecodeOk(c, rs,
87-
"unpack my error",
88-
"ng refs/heads/master command error",
87+
"unpack my error\n",
88+
"ng refs/heads/master command error\n",
8989
pktline.FlushString,
9090
)
9191
}
@@ -105,10 +105,10 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkMoreReferences(c *C) {
105105
}}
106106

107107
s.testEncodeDecodeOk(c, rs,
108-
"unpack ok",
109-
"ok refs/heads/master",
110-
"ok refs/heads/a",
111-
"ok refs/heads/b",
108+
"unpack ok\n",
109+
"ok refs/heads/master\n",
110+
"ok refs/heads/a\n",
111+
"ok refs/heads/b\n",
112112
pktline.FlushString,
113113
)
114114
}
@@ -128,10 +128,10 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkMoreReferencesFailed(c *C) {
128128
}}
129129

130130
s.testEncodeDecodeOk(c, rs,
131-
"unpack my error",
132-
"ok refs/heads/master",
133-
"ng refs/heads/a command error",
134-
"ok refs/heads/b",
131+
"unpack my error\n",
132+
"ok refs/heads/master\n",
133+
"ng refs/heads/a command error\n",
134+
"ok refs/heads/b\n",
135135
pktline.FlushString,
136136
)
137137
}
@@ -141,7 +141,7 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkNoReferences(c *C) {
141141
expected.UnpackStatus = "ok"
142142

143143
s.testEncodeDecodeOk(c, expected,
144-
"unpack ok",
144+
"unpack ok\n",
145145
pktline.FlushString,
146146
)
147147
}
@@ -151,7 +151,7 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkNoReferencesFailed(c *C) {
151151
rs.UnpackStatus = "my error"
152152

153153
s.testEncodeDecodeOk(c, rs,
154-
"unpack my error",
154+
"unpack my error\n",
155155
pktline.FlushString,
156156
)
157157
}
@@ -165,8 +165,8 @@ func (s *ReportStatusSuite) TestDecodeErrorOneReferenceNoFlush(c *C) {
165165
}}
166166

167167
s.testDecodeError(c, "missing flush",
168-
"unpack ok",
169-
"ok refs/heads/master",
168+
"unpack ok\n",
169+
"ok refs/heads/master\n",
170170
)
171171
}
172172

@@ -190,7 +190,7 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformed(c *C) {
190190
}}
191191

192192
s.testDecodeError(c, "malformed unpack status: unpackok",
193-
"unpackok",
193+
"unpackok\n",
194194
pktline.FlushString,
195195
)
196196
}
@@ -204,7 +204,7 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformed2(c *C) {
204204
}}
205205

206206
s.testDecodeError(c, "malformed unpack status: UNPACK OK",
207-
"UNPACK OK",
207+
"UNPACK OK\n",
208208
pktline.FlushString,
209209
)
210210
}
@@ -218,8 +218,8 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformedCommandStatus(c *C) {
218218
}}
219219

220220
s.testDecodeError(c, "malformed command status: ko refs/heads/master",
221-
"unpack ok",
222-
"ko refs/heads/master",
221+
"unpack ok\n",
222+
"ko refs/heads/master\n",
223223
pktline.FlushString,
224224
)
225225
}
@@ -233,8 +233,8 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformedCommandStatus2(c *C) {
233233
}}
234234

235235
s.testDecodeError(c, "malformed command status: ng refs/heads/master",
236-
"unpack ok",
237-
"ng refs/heads/master",
236+
"unpack ok\n",
237+
"ng refs/heads/master\n",
238238
pktline.FlushString,
239239
)
240240
}

plumbing/protocol/packp/ulreq.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import (
88
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
99
)
1010

11-
const DefaultAgent = "go-git/4.x"
12-
1311
// UploadRequest values represent the information transmitted on a
1412
// upload-request message. Values from this type are not zero-value
1513
// safe, use the New function instead.
@@ -97,7 +95,7 @@ func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest {
9795
}
9896

9997
if adv.Supports(capability.Agent) {
100-
r.Capabilities.Set(capability.Agent, DefaultAgent)
98+
r.Capabilities.Set(capability.Agent, capability.DefaultAgent)
10199
}
102100

103101
return r

plumbing/protocol/packp/updreq.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package packp
22

33
import (
44
"errors"
5+
"io"
56

67
"gopkg.in/src-d/go-git.v4/plumbing"
78
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
@@ -20,6 +21,8 @@ type ReferenceUpdateRequest struct {
2021
Capabilities *capability.List
2122
Commands []*Command
2223
Shallow *plumbing.Hash
24+
// Packfile contains an optional packfile reader.
25+
Packfile io.ReadCloser
2326
}
2427

2528
// New returns a pointer to a new ReferenceUpdateRequest value.
@@ -30,6 +33,37 @@ func NewReferenceUpdateRequest() *ReferenceUpdateRequest {
3033
}
3134
}
3235

36+
// NewReferenceUpdateRequestFromCapabilities returns a pointer to a new
37+
// ReferenceUpdateRequest value, the request capabilities are filled with the
38+
// most optimal ones, based on the adv value (advertised capabilities), the
39+
// ReferenceUpdateRequest contains no commands
40+
//
41+
// It does set the following capabilities:
42+
// - agent
43+
// - report-status
44+
// - ofs-delta
45+
// - ref-delta
46+
// It leaves up to the user to add the following capabilities later:
47+
// - atomic
48+
// - ofs-delta
49+
// - side-band
50+
// - side-band-64k
51+
// - quiet
52+
// - push-cert
53+
func NewReferenceUpdateRequestFromCapabilities(adv *capability.List) *ReferenceUpdateRequest {
54+
r := NewReferenceUpdateRequest()
55+
56+
if adv.Supports(capability.Agent) {
57+
r.Capabilities.Set(capability.Agent, capability.DefaultAgent)
58+
}
59+
60+
if adv.Supports(capability.ReportStatus) {
61+
r.Capabilities.Set(capability.ReportStatus)
62+
}
63+
64+
return r
65+
}
66+
3367
func (r *ReferenceUpdateRequest) validate() error {
3468
if len(r.Commands) == 0 {
3569
return ErrEmptyCommands

plumbing/protocol/packp/updreq_decode.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"io"
9+
"io/ioutil"
910

1011
"gopkg.in/src-d/go-git.v4/plumbing"
1112
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
@@ -76,23 +77,32 @@ func errMalformedCommand(err error) error {
7677

7778
// Decode reads the next update-request message form the reader and wr
7879
func (req *ReferenceUpdateRequest) Decode(r io.Reader) error {
79-
d := &updReqDecoder{s: pktline.NewScanner(r)}
80+
var rc io.ReadCloser
81+
var ok bool
82+
rc, ok = r.(io.ReadCloser)
83+
if !ok {
84+
rc = ioutil.NopCloser(r)
85+
}
86+
87+
d := &updReqDecoder{r: rc, s: pktline.NewScanner(r)}
8088
return d.Decode(req)
8189
}
8290

8391
type updReqDecoder struct {
84-
s *pktline.Scanner
85-
r *ReferenceUpdateRequest
92+
r io.ReadCloser
93+
s *pktline.Scanner
94+
req *ReferenceUpdateRequest
8695
}
8796

88-
func (d *updReqDecoder) Decode(r *ReferenceUpdateRequest) error {
89-
d.r = r
97+
func (d *updReqDecoder) Decode(req *ReferenceUpdateRequest) error {
98+
d.req = req
9099
funcs := []func() error{
91100
d.scanLine,
92101
d.decodeShallow,
93102
d.decodeCommandAndCapabilities,
94103
d.decodeCommands,
95-
r.validate,
104+
d.setPackfile,
105+
req.validate,
96106
}
97107

98108
for _, f := range funcs {
@@ -132,7 +142,7 @@ func (d *updReqDecoder) decodeShallow() error {
132142
return d.scanErrorOr(errNoCommands)
133143
}
134144

135-
d.r.Shallow = &h
145+
d.req.Shallow = &h
136146

137147
return nil
138148
}
@@ -149,7 +159,7 @@ func (d *updReqDecoder) decodeCommands() error {
149159
return err
150160
}
151161

152-
d.r.Commands = append(d.r.Commands, c)
162+
d.req.Commands = append(d.req.Commands, c)
153163

154164
if ok := d.s.Scan(); !ok {
155165
return d.s.Err()
@@ -173,9 +183,9 @@ func (d *updReqDecoder) decodeCommandAndCapabilities() error {
173183
return err
174184
}
175185

176-
d.r.Commands = append(d.r.Commands, cmd)
186+
d.req.Commands = append(d.req.Commands, cmd)
177187

178-
if err := d.r.Capabilities.Decode(b[i+1:]); err != nil {
188+
if err := d.req.Capabilities.Decode(b[i+1:]); err != nil {
179189
return err
180190
}
181191

@@ -186,6 +196,12 @@ func (d *updReqDecoder) decodeCommandAndCapabilities() error {
186196
return nil
187197
}
188198

199+
func (d *updReqDecoder) setPackfile() error {
200+
d.req.Packfile = d.r
201+
202+
return nil
203+
}
204+
189205
func parseCommand(b []byte) (*Command, error) {
190206
if len(b) < minCommandLength {
191207
return nil, errInvalidCommandLineLength(len(b))

0 commit comments

Comments
 (0)