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

Commit b8b61e7

Browse files
committed
Merge branch 'master' of github.com:src-d/go-git into commit
2 parents 40fa588 + e80cdba commit b8b61e7

25 files changed

+663
-163
lines changed

_examples/common_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package examples
22

33
import (
44
"flag"
5-
"fmt"
65
"go/build"
76
"io/ioutil"
87
"os"
@@ -96,7 +95,7 @@ func createBareRepository(dir string) string {
9695

9796
func setEmptyRemote(dir string) string {
9897
remote := createBareRepository(tempFolder())
99-
setRemote(dir, fmt.Sprintf("file://%s", remote))
98+
setRemote(dir, remote)
10099
return dir
101100
}
102101

_examples/storage/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#go-git + aerospike: a git repository backed by a database
1+
# go-git + aerospike: a git repository backed by a database
22

33
<img src="https://upload.wikimedia.org/wikipedia/en/2/2b/Aerospike_logo.png" align="right"/> This is an example of a [go-git](https://github.com/src-d/go-git) repository backed by [Aerospike](http://www.aerospike.com/).
44

common_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package git
22

33
import (
4-
"fmt"
54
"testing"
65

76
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -95,8 +94,7 @@ func (s *BaseSuite) GetBasicLocalRepositoryURL() string {
9594
}
9695

9796
func (s *BaseSuite) GetLocalRepositoryURL(f *fixtures.Fixture) string {
98-
path := f.DotGit().Base()
99-
return fmt.Sprintf("file://%s", path)
97+
return f.DotGit().Base()
10098
}
10199

102100
type SuiteCommon struct{}

plumbing/transport/client/client.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ func InstallProtocol(scheme string, c transport.Transport) {
3535
// http://, https://, ssh:// and file://.
3636
// See `InstallProtocol` to add or modify protocols.
3737
func NewClient(endpoint transport.Endpoint) (transport.Transport, error) {
38-
f, ok := Protocols[endpoint.Scheme]
38+
f, ok := Protocols[endpoint.Protocol()]
3939
if !ok {
40-
return nil, fmt.Errorf("unsupported scheme %q", endpoint.Scheme)
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.Scheme)
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/common.go

+137-19
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"io"
1919
"net/url"
2020
"regexp"
21+
"strconv"
2122

2223
"gopkg.in/src-d/go-git.v4/plumbing"
2324
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
@@ -28,7 +29,7 @@ var (
2829
ErrRepositoryNotFound = errors.New("repository not found")
2930
ErrEmptyRemoteRepository = errors.New("remote repository is empty")
3031
ErrAuthenticationRequired = errors.New("authentication required")
31-
ErrAuthorizationFailed = errors.New("authorization failed")
32+
ErrAuthorizationFailed = errors.New("authorization failed")
3233
ErrEmptyUploadPackRequest = errors.New("empty git-upload-pack given")
3334
ErrInvalidAuthMethod = errors.New("invalid auth method")
3435
ErrAlreadyConnected = errors.New("session already established")
@@ -88,42 +89,159 @@ type ReceivePackSession interface {
8889
ReceivePack(*packp.ReferenceUpdateRequest) (*packp.ReportStatus, error)
8990
}
9091

91-
type Endpoint url.URL
92-
93-
var (
94-
isSchemeRegExp = regexp.MustCompile("^[^:]+://")
95-
scpLikeUrlRegExp = regexp.MustCompile("^(?P<user>[^@]+@)?(?P<host>[^:]+):/?(?P<path>.+)$")
96-
)
92+
// Endpoint represents a Git URL in any supported protocol.
93+
type Endpoint interface {
94+
// Protocol returns the protocol (e.g. git, https, file). It should never
95+
// return the empty string.
96+
Protocol() string
97+
// User returns the user or an empty string if none is given.
98+
User() string
99+
// Password returns the password or an empty string if none is given.
100+
Password() string
101+
// Host returns the host or an empty string if none is given.
102+
Host() string
103+
// Port returns the port or 0 if there is no port or a default should be
104+
// used.
105+
Port() int
106+
// Path returns the repository path.
107+
Path() string
108+
// String returns a string representation of the Git URL.
109+
String() string
110+
}
97111

98112
func NewEndpoint(endpoint string) (Endpoint, error) {
99-
endpoint = transformSCPLikeIfNeeded(endpoint)
113+
if e, ok := parseSCPLike(endpoint); ok {
114+
return e, nil
115+
}
116+
117+
if e, ok := parseFile(endpoint); ok {
118+
return e, nil
119+
}
100120

101121
u, err := url.Parse(endpoint)
102122
if err != nil {
103-
return Endpoint{}, plumbing.NewPermanentError(err)
123+
return nil, plumbing.NewPermanentError(err)
104124
}
105125

106126
if !u.IsAbs() {
107-
return Endpoint{}, plumbing.NewPermanentError(fmt.Errorf(
127+
return nil, plumbing.NewPermanentError(fmt.Errorf(
108128
"invalid endpoint: %s", endpoint,
109129
))
110130
}
111131

112-
return Endpoint(*u), nil
132+
return urlEndpoint{u}, nil
133+
}
134+
135+
type urlEndpoint struct {
136+
*url.URL
137+
}
138+
139+
func (e urlEndpoint) Protocol() string { return e.URL.Scheme }
140+
func (e urlEndpoint) Host() string { return e.URL.Hostname() }
141+
142+
func (e urlEndpoint) User() string {
143+
if e.URL.User == nil {
144+
return ""
145+
}
146+
147+
return e.URL.User.Username()
148+
}
149+
150+
func (e urlEndpoint) Password() string {
151+
if e.URL.User == nil {
152+
return ""
153+
}
154+
155+
p, _ := e.URL.User.Password()
156+
return p
157+
}
158+
159+
func (e urlEndpoint) Port() int {
160+
p := e.URL.Port()
161+
if p == "" {
162+
return 0
163+
}
164+
165+
i, err := strconv.Atoi(e.URL.Port())
166+
if err != nil {
167+
return 0
168+
}
169+
170+
return i
171+
}
172+
173+
func (e urlEndpoint) Path() string {
174+
var res string = e.URL.Path
175+
if e.URL.RawQuery != "" {
176+
res += "?" + e.URL.RawQuery
177+
}
178+
179+
if e.URL.Fragment != "" {
180+
res += "#" + e.URL.Fragment
181+
}
182+
183+
return res
184+
}
185+
186+
type scpEndpoint struct {
187+
user string
188+
host string
189+
path string
113190
}
114191

115-
func (e *Endpoint) String() string {
116-
u := url.URL(*e)
117-
return u.String()
192+
func (e *scpEndpoint) Protocol() string { return "ssh" }
193+
func (e *scpEndpoint) User() string { return e.user }
194+
func (e *scpEndpoint) Password() string { return "" }
195+
func (e *scpEndpoint) Host() string { return e.host }
196+
func (e *scpEndpoint) Port() int { return 22 }
197+
func (e *scpEndpoint) Path() string { return e.path }
198+
199+
func (e *scpEndpoint) String() string {
200+
var user string
201+
if e.user != "" {
202+
user = fmt.Sprintf("%s@", e.user)
203+
}
204+
205+
return fmt.Sprintf("%s%s:%s", user, e.host, e.path)
206+
}
207+
208+
type fileEndpoint struct {
209+
path string
210+
}
211+
212+
func (e *fileEndpoint) Protocol() string { return "file" }
213+
func (e *fileEndpoint) User() string { return "" }
214+
func (e *fileEndpoint) Password() string { return "" }
215+
func (e *fileEndpoint) Host() string { return "" }
216+
func (e *fileEndpoint) Port() int { return 0 }
217+
func (e *fileEndpoint) Path() string { return e.path }
218+
func (e *fileEndpoint) String() string { return e.path }
219+
220+
var (
221+
isSchemeRegExp = regexp.MustCompile(`^[^:]+://`)
222+
scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P<user>[^@]+)@)?(?P<host>[^:\s]+):(?P<path>[^\\].*)$`)
223+
)
224+
225+
func parseSCPLike(endpoint string) (Endpoint, bool) {
226+
if isSchemeRegExp.MatchString(endpoint) || !scpLikeUrlRegExp.MatchString(endpoint) {
227+
return nil, false
228+
}
229+
230+
m := scpLikeUrlRegExp.FindStringSubmatch(endpoint)
231+
return &scpEndpoint{
232+
user: m[1],
233+
host: m[2],
234+
path: m[3],
235+
}, true
118236
}
119237

120-
func transformSCPLikeIfNeeded(endpoint string) string {
121-
if !isSchemeRegExp.MatchString(endpoint) && scpLikeUrlRegExp.MatchString(endpoint) {
122-
m := scpLikeUrlRegExp.FindStringSubmatch(endpoint)
123-
return fmt.Sprintf("ssh://%s%s/%s", m[1], m[2], m[3])
238+
func parseFile(endpoint string) (Endpoint, bool) {
239+
if isSchemeRegExp.MatchString(endpoint) {
240+
return nil, false
124241
}
125242

126-
return endpoint
243+
path := endpoint
244+
return &fileEndpoint{path}, true
127245
}
128246

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

plumbing/transport/common_test.go

+102-6
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,118 @@ type SuiteCommon struct{}
1414

1515
var _ = Suite(&SuiteCommon{})
1616

17-
func (s *SuiteCommon) TestNewEndpoint(c *C) {
17+
func (s *SuiteCommon) TestNewEndpointHTTP(c *C) {
18+
e, err := NewEndpoint("http://git:[email protected]/user/repository.git?foo#bar")
19+
c.Assert(err, IsNil)
20+
c.Assert(e.Protocol(), Equals, "http")
21+
c.Assert(e.User(), Equals, "git")
22+
c.Assert(e.Password(), Equals, "pass")
23+
c.Assert(e.Host(), Equals, "github.com")
24+
c.Assert(e.Port(), Equals, 0)
25+
c.Assert(e.Path(), Equals, "/user/repository.git?foo#bar")
26+
c.Assert(e.String(), Equals, "http://git:[email protected]/user/repository.git?foo#bar")
27+
}
28+
29+
func (s *SuiteCommon) TestNewEndpointSSH(c *C) {
1830
e, err := NewEndpoint("ssh://[email protected]/user/repository.git")
1931
c.Assert(err, IsNil)
32+
c.Assert(e.Protocol(), Equals, "ssh")
33+
c.Assert(e.User(), Equals, "git")
34+
c.Assert(e.Password(), Equals, "")
35+
c.Assert(e.Host(), Equals, "github.com")
36+
c.Assert(e.Port(), Equals, 0)
37+
c.Assert(e.Path(), Equals, "/user/repository.git")
2038
c.Assert(e.String(), Equals, "ssh://[email protected]/user/repository.git")
2139
}
2240

41+
func (s *SuiteCommon) TestNewEndpointSSHNoUser(c *C) {
42+
e, err := NewEndpoint("ssh://github.com/user/repository.git")
43+
c.Assert(err, IsNil)
44+
c.Assert(e.Protocol(), Equals, "ssh")
45+
c.Assert(e.User(), Equals, "")
46+
c.Assert(e.Password(), Equals, "")
47+
c.Assert(e.Host(), Equals, "github.com")
48+
c.Assert(e.Port(), Equals, 0)
49+
c.Assert(e.Path(), Equals, "/user/repository.git")
50+
c.Assert(e.String(), Equals, "ssh://github.com/user/repository.git")
51+
}
52+
53+
func (s *SuiteCommon) TestNewEndpointSSHWithPort(c *C) {
54+
e, err := NewEndpoint("ssh://[email protected]:777/user/repository.git")
55+
c.Assert(err, IsNil)
56+
c.Assert(e.Protocol(), Equals, "ssh")
57+
c.Assert(e.User(), Equals, "git")
58+
c.Assert(e.Password(), Equals, "")
59+
c.Assert(e.Host(), Equals, "github.com")
60+
c.Assert(e.Port(), Equals, 777)
61+
c.Assert(e.Path(), Equals, "/user/repository.git")
62+
c.Assert(e.String(), Equals, "ssh://[email protected]:777/user/repository.git")
63+
}
64+
2365
func (s *SuiteCommon) TestNewEndpointSCPLike(c *C) {
2466
e, err := NewEndpoint("[email protected]:user/repository.git")
2567
c.Assert(err, IsNil)
26-
c.Assert(e.String(), Equals, "ssh://[email protected]/user/repository.git")
68+
c.Assert(e.Protocol(), Equals, "ssh")
69+
c.Assert(e.User(), Equals, "git")
70+
c.Assert(e.Password(), Equals, "")
71+
c.Assert(e.Host(), Equals, "github.com")
72+
c.Assert(e.Port(), Equals, 22)
73+
c.Assert(e.Path(), Equals, "user/repository.git")
74+
c.Assert(e.String(), Equals, "[email protected]:user/repository.git")
75+
}
76+
77+
func (s *SuiteCommon) TestNewEndpointFileAbs(c *C) {
78+
e, err := NewEndpoint("/foo.git")
79+
c.Assert(err, IsNil)
80+
c.Assert(e.Protocol(), Equals, "file")
81+
c.Assert(e.User(), Equals, "")
82+
c.Assert(e.Password(), Equals, "")
83+
c.Assert(e.Host(), Equals, "")
84+
c.Assert(e.Port(), Equals, 0)
85+
c.Assert(e.Path(), Equals, "/foo.git")
86+
c.Assert(e.String(), Equals, "/foo.git")
87+
}
88+
89+
func (s *SuiteCommon) TestNewEndpointFileRel(c *C) {
90+
e, err := NewEndpoint("foo.git")
91+
c.Assert(err, IsNil)
92+
c.Assert(e.Protocol(), Equals, "file")
93+
c.Assert(e.User(), Equals, "")
94+
c.Assert(e.Password(), Equals, "")
95+
c.Assert(e.Host(), Equals, "")
96+
c.Assert(e.Port(), Equals, 0)
97+
c.Assert(e.Path(), Equals, "foo.git")
98+
c.Assert(e.String(), Equals, "foo.git")
99+
}
100+
101+
func (s *SuiteCommon) TestNewEndpointFileWindows(c *C) {
102+
e, err := NewEndpoint("C:\\foo.git")
103+
c.Assert(err, IsNil)
104+
c.Assert(e.Protocol(), Equals, "file")
105+
c.Assert(e.User(), Equals, "")
106+
c.Assert(e.Password(), Equals, "")
107+
c.Assert(e.Host(), Equals, "")
108+
c.Assert(e.Port(), Equals, 0)
109+
c.Assert(e.Path(), Equals, "C:\\foo.git")
110+
c.Assert(e.String(), Equals, "C:\\foo.git")
111+
}
112+
113+
func (s *SuiteCommon) TestNewEndpointFileURL(c *C) {
114+
e, err := NewEndpoint("file:///foo.git")
115+
c.Assert(err, IsNil)
116+
c.Assert(e.Protocol(), Equals, "file")
117+
c.Assert(e.User(), Equals, "")
118+
c.Assert(e.Password(), Equals, "")
119+
c.Assert(e.Host(), Equals, "")
120+
c.Assert(e.Port(), Equals, 0)
121+
c.Assert(e.Path(), Equals, "/foo.git")
122+
c.Assert(e.String(), Equals, "file:///foo.git")
27123
}
28124

29-
func (s *SuiteCommon) TestNewEndpointWrongForgat(c *C) {
30-
e, err := NewEndpoint("foo")
31-
c.Assert(err, Not(IsNil))
32-
c.Assert(e.Host, Equals, "")
125+
func (s *SuiteCommon) TestNewEndpointInvalidURL(c *C) {
126+
e, err := NewEndpoint("http://\\")
127+
c.Assert(err, NotNil)
128+
c.Assert(e, IsNil)
33129
}
34130

35131
func (s *SuiteCommon) TestFilterUnsupportedCapabilities(c *C) {

plumbing/transport/file/client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthM
4141
return nil, err
4242
}
4343

44-
return &command{cmd: exec.Command(cmd, ep.Path)}, nil
44+
return &command{cmd: exec.Command(cmd, ep.Path())}, nil
4545
}
4646

4747
type command struct {

0 commit comments

Comments
 (0)