func mktempFile(dir string) (func(), string, error) {
	file, err := ioutil.TempFile(dir, "repo.*")
	return func() {
		if err := os.Remove(file.Name()); err != nil {
			logrus.Fatal(err)
		}
	}, file.Name(), err
}
mkTempFile will make a temporary file and return the name
and cleanup method
package bundle
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"github.com/sirupsen/logrus"
	"helm.sh/helm/v3/pkg/action"
	helmchart "helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"
	helmcli "helm.sh/helm/v3/pkg/cli"
	"helm.sh/helm/v3/pkg/downloader"
	"helm.sh/helm/v3/pkg/getter"
	helmrepo "helm.sh/helm/v3/pkg/repo"
	"k8s.io/client-go/util/jsonpath"
	"sigs.k8s.io/yaml"
	cli "github.com/RedHatGov/bundle/pkg/cli"
	"github.com/RedHatGov/bundle/pkg/config"
	"github.com/RedHatGov/bundle/pkg/config/v1alpha1"
	"github.com/RedHatGov/bundle/pkg/image"
)
type HelmOptions struct {
	cli.RootOptions
	settings *helmcli.EnvSettings
}
func NewHelmOptions(ro cli.RootOptions) *HelmOptions {
	settings := helmcli.New()
	return &HelmOptions{
		RootOptions: ro,
		settings:    settings,
	}
}
func (h *HelmOptions) PullCharts(cfg v1alpha1.ImageSetConfiguration) (image.AssociationSet, error) {
	var images []v1alpha1.AdditionalImages
	cleanup, file, err := mktempFile(h.Dir)
	if err != nil {
		return image.AssociationSet{}, err
	}
	h.settings.RepositoryConfig = file
	defer cleanup()
	c := downloader.ChartDownloader{
		Out:     os.Stdout,
		Keyring: "",
		Verify:  downloader.VerifyNever,
		Getters: getter.All(h.settings),
		Options: []getter.Option{
			getter.WithInsecureSkipVerifyTLS(h.SkipTLS),
		},
		RepositoryConfig: h.settings.RepositoryConfig,
		RepositoryCache:  h.settings.RepositoryCache,
	}
	for _, chart := range cfg.Mirror.Helm.Local {
		img, err := findImages(chart.Path, chart.ImagePaths...)
		if err != nil {
			return image.AssociationSet{}, err
		}
		images = append(images, img...)
	}
	for _, repo := range cfg.Mirror.Helm.Repos {
		if err := h.repoAdd(repo); err != nil {
			return image.AssociationSet{}, err
		}
		for _, chart := range repo.Charts {
			logrus.Infof("Pulling chart %s", chart.Name)
			ref := fmt.Sprintf("%s/%s", repo.Name, chart.Name)
			dest := filepath.Join(h.Dir, config.SourceDir, config.HelmDir)
			path, _, err := c.DownloadTo(ref, chart.Version, dest)
			if err != nil {
				return image.AssociationSet{}, fmt.Errorf("error pulling chart %q: %v", ref, err)
			}
			img, err := findImages(path, chart.ImagePaths...)
			if err != nil {
				return image.AssociationSet{}, err
			}
			images = append(images, img...)
		}
	}
	opts := NewAdditionalOptions(h.RootOptions)
	return opts.GetAdditional(cfg, images)
}
func findImages(path string, imagePaths ...string) (images []v1alpha1.AdditionalImages, err error) {
	logrus.Debugf("Reading from path %s", path)
	p := getImagesPath(imagePaths...)
	chart, err := loader.Load(path)
	if err != nil {
		return nil, err
	}
	manifest, err := render(chart)
	if err != nil {
		return nil, err
	}
	for _, single := range bytes.Split([]byte(manifest), []byte("\n---\n")) {
		imgs, err := search(single, p...)
		if err != nil {
			return nil, err
		}
		images = append(images, imgs...)
	}
	return images, nil
}
func getImagesPath(paths ...string) []string {
	pathlist := []string{
		"{.spec.template.spec.initContainers[*].image}",
		"{.spec.template.spec.containers[*].image}",
		"{.spec.initContainers[*].image}",
		"{.spec.containers[*].image}",
	}
	return append(pathlist, paths...)
}
func render(chart *helmchart.Chart) (string, error) {
	cfg := new(action.Configuration)
	client := action.NewInstall(cfg)
	client.DryRun = true
	client.ReleaseName = "RELEASE-NAME"
	client.Replace = true
	client.ClientOnly = true
	client.IncludeCRDs = true
	valueOpts := make(map[string]interface{})
	rel, err := client.Run(chart, valueOpts)
	return rel.Manifest, err
}
func (h *HelmOptions) repoAdd(chartRepo v1alpha1.Repo) error {
	entry := helmrepo.Entry{
		Name: chartRepo.Name,
		URL:  chartRepo.URL,
	}
	b, err := ioutil.ReadFile(h.settings.RepositoryConfig)
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	var helmFile helmrepo.File
	if err := yaml.Unmarshal(b, &helmFile); err != nil {
		return err
	}
	if helmFile.Has(chartRepo.Name) {
		logrus.Infof("repository name (%s) already exists", chartRepo.Name)
		return nil
	}
	r, err := helmrepo.NewChartRepository(&entry, getter.All(h.settings))
	if err != nil {
		return err
	}
	if _, err := r.DownloadIndexFile(); err != nil {
		return fmt.Errorf("invalid chart repository %q: %v", chartRepo.URL, err)
	}
	helmFile.Update(&entry)
	if err := helmFile.WriteFile(h.settings.RepositoryConfig, 0644); err != nil {
		return fmt.Errorf("error writing helm repo file: %v", err)
	}
	return nil
}
func parseJSONPath(input interface{}, parser *jsonpath.JSONPath, template string) ([]string, error) {
	buf := new(bytes.Buffer)
	if err := parser.Parse(template); err != nil {
		return nil, err
	}
	if err := parser.Execute(buf, input); err != nil {
		return nil, err
	}
	f := func(s rune) bool { return s == ' ' }
	r := strings.FieldsFunc(buf.String(), f)
	return r, nil
}
func search(yamlData []byte, paths ...string) (images []v1alpha1.AdditionalImages, err error) {
	var data interface{}
	if err := yaml.Unmarshal(yamlData, &data); err != nil {
		logrus.Error(err)
	}
	j := jsonpath.New("")
	j.AllowMissingKeys(true)
	for _, path := range paths {
		results, err := parseJSONPath(data, j, path)
		if err != nil {
			return nil, err
		}
		for _, result := range results {
			logrus.Debugf("Found image %s", result)
			img := v1alpha1.AdditionalImages{
				Image: v1alpha1.Image{
					Name: result,
				},
			}
			images = append(images, img)
		}
	}
	return images, nil
}