1313package transport
1414
1515import (
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.
4648type 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
5355type 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-
228227var (
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