Move git code to its own pkg.

This commit is contained in:
jregan
2019-01-26 13:36:23 -08:00
parent d953eca630
commit 1d9a20b391
5 changed files with 129 additions and 128 deletions

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package loader package git
import ( import (
"bytes" "bytes"
@@ -27,8 +27,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// gitCloner is a function that can clone a git repo. // Cloner is a function that can clone a git repo.
type gitCloner func(url string) ( type Cloner func(url string) (
// Directory where the repo is cloned to. // Directory where the repo is cloned to.
checkoutDir string, checkoutDir string,
// Relative path in the checkoutDir to location // Relative path in the checkoutDir to location
@@ -37,8 +37,8 @@ type gitCloner func(url string) (
// Any error encountered when cloning. // Any error encountered when cloning.
err error) err error)
// isRepoUrl checks if a string is likely a github repo Url. // IsRepoUrl checks if a string is likely a github repo Url.
func isRepoUrl(arg string) bool { func IsRepoUrl(arg string) bool {
arg = strings.ToLower(arg) arg = strings.ToLower(arg)
return !filepath.IsAbs(arg) && return !filepath.IsAbs(arg) &&
(strings.HasPrefix(arg, "git::") || (strings.HasPrefix(arg, "git::") ||
@@ -54,7 +54,7 @@ func makeTmpDir() (string, error) {
return ioutil.TempDir("", "kustomize-") return ioutil.TempDir("", "kustomize-")
} }
func simpleGitCloner(spec string) ( func ClonerUsingGitExec(spec string) (
checkoutDir string, pathInCoDir string, err error) { checkoutDir string, pathInCoDir string, err error) {
gitProgram, err := exec.LookPath("git") gitProgram, err := exec.LookPath("git")
if err != nil { if err != nil {

View File

@@ -14,16 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package loader package git
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs"
) )
func TestIsRepoURL(t *testing.T) { func TestIsRepoURL(t *testing.T) {
@@ -98,107 +94,13 @@ func TestIsRepoURL(t *testing.T) {
}, },
} }
for _, tc := range testcases { for _, tc := range testcases {
actual := isRepoUrl(tc.input) actual := IsRepoUrl(tc.input)
if actual != tc.expected { if actual != tc.expected {
t.Errorf("unexpected error: unexpected result %t for input %s", actual, tc.input) t.Errorf("unexpected error: unexpected result %t for input %s", actual, tc.input)
} }
} }
} }
func splitOnNthSlash(v string, n int) (string, string) {
left := ""
for i := 0; i < n; i++ {
k := strings.Index(v, "/")
if k < 0 {
break
}
left = left + v[:k+1]
v = v[k+1:]
}
return left[:len(left)-1], v
}
func TestSplit(t *testing.T) {
path := "a/b/c/d/e/f/g"
if left, right := splitOnNthSlash(path, 2); left != "a/b" || right != "c/d/e/f/g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
if left, right := splitOnNthSlash(path, 3); left != "a/b/c" || right != "d/e/f/g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
if left, right := splitOnNthSlash(path, 6); left != "a/b/c/d/e/f" || right != "g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
}
// makeFakeGitCloner returns a cloner that ignores the
// URL argument and returns a path in a fake file system
// that should already hold the 'repo' contents.
func makeFakeGitCloner(t *testing.T, fSys fs.FileSystem, coRoot string) gitCloner {
if !fSys.IsDir(coRoot) {
t.Fatalf("expecting a directory at '%s'", coRoot)
}
return func(url string) (
checkoutDir string, pathInCoDir string, err error) {
_, path := splitOnNthSlash(url, 3)
if !fSys.IsDir(coRoot + "/" + path) {
t.Fatalf("expecting a directory at '%s'/'%s'",
coRoot, path)
}
return coRoot, path, nil
}
}
func TestGitLoader(t *testing.T) {
rootUrl := "github.com/someOrg/someRepo"
pathInRepo := "foo/base"
url := rootUrl + "/" + pathInRepo
if !isRepoUrl(url) {
t.Fatalf("'%s' should be accepted as a repo url", url)
}
coRoot := "/tmp"
fSys := fs.MakeFakeFS()
fSys.MkdirAll(coRoot)
fSys.MkdirAll(coRoot + "/" + pathInRepo)
fSys.WriteFile(
coRoot+"/"+pathInRepo+"/"+constants.KustomizationFileNames[0],
[]byte(`
whatever
`))
l, err := newGitLoader(
url, fSys, nil,
makeFakeGitCloner(t, fSys, coRoot))
if err != nil {
t.Fatalf("unexpected err: %v\n", err)
}
if coRoot+"/"+pathInRepo != l.Root() {
t.Fatalf("expected root '%s', got '%s'\n",
coRoot+"/"+pathInRepo, l.Root())
}
if _, err = l.New(url); err == nil {
t.Fatalf("expected cycle error 1")
}
if _, err = l.New(rootUrl + "/" + "foo"); err == nil {
t.Fatalf("expected cycle error 2")
}
pathInRepo = "foo/overlay"
fSys.MkdirAll(coRoot + "/" + pathInRepo)
url = rootUrl + "/" + pathInRepo
if !isRepoUrl(url) {
t.Fatalf("'%s' should be accepted as a repo url", url)
}
l2, err := l.New(url)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if coRoot+"/"+pathInRepo != l2.Root() {
t.Fatalf("expected root '%s', got '%s'\n",
coRoot+"/"+pathInRepo, l2.Root())
}
}
var repoNames = []string{"someOrg/someRepo", "kubernetes/website"} var repoNames = []string{"someOrg/someRepo", "kubernetes/website"}
var paths = []string{"README.md", "foo/krusty.txt", ""} var paths = []string{"README.md", "foo/krusty.txt", ""}
@@ -231,7 +133,7 @@ func TestParseGithubUrl(t *testing.T) {
if hrefArg != "" { if hrefArg != "" {
input = input + refQuery + hrefArg input = input + refQuery + hrefArg
} }
if !isRepoUrl(input) { if !IsRepoUrl(input) {
t.Errorf("Should smell like github arg: %s\n", input) t.Errorf("Should smell like github arg: %s\n", input)
continue continue
} }

View File

@@ -23,6 +23,7 @@ import (
"strings" "strings"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/git"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
) )
@@ -91,7 +92,7 @@ type fileLoader struct {
// File system utilities. // File system utilities.
fSys fs.FileSystem fSys fs.FileSystem
// Used to clone repositories. // Used to clone repositories.
cloner gitCloner cloner git.Cloner
// Used to clean up, as needed. // Used to clean up, as needed.
cleaner func() error cleaner func() error
} }
@@ -113,18 +114,18 @@ func (l *fileLoader) Root() string {
} }
func newLoaderOrDie(fSys fs.FileSystem, path string) *fileLoader { func newLoaderOrDie(fSys fs.FileSystem, path string) *fileLoader {
l, err := newFileLoaderAt( l, err := newLoaderAtConfirmedDir(
path, fSys, nil, simpleGitCloner) path, fSys, nil, git.ClonerUsingGitExec)
if err != nil { if err != nil {
log.Fatalf("unable to make loader at '%s'; %v", path, err) log.Fatalf("unable to make loader at '%s'; %v", path, err)
} }
return l return l
} }
// newFileLoaderAt returns a new fileLoader with given root. // newLoaderAtConfirmedDir returns a new fileLoader with given root.
func newFileLoaderAt( func newLoaderAtConfirmedDir(
possibleRoot string, fSys fs.FileSystem, possibleRoot string, fSys fs.FileSystem,
referrer *fileLoader, cloner gitCloner) (*fileLoader, error) { referrer *fileLoader, cloner git.Cloner) (*fileLoader, error) {
if possibleRoot == "" { if possibleRoot == "" {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"loader root cannot be empty") "loader root cannot be empty")
@@ -159,25 +160,25 @@ func (l *fileLoader) New(path string) (ifc.Loader, error) {
if path == "" { if path == "" {
return nil, fmt.Errorf("new root cannot be empty") return nil, fmt.Errorf("new root cannot be empty")
} }
if isRepoUrl(path) { if git.IsRepoUrl(path) {
// Avoid cycles. // Avoid cycles.
if err := l.errIfPreviouslySeenUri(path); err != nil { if err := l.errIfPreviouslySeenUri(path); err != nil {
return nil, err return nil, err
} }
return newGitLoader(path, l.fSys, l.referrer, l.cloner) return newLoaderAtGitClone(path, l.fSys, l.referrer, l.cloner)
} }
if filepath.IsAbs(path) { if filepath.IsAbs(path) {
return nil, fmt.Errorf("new root '%s' cannot be absolute", path) return nil, fmt.Errorf("new root '%s' cannot be absolute", path)
} }
return newFileLoaderAt( return newLoaderAtConfirmedDir(
l.root.Join(path), l.fSys, l, l.cloner) l.root.Join(path), l.fSys, l, l.cloner)
} }
// newGitLoader returns a new Loader pinned to a temporary // newLoaderAtGitClone returns a new Loader pinned to a temporary
// directory holding a cloned git repo. // directory holding a cloned git repo.
func newGitLoader( func newLoaderAtGitClone(
uri string, fSys fs.FileSystem, uri string, fSys fs.FileSystem,
referrer *fileLoader, cloner gitCloner) (ifc.Loader, error) { referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) {
tmpDirForRepo, pathInRepo, err := cloner(uri) tmpDirForRepo, pathInRepo, err := cloner(uri)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -25,6 +25,9 @@ import (
"strings" "strings"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/git"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
) )
@@ -61,17 +64,17 @@ func MakeFakeFs(td []testData) fs.FileSystem {
return fSys return fSys
} }
func TestNewFileLoaderAt_DemandsDirectory(t *testing.T) { func TestNewLoaderAtConfirmedDir_DemandsDirectory(t *testing.T) {
fSys := MakeFakeFs(testCases) fSys := MakeFakeFs(testCases)
_, err := newFileLoaderAt("/foo", fSys, nil, nil) _, err := newLoaderAtConfirmedDir("/foo", fSys, nil, nil)
if err != nil { if err != nil {
t.Fatalf("Unexpected error - a directory should work.") t.Fatalf("Unexpected error - a directory should work.")
} }
_, err = newFileLoaderAt("/foo/project", fSys, nil, nil) _, err = newLoaderAtConfirmedDir("/foo/project", fSys, nil, nil)
if err != nil { if err != nil {
t.Fatalf("Unexpected error - a directory should work.") t.Fatalf("Unexpected error - a directory should work.")
} }
_, err = newFileLoaderAt("/foo/project/fileA.yaml", fSys, nil, nil) _, err = newLoaderAtConfirmedDir("/foo/project/fileA.yaml", fSys, nil, nil)
if err == nil { if err == nil {
t.Fatalf("Expected error - a file should not work.") t.Fatalf("Expected error - a file should not work.")
} }
@@ -321,3 +324,97 @@ func TestRestrictedLoadingInRealLoader(t *testing.T) {
t.Fatalf("unexpected err: %v", err) t.Fatalf("unexpected err: %v", err)
} }
} }
func splitOnNthSlash(v string, n int) (string, string) {
left := ""
for i := 0; i < n; i++ {
k := strings.Index(v, "/")
if k < 0 {
break
}
left = left + v[:k+1]
v = v[k+1:]
}
return left[:len(left)-1], v
}
func TestSplit(t *testing.T) {
path := "a/b/c/d/e/f/g"
if left, right := splitOnNthSlash(path, 2); left != "a/b" || right != "c/d/e/f/g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
if left, right := splitOnNthSlash(path, 3); left != "a/b/c" || right != "d/e/f/g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
if left, right := splitOnNthSlash(path, 6); left != "a/b/c/d/e/f" || right != "g" {
t.Fatalf("got left='%s', right='%s'", left, right)
}
}
// makeFakeGitCloner returns a cloner that ignores the
// URL argument and returns a path in a fake file system
// that should already hold the 'repo' contents.
func makeFakeGitCloner(t *testing.T, fSys fs.FileSystem, coRoot string) git.Cloner {
if !fSys.IsDir(coRoot) {
t.Fatalf("expecting a directory at '%s'", coRoot)
}
return func(url string) (
checkoutDir string, pathInCoDir string, err error) {
_, path := splitOnNthSlash(url, 3)
if !fSys.IsDir(coRoot + "/" + path) {
t.Fatalf("expecting a directory at '%s'/'%s'",
coRoot, path)
}
return coRoot, path, nil
}
}
func TestNewLoaderAtGitClone(t *testing.T) {
rootUrl := "github.com/someOrg/someRepo"
pathInRepo := "foo/base"
url := rootUrl + "/" + pathInRepo
if !git.IsRepoUrl(url) {
t.Fatalf("'%s' should be accepted as a repo url", url)
}
coRoot := "/tmp"
fSys := fs.MakeFakeFS()
fSys.MkdirAll(coRoot)
fSys.MkdirAll(coRoot + "/" + pathInRepo)
fSys.WriteFile(
coRoot+"/"+pathInRepo+"/"+constants.KustomizationFileNames[0],
[]byte(`
whatever
`))
l, err := newLoaderAtGitClone(
url, fSys, nil,
makeFakeGitCloner(t, fSys, coRoot))
if err != nil {
t.Fatalf("unexpected err: %v\n", err)
}
if coRoot+"/"+pathInRepo != l.Root() {
t.Fatalf("expected root '%s', got '%s'\n",
coRoot+"/"+pathInRepo, l.Root())
}
if _, err = l.New(url); err == nil {
t.Fatalf("expected cycle error 1")
}
if _, err = l.New(rootUrl + "/" + "foo"); err == nil {
t.Fatalf("expected cycle error 2")
}
pathInRepo = "foo/overlay"
fSys.MkdirAll(coRoot + "/" + pathInRepo)
url = rootUrl + "/" + pathInRepo
if !git.IsRepoUrl(url) {
t.Fatalf("'%s' should be accepted as a repo url", url)
}
l2, err := l.New(url)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if coRoot+"/"+pathInRepo != l2.Root() {
t.Fatalf("expected root '%s', got '%s'\n",
coRoot+"/"+pathInRepo, l2.Root())
}
}

View File

@@ -19,15 +19,16 @@ package loader
import ( import (
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/git"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
) )
// NewLoader returns a Loader. // NewLoader returns a Loader.
func NewLoader(root string, fSys fs.FileSystem) (ifc.Loader, error) { func NewLoader(root string, fSys fs.FileSystem) (ifc.Loader, error) {
if isRepoUrl(root) { if git.IsRepoUrl(root) {
return newGitLoader( return newLoaderAtGitClone(
root, fSys, nil, simpleGitCloner) root, fSys, nil, git.ClonerUsingGitExec)
} }
return newFileLoaderAt( return newLoaderAtConfirmedDir(
root, fSys, nil, simpleGitCloner) root, fSys, nil, git.ClonerUsingGitExec)
} }