Skip to content

Commit 52b6d13

Browse files
committed
support ipv6 for git url parse
1 parent da038e4 commit 52b6d13

File tree

3 files changed

+141
-34
lines changed

3 files changed

+141
-34
lines changed

modules/git/remote.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package git
77
import (
88
"context"
99

10-
"code.gitea.io/gitea/modules/git/url"
10+
giturl "code.gitea.io/gitea/modules/git/url"
1111
)
1212

1313
// GetRemoteURL returns remote url of git repository in the repoPath with special remote name
@@ -35,10 +35,10 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (string, err
3535
}
3636

3737
// GetRemoteAddress returns the url of a specific remote of the repository.
38-
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) {
38+
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*giturl.GitURL, error) {
3939
result, err := GetRemoteURL(ctx, repoPath, remoteName)
4040
if err != nil {
4141
return nil, err
4242
}
43-
return url.Parse(result)
43+
return giturl.Parse(result)
4444
}

modules/git/url/url.go

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@ package url
66

77
import (
88
"fmt"
9-
"net/url"
109
stdurl "net/url"
11-
"regexp"
1210
"strings"
1311
)
1412

15-
// URL represents a git remote URL
16-
type URL struct {
13+
// ErrWrongURLFormat represents an error with wrong url format
14+
type ErrWrongURLFormat struct {
15+
URL string
16+
}
17+
18+
func (err ErrWrongURLFormat) Error() string {
19+
return fmt.Sprintf("git URL %s format is wrong", err.URL)
20+
}
21+
22+
// GitURL represents a git URL
23+
type GitURL struct {
1724
*stdurl.URL
1825
extraMark int // 0 no extra 1 scp 2 file path with no prefix
1926
}
2027

2128
// String returns the URL's string
22-
func (u *URL) String() string {
29+
func (u *GitURL) String() string {
2330
switch u.extraMark {
2431
case 0:
2532
return u.String()
@@ -32,31 +39,48 @@ func (u *URL) String() string {
3239
}
3340
}
3441

35-
var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9-._~]+)@([a-zA-Z0-9._-]+):(.*)$`)
36-
37-
// Parse parse all kinds of git remote URL
38-
func Parse(remote string) (*URL, error) {
42+
// Parse parse all kinds of git URL
43+
func Parse(remote string) (*GitURL, error) {
3944
if strings.Contains(remote, "://") {
4045
u, err := stdurl.Parse(remote)
4146
if err != nil {
4247
return nil, err
4348
}
44-
return &URL{URL: u}, nil
45-
}
46-
47-
if results := scpSyntaxRe.FindStringSubmatch(remote); results != nil {
48-
return &URL{
49-
URL: &stdurl.URL{
50-
Scheme: "ssh",
51-
User: url.User(results[1]),
52-
Host: results[2],
53-
Path: results[3],
54-
},
49+
return &GitURL{URL: u}, nil
50+
} else if strings.Contains(remote, "@") && strings.Contains(remote, ":") {
51+
url := stdurl.URL{
52+
Scheme: "ssh",
53+
}
54+
squareBrackets := false
55+
lastIndex := -1
56+
FOR:
57+
for i := 0; i < len(remote); i++ {
58+
switch remote[i] {
59+
case '@':
60+
url.User = stdurl.User(remote[:i])
61+
lastIndex = i + 1
62+
case ':':
63+
if !squareBrackets {
64+
url.Host = remote[lastIndex:i]
65+
if len(remote) <= i+1 {
66+
return nil, ErrWrongURLFormat{URL: remote}
67+
}
68+
url.Path = remote[i+1:]
69+
break FOR
70+
}
71+
case '[':
72+
squareBrackets = true
73+
case ']':
74+
squareBrackets = false
75+
}
76+
}
77+
return &GitURL{
78+
URL: &url,
5579
extraMark: 1,
5680
}, nil
5781
}
5882

59-
return &URL{
83+
return &GitURL{
6084
URL: &stdurl.URL{
6185
Scheme: "file",
6286
Path: remote,

modules/git/url/url_test.go

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,50 @@ import (
1111
"github.com/stretchr/testify/assert"
1212
)
1313

14-
func TestParseURL(t *testing.T) {
14+
func TestParseGitURLs(t *testing.T) {
1515
kases := []struct {
1616
kase string
17-
expected *URL
17+
expected *GitURL
1818
}{
19+
{
20+
kase: "[email protected]:go-gitea/gitea.git",
21+
expected: &GitURL{
22+
URL: &url.URL{
23+
Scheme: "ssh",
24+
User: url.User("git"),
25+
Host: "127.0.0.1",
26+
Path: "go-gitea/gitea.git",
27+
},
28+
extraMark: 1,
29+
},
30+
},
31+
{
32+
kase: "git@[fe80:14fc:cec5:c174:d88%2510]:go-gitea/gitea.git",
33+
expected: &GitURL{
34+
URL: &url.URL{
35+
Scheme: "ssh",
36+
User: url.User("git"),
37+
Host: "[fe80:14fc:cec5:c174:d88%2510]",
38+
Path: "go-gitea/gitea.git",
39+
},
40+
extraMark: 1,
41+
},
42+
},
43+
{
44+
kase: "git@[::1]:go-gitea/gitea.git",
45+
expected: &GitURL{
46+
URL: &url.URL{
47+
Scheme: "ssh",
48+
User: url.User("git"),
49+
Host: "[::1]",
50+
Path: "go-gitea/gitea.git",
51+
},
52+
extraMark: 1,
53+
},
54+
},
1955
{
2056
kase: "[email protected]:go-gitea/gitea.git",
21-
expected: &URL{
57+
expected: &GitURL{
2258
URL: &url.URL{
2359
Scheme: "ssh",
2460
User: url.User("git"),
@@ -28,19 +64,53 @@ func TestParseURL(t *testing.T) {
2864
extraMark: 1,
2965
},
3066
},
67+
{
68+
kase: "ssh://[email protected]/go-gitea/gitea.git",
69+
expected: &GitURL{
70+
URL: &url.URL{
71+
Scheme: "ssh",
72+
User: url.User("git"),
73+
Host: "github.com",
74+
Path: "/go-gitea/gitea.git",
75+
},
76+
extraMark: 0,
77+
},
78+
},
79+
{
80+
kase: "ssh://git@[::1]/go-gitea/gitea.git",
81+
expected: &GitURL{
82+
URL: &url.URL{
83+
Scheme: "ssh",
84+
User: url.User("git"),
85+
Host: "[::1]",
86+
Path: "/go-gitea/gitea.git",
87+
},
88+
extraMark: 0,
89+
},
90+
},
3191
{
3292
kase: "/repositories/go-gitea/gitea.git",
33-
expected: &URL{
93+
expected: &GitURL{
3494
URL: &url.URL{
3595
Scheme: "file",
3696
Path: "/repositories/go-gitea/gitea.git",
3797
},
3898
extraMark: 2,
3999
},
40100
},
101+
{
102+
kase: "file:///repositories/go-gitea/gitea.git",
103+
expected: &GitURL{
104+
URL: &url.URL{
105+
Scheme: "file",
106+
Path: "/repositories/go-gitea/gitea.git",
107+
},
108+
extraMark: 0,
109+
},
110+
},
41111
{
42112
kase: "https://github.com/go-gitea/gitea.git",
43-
expected: &URL{
113+
expected: &GitURL{
44114
URL: &url.URL{
45115
Scheme: "https",
46116
Host: "github.com",
@@ -51,7 +121,7 @@ func TestParseURL(t *testing.T) {
51121
},
52122
{
53123
kase: "https://git:[email protected]/go-gitea/gitea.git",
54-
expected: &URL{
124+
expected: &GitURL{
55125
URL: &url.URL{
56126
Scheme: "https",
57127
Host: "github.com",
@@ -61,12 +131,25 @@ func TestParseURL(t *testing.T) {
61131
extraMark: 0,
62132
},
63133
},
134+
{
135+
kase: "git://github.com/go-gitea/gitea.git",
136+
expected: &GitURL{
137+
URL: &url.URL{
138+
Scheme: "git",
139+
Host: "github.com",
140+
Path: "/go-gitea/gitea.git",
141+
},
142+
extraMark: 0,
143+
},
144+
},
64145
}
65146

66147
for _, kase := range kases {
67-
u, err := Parse(kase.kase)
68-
assert.NoError(t, err)
69-
assert.EqualValues(t, kase.expected.extraMark, u.extraMark)
70-
assert.EqualValues(t, *kase.expected, *u)
148+
t.Run(kase.kase, func(t *testing.T) {
149+
u, err := Parse(kase.kase)
150+
assert.NoError(t, err)
151+
assert.EqualValues(t, kase.expected.extraMark, u.extraMark)
152+
assert.EqualValues(t, *kase.expected, *u)
153+
})
71154
}
72155
}

0 commit comments

Comments
 (0)