code.gitea.io/gitea@v1.19.3/modules/git/submodule.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // Copyright 2015 The Gogs Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package git
     6  
     7  import (
     8  	"fmt"
     9  	"net"
    10  	"net/url"
    11  	"path"
    12  	"regexp"
    13  	"strings"
    14  )
    15  
    16  var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`)
    17  
    18  // SubModule submodule is a reference on git repository
    19  type SubModule struct {
    20  	Name string
    21  	URL  string
    22  }
    23  
    24  // SubModuleFile represents a file with submodule type.
    25  type SubModuleFile struct {
    26  	*Commit
    27  
    28  	refURL string
    29  	refID  string
    30  }
    31  
    32  // NewSubModuleFile create a new submodule file
    33  func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
    34  	return &SubModuleFile{
    35  		Commit: c,
    36  		refURL: refURL,
    37  		refID:  refID,
    38  	}
    39  }
    40  
    41  func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string {
    42  	if refURL == "" {
    43  		return ""
    44  	}
    45  
    46  	refURI := strings.TrimSuffix(refURL, ".git")
    47  
    48  	prefixURL, _ := url.Parse(urlPrefix)
    49  	urlPrefixHostname, _, err := net.SplitHostPort(prefixURL.Host)
    50  	if err != nil {
    51  		urlPrefixHostname = prefixURL.Host
    52  	}
    53  
    54  	urlPrefix = strings.TrimSuffix(urlPrefix, "/")
    55  
    56  	// FIXME: Need to consider branch - which will require changes in modules/git/commit.go:GetSubModules
    57  	// Relative url prefix check (according to git submodule documentation)
    58  	if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") {
    59  		return urlPrefix + path.Clean(path.Join("/", repoFullName, refURI))
    60  	}
    61  
    62  	if !strings.Contains(refURI, "://") {
    63  		// scp style syntax which contains *no* port number after the : (and is not parsed by net/url)
    64  		// ex: git@try.gitea.io:go-gitea/gitea
    65  		match := scpSyntax.FindAllStringSubmatch(refURI, -1)
    66  		if len(match) > 0 {
    67  
    68  			m := match[0]
    69  			refHostname := m[2]
    70  			pth := m[3]
    71  
    72  			if !strings.HasPrefix(pth, "/") {
    73  				pth = "/" + pth
    74  			}
    75  
    76  			if urlPrefixHostname == refHostname || refHostname == sshDomain {
    77  				return urlPrefix + path.Clean(path.Join("/", pth))
    78  			}
    79  			return "http://" + refHostname + pth
    80  		}
    81  	}
    82  
    83  	ref, err := url.Parse(refURI)
    84  	if err != nil {
    85  		return ""
    86  	}
    87  
    88  	refHostname, _, err := net.SplitHostPort(ref.Host)
    89  	if err != nil {
    90  		refHostname = ref.Host
    91  	}
    92  
    93  	supportedSchemes := []string{"http", "https", "git", "ssh", "git+ssh"}
    94  
    95  	for _, scheme := range supportedSchemes {
    96  		if ref.Scheme == scheme {
    97  			if ref.Scheme == "http" || ref.Scheme == "https" {
    98  				if len(ref.User.Username()) > 0 {
    99  					return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path
   100  				}
   101  				return ref.Scheme + "://" + ref.Host + ref.Path
   102  			} else if urlPrefixHostname == refHostname || refHostname == sshDomain {
   103  				return urlPrefix + path.Clean(path.Join("/", ref.Path))
   104  			} else {
   105  				return "http://" + refHostname + ref.Path
   106  			}
   107  		}
   108  	}
   109  
   110  	return ""
   111  }
   112  
   113  // RefURL guesses and returns reference URL.
   114  func (sf *SubModuleFile) RefURL(urlPrefix, repoFullName, sshDomain string) string {
   115  	return getRefURL(sf.refURL, urlPrefix, repoFullName, sshDomain)
   116  }
   117  
   118  // RefID returns reference ID.
   119  func (sf *SubModuleFile) RefID() string {
   120  	return sf.refID
   121  }