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

Commit 97fb5e9

Browse files
authored
Merge pull request #650 from mcuadros/endpoint
transport: converts Endpoint interface into a struct
2 parents dd81bc9 + 5eb1c56 commit 97fb5e9

25 files changed

+278
-269
lines changed

plumbing/transport/client/client.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ func InstallProtocol(scheme string, c transport.Transport) {
3434
// NewClient returns the appropriate client among of the set of known protocols:
3535
// http://, https://, ssh:// and file://.
3636
// See `InstallProtocol` to add or modify protocols.
37-
func NewClient(endpoint transport.Endpoint) (transport.Transport, error) {
38-
f, ok := Protocols[endpoint.Protocol()]
37+
func NewClient(endpoint *transport.Endpoint) (transport.Transport, error) {
38+
f, ok := Protocols[endpoint.Protocol]
3939
if !ok {
40-
return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol())
40+
return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol)
4141
}
4242

4343
if f == nil {
44-
return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol())
44+
return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol)
4545
}
4646

4747
return f, nil

plumbing/transport/client/client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ type dummyClient struct {
5959
*http.Client
6060
}
6161

62-
func (*dummyClient) NewUploadPackSession(transport.Endpoint, transport.AuthMethod) (
62+
func (*dummyClient) NewUploadPackSession(*transport.Endpoint, transport.AuthMethod) (
6363
transport.UploadPackSession, error) {
6464
return nil, nil
6565
}
6666

67-
func (*dummyClient) NewReceivePackSession(transport.Endpoint, transport.AuthMethod) (
67+
func (*dummyClient) NewReceivePackSession(*transport.Endpoint, transport.AuthMethod) (
6868
transport.ReceivePackSession, error) {
6969
return nil, nil
7070
}

plumbing/transport/common.go

Lines changed: 111 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
package transport
1414

1515
import (
16+
"bytes"
1617
"context"
1718
"errors"
1819
"fmt"
1920
"io"
2021
"net/url"
2122
"regexp"
2223
"strconv"
24+
"strings"
2325

2426
"gopkg.in/src-d/go-git.v4/plumbing"
2527
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
@@ -45,9 +47,9 @@ const (
4547
// It is implemented both by the client and the server, making this a RPC.
4648
type Transport interface {
4749
// NewUploadPackSession starts a git-upload-pack session for an endpoint.
48-
NewUploadPackSession(Endpoint, AuthMethod) (UploadPackSession, error)
50+
NewUploadPackSession(*Endpoint, AuthMethod) (UploadPackSession, error)
4951
// NewReceivePackSession starts a git-receive-pack session for an endpoint.
50-
NewReceivePackSession(Endpoint, AuthMethod) (ReceivePackSession, error)
52+
NewReceivePackSession(*Endpoint, AuthMethod) (ReceivePackSession, error)
5153
}
5254

5355
type Session interface {
@@ -91,26 +93,71 @@ type ReceivePackSession interface {
9193
}
9294

9395
// Endpoint represents a Git URL in any supported protocol.
94-
type Endpoint interface {
95-
// Protocol returns the protocol (e.g. git, https, file). It should never
96-
// return the empty string.
97-
Protocol() string
98-
// User returns the user or an empty string if none is given.
99-
User() string
100-
// Password returns the password or an empty string if none is given.
101-
Password() string
102-
// Host returns the host or an empty string if none is given.
103-
Host() string
104-
// Port returns the port or 0 if there is no port or a default should be
105-
// used.
106-
Port() int
107-
// Path returns the repository path.
108-
Path() string
109-
// String returns a string representation of the Git URL.
110-
String() string
96+
type Endpoint struct {
97+
// Protocol is the protocol of the endpoint (e.g. git, https, file). I
98+
Protocol string
99+
// User is the user.
100+
User string
101+
// Password is the password.
102+
Password string
103+
// Host is the host.
104+
Host string
105+
// Port is the port to connect, if 0 the default port for the given protocol
106+
// wil be used.
107+
Port int
108+
// Path is the repository path.
109+
Path string
111110
}
112111

113-
func NewEndpoint(endpoint string) (Endpoint, error) {
112+
var defaultPorts = map[string]int{
113+
"http": 80,
114+
"https": 443,
115+
"git": 9418,
116+
"ssh": 22,
117+
}
118+
119+
// String returns a string representation of the Git URL.
120+
func (u *Endpoint) String() string {
121+
var buf bytes.Buffer
122+
if u.Protocol != "" {
123+
buf.WriteString(u.Protocol)
124+
buf.WriteByte(':')
125+
}
126+
127+
if u.Protocol != "" || u.Host != "" || u.User != "" || u.Password != "" {
128+
buf.WriteString("//")
129+
130+
if u.User != "" || u.Password != "" {
131+
buf.WriteString(u.User)
132+
if u.Password != "" {
133+
buf.WriteByte(':')
134+
buf.WriteString(u.Password)
135+
}
136+
137+
buf.WriteByte('@')
138+
}
139+
140+
if u.Host != "" {
141+
buf.WriteString(u.Host)
142+
143+
if u.Port != 0 {
144+
port, ok := defaultPorts[strings.ToLower(u.Protocol)]
145+
if !ok || ok && port != u.Port {
146+
fmt.Fprintf(&buf, ":%d", u.Port)
147+
}
148+
}
149+
}
150+
}
151+
152+
if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
153+
buf.WriteByte('/')
154+
}
155+
156+
buf.WriteString(u.Path)
157+
return buf.String()
158+
}
159+
160+
func NewEndpoint(endpoint string) (*Endpoint, error) {
114161
if e, ok := parseSCPLike(endpoint); ok {
115162
return e, nil
116163
}
@@ -119,9 +166,13 @@ func NewEndpoint(endpoint string) (Endpoint, error) {
119166
return e, nil
120167
}
121168

169+
return parseURL(endpoint)
170+
}
171+
172+
func parseURL(endpoint string) (*Endpoint, error) {
122173
u, err := url.Parse(endpoint)
123174
if err != nil {
124-
return nil, plumbing.NewPermanentError(err)
175+
return nil, err
125176
}
126177

127178
if !u.IsAbs() {
@@ -130,127 +181,85 @@ func NewEndpoint(endpoint string) (Endpoint, error) {
130181
))
131182
}
132183

133-
return urlEndpoint{u}, nil
134-
}
135-
136-
type urlEndpoint struct {
137-
*url.URL
138-
}
139-
140-
func (e urlEndpoint) Protocol() string { return e.URL.Scheme }
141-
func (e urlEndpoint) Host() string { return e.URL.Hostname() }
142-
143-
func (e urlEndpoint) User() string {
144-
if e.URL.User == nil {
145-
return ""
146-
}
147-
148-
return e.URL.User.Username()
149-
}
150-
151-
func (e urlEndpoint) Password() string {
152-
if e.URL.User == nil {
153-
return ""
184+
var user, pass string
185+
if u.User != nil {
186+
user = u.User.Username()
187+
pass, _ = u.User.Password()
154188
}
155189

156-
p, _ := e.URL.User.Password()
157-
return p
190+
return &Endpoint{
191+
Protocol: u.Scheme,
192+
User: user,
193+
Password: pass,
194+
Host: u.Hostname(),
195+
Port: getPort(u),
196+
Path: getPath(u),
197+
}, nil
158198
}
159199

160-
func (e urlEndpoint) Port() int {
161-
p := e.URL.Port()
200+
func getPort(u *url.URL) int {
201+
p := u.Port()
162202
if p == "" {
163203
return 0
164204
}
165205

166-
i, err := strconv.Atoi(e.URL.Port())
206+
i, err := strconv.Atoi(p)
167207
if err != nil {
168208
return 0
169209
}
170210

171211
return i
172212
}
173213

174-
func (e urlEndpoint) Path() string {
175-
var res string = e.URL.Path
176-
if e.URL.RawQuery != "" {
177-
res += "?" + e.URL.RawQuery
214+
func getPath(u *url.URL) string {
215+
var res string = u.Path
216+
if u.RawQuery != "" {
217+
res += "?" + u.RawQuery
178218
}
179219

180-
if e.URL.Fragment != "" {
181-
res += "#" + e.URL.Fragment
220+
if u.Fragment != "" {
221+
res += "#" + u.Fragment
182222
}
183223

184224
return res
185225
}
186226

187-
type scpEndpoint struct {
188-
user string
189-
host string
190-
port string
191-
path string
192-
}
193-
194-
func (e *scpEndpoint) Protocol() string { return "ssh" }
195-
func (e *scpEndpoint) User() string { return e.user }
196-
func (e *scpEndpoint) Password() string { return "" }
197-
func (e *scpEndpoint) Host() string { return e.host }
198-
func (e *scpEndpoint) Path() string { return e.path }
199-
func (e *scpEndpoint) Port() int {
200-
i, err := strconv.Atoi(e.port)
201-
if err != nil {
202-
return 22
203-
}
204-
return i
205-
}
206-
207-
func (e *scpEndpoint) String() string {
208-
var user string
209-
if e.user != "" {
210-
user = fmt.Sprintf("%s@", e.user)
211-
}
212-
213-
return fmt.Sprintf("%s%s:%s", user, e.host, e.path)
214-
}
215-
216-
type fileEndpoint struct {
217-
path string
218-
}
219-
220-
func (e *fileEndpoint) Protocol() string { return "file" }
221-
func (e *fileEndpoint) User() string { return "" }
222-
func (e *fileEndpoint) Password() string { return "" }
223-
func (e *fileEndpoint) Host() string { return "" }
224-
func (e *fileEndpoint) Port() int { return 0 }
225-
func (e *fileEndpoint) Path() string { return e.path }
226-
func (e *fileEndpoint) String() string { return e.path }
227-
228227
var (
229228
isSchemeRegExp = regexp.MustCompile(`^[^:]+://`)
230229
scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P<user>[^@]+)@)?(?P<host>[^:\s]+):(?:(?P<port>[0-9]{1,5})/)?(?P<path>[^\\].*)$`)
231230
)
232231

233-
func parseSCPLike(endpoint string) (Endpoint, bool) {
232+
func parseSCPLike(endpoint string) (*Endpoint, bool) {
234233
if isSchemeRegExp.MatchString(endpoint) || !scpLikeUrlRegExp.MatchString(endpoint) {
235234
return nil, false
236235
}
237236

238237
m := scpLikeUrlRegExp.FindStringSubmatch(endpoint)
239-
return &scpEndpoint{
240-
user: m[1],
241-
host: m[2],
242-
port: m[3],
243-
path: m[4],
238+
239+
port, err := strconv.Atoi(m[3])
240+
if err != nil {
241+
port = 22
242+
}
243+
244+
return &Endpoint{
245+
Protocol: "ssh",
246+
User: m[1],
247+
Host: m[2],
248+
Port: port,
249+
Path: m[4],
244250
}, true
245251
}
246252

247-
func parseFile(endpoint string) (Endpoint, bool) {
253+
func parseFile(endpoint string) (*Endpoint, bool) {
248254
if isSchemeRegExp.MatchString(endpoint) {
249255
return nil, false
250256
}
251257

252258
path := endpoint
253-
return &fileEndpoint{path}, true
259+
return &Endpoint{
260+
Protocol: "file",
261+
Path: path,
262+
}, true
254263
}
255264

256265
// UnsupportedCapabilities are the capabilities not supported by any client

0 commit comments

Comments
 (0)