mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Fix some mirror bugs (#18649)
* Fix some mirror bugs * Remove unnecessary code * Fix lint * rename stdard url * Allow more charactors in git ssh protocol url * improve the detection * support ipv6 for git url parse * Fix bug * Fix template * Fix bug * fix template * Fix tmpl * Fix tmpl * Fix parse ssh with interface * Rename functions name Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		| @@ -6,11 +6,12 @@ package git | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"net/url" | ||||
|  | ||||
| 	giturl "code.gitea.io/gitea/modules/git/url" | ||||
| ) | ||||
|  | ||||
| // GetRemoteAddress returns the url of a specific remote of the repository. | ||||
| func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) { | ||||
| // GetRemoteAddress returns remote url of git repository in the repoPath with special remote name | ||||
| func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) { | ||||
| 	var cmd *Command | ||||
| 	if CheckGitVersionAtLeast("2.7") == nil { | ||||
| 		cmd = NewCommand(ctx, "remote", "get-url", remoteName) | ||||
| @@ -20,11 +21,20 @@ func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.UR | ||||
|  | ||||
| 	result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if len(result) > 0 { | ||||
| 		result = result[:len(result)-1] | ||||
| 	} | ||||
| 	return url.Parse(result) | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // GetRemoteURL returns the url of a specific remote of the repository. | ||||
| func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.GitURL, error) { | ||||
| 	addr, err := GetRemoteAddress(ctx, repoPath, remoteName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return giturl.Parse(addr) | ||||
| } | ||||
|   | ||||
							
								
								
									
										90
									
								
								modules/git/url/url.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								modules/git/url/url.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| // Copyright 2022 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package url | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	stdurl "net/url" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ErrWrongURLFormat represents an error with wrong url format | ||||
| type ErrWrongURLFormat struct { | ||||
| 	URL string | ||||
| } | ||||
|  | ||||
| func (err ErrWrongURLFormat) Error() string { | ||||
| 	return fmt.Sprintf("git URL %s format is wrong", err.URL) | ||||
| } | ||||
|  | ||||
| // GitURL represents a git URL | ||||
| type GitURL struct { | ||||
| 	*stdurl.URL | ||||
| 	extraMark int // 0 no extra 1 scp 2 file path with no prefix | ||||
| } | ||||
|  | ||||
| // String returns the URL's string | ||||
| func (u *GitURL) String() string { | ||||
| 	switch u.extraMark { | ||||
| 	case 0: | ||||
| 		return u.URL.String() | ||||
| 	case 1: | ||||
| 		return fmt.Sprintf("%s@%s:%s", u.User.Username(), u.Host, u.Path) | ||||
| 	case 2: | ||||
| 		return u.Path | ||||
| 	default: | ||||
| 		return "" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Parse parse all kinds of git URL | ||||
| func Parse(remote string) (*GitURL, error) { | ||||
| 	if strings.Contains(remote, "://") { | ||||
| 		u, err := stdurl.Parse(remote) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &GitURL{URL: u}, nil | ||||
| 	} else if strings.Contains(remote, "@") && strings.Contains(remote, ":") { | ||||
| 		url := stdurl.URL{ | ||||
| 			Scheme: "ssh", | ||||
| 		} | ||||
| 		squareBrackets := false | ||||
| 		lastIndex := -1 | ||||
| 	FOR: | ||||
| 		for i := 0; i < len(remote); i++ { | ||||
| 			switch remote[i] { | ||||
| 			case '@': | ||||
| 				url.User = stdurl.User(remote[:i]) | ||||
| 				lastIndex = i + 1 | ||||
| 			case ':': | ||||
| 				if !squareBrackets { | ||||
| 					url.Host = strings.ReplaceAll(remote[lastIndex:i], "%25", "%") | ||||
| 					if len(remote) <= i+1 { | ||||
| 						return nil, ErrWrongURLFormat{URL: remote} | ||||
| 					} | ||||
| 					url.Path = remote[i+1:] | ||||
| 					break FOR | ||||
| 				} | ||||
| 			case '[': | ||||
| 				squareBrackets = true | ||||
| 			case ']': | ||||
| 				squareBrackets = false | ||||
| 			} | ||||
| 		} | ||||
| 		return &GitURL{ | ||||
| 			URL:       &url, | ||||
| 			extraMark: 1, | ||||
| 		}, nil | ||||
| 	} | ||||
|  | ||||
| 	return &GitURL{ | ||||
| 		URL: &stdurl.URL{ | ||||
| 			Scheme: "file", | ||||
| 			Path:   remote, | ||||
| 		}, | ||||
| 		extraMark: 2, | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										167
									
								
								modules/git/url/url_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								modules/git/url/url_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| // Copyright 2022 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package url | ||||
|  | ||||
| import ( | ||||
| 	"net/url" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestParseGitURLs(t *testing.T) { | ||||
| 	kases := []struct { | ||||
| 		kase     string | ||||
| 		expected *GitURL | ||||
| 	}{ | ||||
| 		{ | ||||
| 			kase: "git@127.0.0.1:go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "127.0.0.1", | ||||
| 					Path:   "go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "git@[fe80:14fc:cec5:c174:d88%2510]:go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "[fe80:14fc:cec5:c174:d88%10]", | ||||
| 					Path:   "go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "git@[::1]:go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "[::1]", | ||||
| 					Path:   "go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "git@github.com:go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "github.com", | ||||
| 					Path:   "go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "ssh://git@github.com/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "github.com", | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "ssh://git@[::1]/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "ssh", | ||||
| 					User:   url.User("git"), | ||||
| 					Host:   "[::1]", | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "/repositories/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "file", | ||||
| 					Path:   "/repositories/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 2, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "file:///repositories/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "file", | ||||
| 					Path:   "/repositories/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "https://github.com/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "https", | ||||
| 					Host:   "github.com", | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "https://git:git@github.com/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "https", | ||||
| 					Host:   "github.com", | ||||
| 					User:   url.UserPassword("git", "git"), | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			kase: "https://[fe80:14fc:cec5:c174:d88%2510]:20/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "https", | ||||
| 					Host:   "[fe80:14fc:cec5:c174:d88%10]:20", | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			kase: "git://github.com/go-gitea/gitea.git", | ||||
| 			expected: &GitURL{ | ||||
| 				URL: &url.URL{ | ||||
| 					Scheme: "git", | ||||
| 					Host:   "github.com", | ||||
| 					Path:   "/go-gitea/gitea.git", | ||||
| 				}, | ||||
| 				extraMark: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, kase := range kases { | ||||
| 		t.Run(kase.kase, func(t *testing.T) { | ||||
| 			u, err := Parse(kase.kase) | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.EqualValues(t, kase.expected.extraMark, u.extraMark) | ||||
| 			assert.EqualValues(t, *kase.expected, *u) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Lunny Xiao
					Lunny Xiao