diff --git a/pkg/git/repository.go b/pkg/git/repository.go index b8247b84..7d3dc6f7 100644 --- a/pkg/git/repository.go +++ b/pkg/git/repository.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "net/url" "os" "strings" @@ -57,6 +58,11 @@ type ( } ) +const ( + gitSuffix = ".git" + gitDelimiter = "_git/" +) + // Errors var ( ErrNilOpts = errors.New("options cannot be nil") @@ -116,7 +122,7 @@ func (o *CloneOptions) Parse() { suffix string ) - host, orgRepo, o.path, o.revision, suffix = util.ParseGitUrl(o.Repo) + host, orgRepo, o.path, o.revision, suffix = parseGitUrl(o.Repo) o.url = host + orgRepo + suffix } @@ -281,3 +287,132 @@ func getAuth(auth Auth) transport.AuthMethod { Password: auth.Password, } } + +// From strings like git@github.com:someOrg/someRepo.git or +// https://github.com/someOrg/someRepo?ref=someHash, extract +// the parts. +func parseGitUrl(n string) (host, orgRepo, path, ref, gitSuff string) { + if strings.Contains(n, gitDelimiter) { + index := strings.Index(n, gitDelimiter) + // Adding _git/ to host + host = normalizeGitHostSpec(n[:index+len(gitDelimiter)]) + orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0] + path, ref = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):]) + return + } + + host, n = parseHostSpec(n) + gitSuff = gitSuffix + if strings.Contains(n, gitSuffix) { + index := strings.Index(n, gitSuffix) + orgRepo = n[0:index] + n = n[index+len(gitSuffix):] + path, ref = peelQuery(n) + return + } + + i := strings.Index(n, "/") + if i < 1 { + path, ref = peelQuery(n) + return + } + + j := strings.Index(n[i+1:], "/") + if j >= 0 { + j += i + 1 + orgRepo = n[:j] + path, ref = peelQuery(n[j+1:]) + return + } + + path = "" + orgRepo, ref = peelQuery(n) + return +} + +func peelQuery(arg string) (path, ref string) { + parsed, err := url.Parse(arg) + if err != nil { + return path, "" + } + + path = parsed.Path + values := parsed.Query() + branch := values.Get("ref") + tag := values.Get("tag") + sha := values.Get("sha") + if sha != "" { + ref = sha + return + } + + if tag != "" { + ref = "refs/tags/" + tag + return + } + + if branch != "" { + ref = "refs/heads/" + branch + return + } + + return +} + +func parseHostSpec(n string) (string, string) { + var host string + // Start accumulating the host part. + for _, p := range [...]string{ + // Order matters here. + "git::", "gh:", "ssh://", "https://", "http://", + "git@", "github.com:", "github.com/"} { + if len(p) < len(n) && strings.ToLower(n[:len(p)]) == p { + n = n[len(p):] + host += p + } + } + if host == "git@" { + i := strings.Index(n, "/") + if i > -1 { + host += n[:i+1] + n = n[i+1:] + } else { + i = strings.Index(n, ":") + if i > -1 { + host += n[:i+1] + n = n[i+1:] + } + } + return host, n + } + + // If host is a http(s) or ssh URL, grab the domain part. + for _, p := range [...]string{ + "ssh://", "https://", "http://"} { + if strings.HasSuffix(host, p) { + i := strings.Index(n, "/") + if i > -1 { + host = host + n[0:i+1] + n = n[i+1:] + } + break + } + } + + return normalizeGitHostSpec(host), n +} + +func normalizeGitHostSpec(host string) string { + s := strings.ToLower(host) + if strings.Contains(s, "github.com") { + if strings.Contains(s, "git@") || strings.Contains(s, "ssh:") { + host = "git@github.com:" + } else { + host = "https://github.com/" + } + } + if strings.HasPrefix(s, "git::") { + host = strings.TrimPrefix(s, "git::") + } + return host +} diff --git a/pkg/util/repospec_test.go b/pkg/git/repospec_test.go similarity index 97% rename from pkg/util/repospec_test.go rename to pkg/git/repospec_test.go index cd6b2100..53f8678c 100644 --- a/pkg/util/repospec_test.go +++ b/pkg/git/repospec_test.go @@ -4,7 +4,7 @@ // Copyright 2019 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0 -package util +package git import ( "fmt" @@ -57,16 +57,19 @@ func TestNewRepoSpecFromUrl(t *testing.T) { for _, pathName := range pathNames { for _, hrefArg := range hrefArgs { uri := makeUrl(hostRaw, orgRepo, pathName, hrefArg) - host, org, path, ref, _ := ParseGitUrl(uri) + host, org, path, ref, _ := parseGitUrl(uri) if host != hostSpec { bad = append(bad, []string{"host", uri, host, hostSpec}) } + if org != orgRepo { bad = append(bad, []string{"orgRepo", uri, orgRepo, orgRepo}) } + if path != pathName { bad = append(bad, []string{"path", uri, path, pathName}) } + if hrefArg != "" && ref != "refs/heads/"+hrefArg { bad = append(bad, []string{"ref", uri, ref, hrefArg}) } @@ -74,6 +77,7 @@ func TestNewRepoSpecFromUrl(t *testing.T) { } } } + if len(bad) > 0 { for _, tuple := range bad { fmt.Printf("\n"+ @@ -139,7 +143,7 @@ func TestNewRepoSpecFromUrl_CloneSpecs(t *testing.T) { }, } for _, testcase := range testcases { - host, orgRepo, path, ref, suffix := ParseGitUrl(testcase.input) + host, orgRepo, path, ref, suffix := parseGitUrl(testcase.input) cloneSpec := host + orgRepo + suffix if cloneSpec != testcase.cloneSpec { t.Errorf("CloneSpec expected to be %v, but got %v on %s", testcase.cloneSpec, cloneSpec, testcase.input) diff --git a/pkg/util/repospec.go b/pkg/util/repospec.go deleted file mode 100644 index 757bf324..00000000 --- a/pkg/util/repospec.go +++ /dev/null @@ -1,145 +0,0 @@ -// The following file was copied from https://github.com/kubernetes-sigs/kustomize/blob/master/api/internal/git/repospec.go -// and modified to expose the ParseGitUrl function - -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package util - -import ( - "net/url" - "strings" - "time" -) - -const ( - gitSuffix = ".git" - gitDelimiter = "_git/" -) - -// From strings like git@github.com:someOrg/someRepo.git or -// https://github.com/someOrg/someRepo?ref=someHash, extract -// the parts. -func ParseGitUrl(n string) (host, orgRepo, path, ref, gitSuff string) { - if strings.Contains(n, gitDelimiter) { - index := strings.Index(n, gitDelimiter) - // Adding _git/ to host - host = normalizeGitHostSpec(n[:index+len(gitDelimiter)]) - orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0] - path, ref = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):]) - return - } - - host, n = parseHostSpec(n) - gitSuff = gitSuffix - if strings.Contains(n, gitSuffix) { - index := strings.Index(n, gitSuffix) - orgRepo = n[0:index] - n = n[index+len(gitSuffix):] - path, ref = peelQuery(n) - return - } - - i := strings.Index(n, "/") - if i < 1 { - path, ref = peelQuery(n) - return - } - - j := strings.Index(n[i+1:], "/") - if j >= 0 { - j += i + 1 - orgRepo = n[:j] - path, ref = peelQuery(n[j+1:]) - return - } - - path = "" - orgRepo, ref = peelQuery(n) - return -} - -// Clone git submodules by default. -const defaultSubmodules = true - -// Arbitrary, but non-infinite, timeout for running commands. -const defaultTimeout = 27 * time.Second - -func peelQuery(arg string) (path, ref string) { - parsed, err := url.Parse(arg) - if err != nil { - return path, "" - } - - values := parsed.Query() - branch := values.Get("ref") - tag := values.Get("tag") - sha := values.Get("sha") - if sha != "" { - ref = sha - } else if tag != "" { - ref = "refs/tags/" + tag - } else if branch != "" { - ref = "refs/heads/" + branch - } - - return parsed.Path, ref -} - -func parseHostSpec(n string) (string, string) { - var host string - // Start accumulating the host part. - for _, p := range [...]string{ - // Order matters here. - "git::", "gh:", "ssh://", "https://", "http://", - "git@", "github.com:", "github.com/"} { - if len(p) < len(n) && strings.ToLower(n[:len(p)]) == p { - n = n[len(p):] - host += p - } - } - if host == "git@" { - i := strings.Index(n, "/") - if i > -1 { - host += n[:i+1] - n = n[i+1:] - } else { - i = strings.Index(n, ":") - if i > -1 { - host += n[:i+1] - n = n[i+1:] - } - } - return host, n - } - - // If host is a http(s) or ssh URL, grab the domain part. - for _, p := range [...]string{ - "ssh://", "https://", "http://"} { - if strings.HasSuffix(host, p) { - i := strings.Index(n, "/") - if i > -1 { - host = host + n[0:i+1] - n = n[i+1:] - } - break - } - } - - return normalizeGitHostSpec(host), n -} - -func normalizeGitHostSpec(host string) string { - s := strings.ToLower(host) - if strings.Contains(s, "github.com") { - if strings.Contains(s, "git@") || strings.Contains(s, "ssh:") { - host = "git@github.com:" - } else { - host = "https://github.com/" - } - } - if strings.HasPrefix(s, "git::") { - host = strings.TrimPrefix(s, "git::") - } - return host -}