github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/url/url.go (about)

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