AppManager: Use dodo hosted repo for Helm charts

Change-Id: I236bd13907514ab3bced6c7353edc1b03b60b6ee
diff --git a/core/installer/helm.go b/core/installer/helm.go
index 2c13b50..8370b4e 100644
--- a/core/installer/helm.go
+++ b/core/installer/helm.go
@@ -45,21 +45,50 @@
 	Pull(chart HelmChartGitRepo, rfs soft.RepoFS, root string) error
 }
 
-type gitHelmFetcher struct{}
-
-func NewGitHelmFetcher() *gitHelmFetcher {
-	return &gitHelmFetcher{}
+type RepoCloner interface {
+	Clone(addr, ref string) (*git.Repository, error)
 }
 
-func (f *gitHelmFetcher) Pull(chart HelmChartGitRepo, rfs soft.RepoFS, root string) error {
-	ref := fmt.Sprintf("refs/heads/%s", chart.Branch)
+type cachingRepoCloner struct {
+	cache map[string]*git.Repository
+}
+
+func NewCachingRepoCloner() RepoCloner {
+	return &cachingRepoCloner{make(map[string]*git.Repository)}
+}
+
+func (rc *cachingRepoCloner) Clone(addr, ref string) (*git.Repository, error) {
+	key := fmt.Sprintf("%s:%s", addr, ref)
+	if ret, ok := rc.cache[key]; ok {
+		return ret, nil
+	}
 	r, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
-		URL:           chart.Address,
+		URL:           addr,
 		ReferenceName: plumbing.ReferenceName(ref),
 		SingleBranch:  true,
 		Depth:         1,
 	})
 	if err != nil {
+		return nil, err
+	}
+	// TODO(gio): enable
+	// rc.cache[key] = r
+	return r, nil
+}
+
+type gitHelmFetcher struct {
+	rc RepoCloner
+}
+
+func NewGitHelmFetcher() *gitHelmFetcher {
+	// TODO(gio): take cloner as an argument
+	return &gitHelmFetcher{NewCachingRepoCloner()}
+}
+
+func (f *gitHelmFetcher) Pull(chart HelmChartGitRepo, rfs soft.RepoFS, root string) error {
+	ref := fmt.Sprintf("refs/heads/%s", chart.Branch)
+	r, err := f.rc.Clone(chart.Address, ref)
+	if err != nil {
 		return err
 	}
 	wt, err := r.Worktree()