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  }