code.gitea.io/gitea@v1.19.3/modules/git/url/url.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package url 5 6 import ( 7 "fmt" 8 stdurl "net/url" 9 "strings" 10 ) 11 12 // ErrWrongURLFormat represents an error with wrong url format 13 type ErrWrongURLFormat struct { 14 URL string 15 } 16 17 func (err ErrWrongURLFormat) Error() string { 18 return fmt.Sprintf("git URL %s format is wrong", err.URL) 19 } 20 21 // GitURL represents a git URL 22 type GitURL struct { 23 *stdurl.URL 24 extraMark int // 0 no extra 1 scp 2 file path with no prefix 25 } 26 27 // String returns the URL's string 28 func (u *GitURL) String() string { 29 switch u.extraMark { 30 case 0: 31 return u.URL.String() 32 case 1: 33 return fmt.Sprintf("%s@%s:%s", u.User.Username(), u.Host, u.Path) 34 case 2: 35 return u.Path 36 default: 37 return "" 38 } 39 } 40 41 // Parse parse all kinds of git URL 42 func Parse(remote string) (*GitURL, error) { 43 if strings.Contains(remote, "://") { 44 u, err := stdurl.Parse(remote) 45 if err != nil { 46 return nil, err 47 } 48 return &GitURL{URL: u}, nil 49 } else if strings.Contains(remote, "@") && strings.Contains(remote, ":") { 50 url := stdurl.URL{ 51 Scheme: "ssh", 52 } 53 squareBrackets := false 54 lastIndex := -1 55 FOR: 56 for i := 0; i < len(remote); i++ { 57 switch remote[i] { 58 case '@': 59 url.User = stdurl.User(remote[:i]) 60 lastIndex = i + 1 61 case ':': 62 if !squareBrackets { 63 url.Host = strings.ReplaceAll(remote[lastIndex:i], "%25", "%") 64 if len(remote) <= i+1 { 65 return nil, ErrWrongURLFormat{URL: remote} 66 } 67 url.Path = remote[i+1:] 68 break FOR 69 } 70 case '[': 71 squareBrackets = true 72 case ']': 73 squareBrackets = false 74 } 75 } 76 return &GitURL{ 77 URL: &url, 78 extraMark: 1, 79 }, nil 80 } 81 82 return &GitURL{ 83 URL: &stdurl.URL{ 84 Scheme: "file", 85 Path: remote, 86 }, 87 extraMark: 2, 88 }, nil 89 }