diff --git a/pkg/loader/fileloader.go b/pkg/loader/fileloader.go index 052c8cc15..e39515606 100644 --- a/pkg/loader/fileloader.go +++ b/pkg/loader/fileloader.go @@ -110,7 +110,7 @@ func (l *fileLoader) Root() string { func newLoaderOrDie(fSys fs.FileSystem, path string) *fileLoader { l, err := newFileLoaderAt( - path, fSys, []string{}, hashicorpGitCloner) + path, fSys, []string{}, clonerToUse()) if err != nil { log.Fatalf("unable to make loader at '%s'; %v", path, err) } diff --git a/pkg/loader/gitcloner.go b/pkg/loader/gitcloner.go index ad59b5e8c..1306e9f4a 100644 --- a/pkg/loader/gitcloner.go +++ b/pkg/loader/gitcloner.go @@ -17,8 +17,11 @@ limitations under the License. package loader import ( + "bytes" + "github.com/pkg/errors" "io/ioutil" "os" + "os/exec" "path/filepath" "strings" @@ -35,22 +38,69 @@ type gitCloner func(url string) ( // Any error encountered when cloning. err error) -// isRepoUrl checks if a string is a repo Url -func isRepoUrl(s string) bool { - if strings.HasPrefix(s, "https://") { - return true - } - if strings.HasPrefix(s, "git::") { - return true - } - host := strings.SplitN(s, "/", 2)[0] - return strings.Contains(host, ".com") || strings.Contains(host, ".org") +// isRepoUrl checks if a string is likely a github repo Url. +func isRepoUrl(arg string) bool { + arg = strings.ToLower(arg) + return !filepath.IsAbs(arg) && + (strings.HasPrefix(arg, "git::") || + strings.HasPrefix(arg, "gh:") || + strings.HasPrefix(arg, "github.com") || + strings.HasPrefix(arg, "git@github.com:") || + strings.Index(arg, "github.com/") > -1) } func makeTmpDir() (string, error) { return ioutil.TempDir("", "kustomize-") } +func simpleGitCloner(spec string) ( + checkoutDir string, pathInCoDir string, err error) { + gitProgram, err := exec.LookPath("git") + if err != nil { + return "", "", errors.Wrap(err, "no 'git' program on path") + } + checkoutDir, err = makeTmpDir() + if err != nil { + return + } + url, pathInCoDir, err := extractGithubRepoName(spec) + cmd := exec.Command(gitProgram, "clone", url, checkoutDir) + var out bytes.Buffer + cmd.Stdout = &out + err = cmd.Run() + if err != nil { + return "", "", errors.Wrapf(err, "trouble cloning %s", spec) + } + return +} + +// From strings like git@github.com:someOrg/someRepo.git or +// https://github.com/someOrg/someRepo, extract path. +func extractGithubRepoName(n string) (string, string, error) { + for _, p := range []string{ + // Order matters here. + "git::", "gh:", "https://", "http://", + "git@", "github.com:", "github.com/", "gitlab.com/"} { + if strings.ToLower(n[:len(p)]) == p { + n = n[len(p):] + } + } + if strings.HasSuffix(n, ".git") { + n = n[0 : len(n)-len(".git")] + } + i := strings.Index(n, string(filepath.Separator)) + if i < 1 { + return "", "", errors.New("no separator") + } + j := strings.Index(n[i+1:], string(filepath.Separator)) + if j < 0 { + // No path, so show entire repo. + return n, "", nil + } + j += i + 1 + return n[:j], n[j+1:], nil +} + func hashicorpGitCloner(repoUrl string) ( checkoutDir string, pathInCoDir string, err error) { dir, err := makeTmpDir() diff --git a/pkg/loader/gitcloner_test.go b/pkg/loader/gitcloner_test.go index 1b1ac002a..fdd5c3194 100644 --- a/pkg/loader/gitcloner_test.go +++ b/pkg/loader/gitcloner_test.go @@ -17,6 +17,8 @@ limitations under the License. package loader import ( + "fmt" + "path/filepath" "strings" "testing" @@ -38,6 +40,14 @@ func TestIsRepoURL(t *testing.T) { input: "github.com/org/repo", expected: true, }, + { + input: "git@github.com:org/repo", + expected: true, + }, + { + input: "gh:org/repo", + expected: true, + }, { input: "git::https://gitlab.com/org/repo", expected: true, @@ -168,3 +178,52 @@ whatever coRoot+"/"+pathInRepo, l2.Root()) } } + +var repoNames = []string{"someOrg/someRepo", "kubernetes/website"} + +var paths = []string{"", "README.md", "foo/index.md"} + +var extractFmts = []string{ + "gh:%s", + "GH:%s", + "gitHub.com/%s", + "https://github.com/%s", + "hTTps://github.com/%s", + "git::https://gitlab.com/%s", + "git@gitHUB.com:%s.git", + "github.com:%s", +} + +func TestExtractGithubRepoName(t *testing.T) { + for _, repoName := range repoNames { + for _, pathName := range paths { + for _, extractFmt := range extractFmts { + spec := repoName + if len(pathName) > 0 { + spec = filepath.Join(spec, pathName) + } + input := fmt.Sprintf(extractFmt, spec) + if !isRepoUrl(input) { + t.Errorf("Should smell like github arg: %s\n", input) + continue + } + repo, path, err := extractGithubRepoName(input) + if err != nil { + t.Errorf("problem %v", err) + } + if repo != repoName { + t.Errorf("\n"+ + " from %s\n"+ + " gotRepo %s\n"+ + "desiredRepo %s\n", input, repo, repoName) + } + if path != pathName { + t.Errorf("\n"+ + " from %s\n"+ + " gotPath %s\n"+ + "desiredPath %s\n", input, path, pathName) + } + } + } + } +} diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index ba97a0040..c5491fccf 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -22,12 +22,23 @@ import ( "sigs.k8s.io/kustomize/pkg/ifc" ) +const useHashiCorpCloner = true + +func clonerToUse() gitCloner { + if useHashiCorpCloner { + return hashicorpGitCloner + } + return simpleGitCloner +} + +// var clonerToUse = simpleGitCloner + // NewLoader returns a Loader. func NewLoader(root string, fSys fs.FileSystem) (ifc.Loader, error) { if isRepoUrl(root) { return newGitLoader( - root, fSys, []string{}, hashicorpGitCloner) + root, fSys, []string{}, clonerToUse()) } return newFileLoaderAt( - root, fSys, []string{}, hashicorpGitCloner) + root, fSys, []string{}, clonerToUse()) }