1package state
2
3import (
4	"fmt"
5	"github.com/roboll/helmfile/pkg/helmexec"
6	"github.com/roboll/helmfile/pkg/remote"
7	"github.com/variantdev/chartify"
8	"os"
9	"path/filepath"
10	"strings"
11)
12
13type Dependency struct {
14	Chart   string `yaml:"chart"`
15	Version string `yaml:"version"`
16	Alias   string `yaml:"alias"`
17}
18
19func (st *HelmState) appendHelmXFlags(flags []string, release *ReleaseSpec) ([]string, error) {
20	for _, adopt := range release.Adopt {
21		flags = append(flags, "--adopt", adopt)
22	}
23
24	return flags, nil
25}
26
27func fileExistsAt(path string) bool {
28	fileInfo, err := os.Stat(path)
29	return err == nil && fileInfo.Mode().IsRegular()
30}
31
32func directoryExistsAt(path string) bool {
33	fileInfo, err := os.Stat(path)
34	return err == nil && fileInfo.Mode().IsDir()
35}
36
37type Chartify struct {
38	Opts  *chartify.ChartifyOpts
39	Clean func()
40}
41
42func (st *HelmState) downloadChartWithGoGetter(r *ReleaseSpec) (string, error) {
43	pathElems := []string{
44		remote.DefaultCacheDir,
45	}
46
47	if r.Namespace != "" {
48		pathElems = append(pathElems, r.Namespace)
49	}
50
51	if r.KubeContext != "" {
52		pathElems = append(pathElems, r.KubeContext)
53	}
54
55	pathElems = append(pathElems, r.Name, r.Chart)
56
57	cacheDir := filepath.Join(pathElems...)
58
59	return st.goGetterChart(r.Chart, r.Directory, cacheDir, r.ForceGoGetter)
60}
61
62func (st *HelmState) goGetterChart(chart, dir, cacheDir string, force bool) (string, error) {
63	if dir != "" && chart == "" {
64		chart = dir
65	}
66
67	_, err := remote.Parse(chart)
68	if err != nil {
69		if force {
70			return "", fmt.Errorf("Parsing url from dir failed due to error %q.\nContinuing the process assuming this is a regular Helm chart or a local dir.", err.Error())
71		}
72	} else {
73		r := remote.NewRemote(st.logger, st.basePath, st.readFile, directoryExistsAt, fileExistsAt)
74
75		fetchedDir, err := r.Fetch(chart, cacheDir)
76		if err != nil {
77			return "", fmt.Errorf("fetching %q: %v", chart, err)
78		}
79
80		chart = fetchedDir
81	}
82
83	return chart, nil
84}
85
86func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSpec, chart string, workerIndex int) (*Chartify, func(), error) {
87	chartify := &Chartify{
88		Opts: &chartify.ChartifyOpts{
89			WorkaroundOutputDirIssue:    true,
90			EnableKustomizeAlphaPlugins: true,
91			ChartVersion:                release.Version,
92			Namespace:                   release.Namespace,
93		},
94	}
95
96	var filesNeedCleaning []string
97
98	clean := func() {
99		st.removeFiles(filesNeedCleaning)
100	}
101
102	var shouldRun bool
103
104	dir := filepath.Join(st.basePath, chart)
105	if stat, _ := os.Stat(dir); stat != nil && stat.IsDir() {
106		if exists, err := st.fileExists(filepath.Join(dir, "Chart.yaml")); err == nil && !exists {
107			shouldRun = true
108		}
109	}
110
111	for _, d := range release.Dependencies {
112		var dep string
113
114		if d.Alias != "" {
115			dep += d.Alias + "="
116		} else {
117			a := strings.Split(d.Chart, "/")
118
119			chart := a[len(a)-1]
120
121			dep += chart + "="
122		}
123
124		dep += d.Chart
125
126		if d.Version != "" {
127			dep += ":" + d.Version
128		}
129
130		chartify.Opts.AdhocChartDependencies = append(chartify.Opts.AdhocChartDependencies, dep)
131
132		shouldRun = true
133	}
134
135	jsonPatches := release.JSONPatches
136	if len(jsonPatches) > 0 {
137		generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, jsonPatches, release.MissingFileHandler)
138		if err != nil {
139			return nil, clean, err
140		}
141
142		filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
143
144		for _, f := range generatedFiles {
145			chartify.Opts.JsonPatches = append(chartify.Opts.JsonPatches, f)
146		}
147
148		shouldRun = true
149	}
150
151	strategicMergePatches := release.StrategicMergePatches
152	if len(strategicMergePatches) > 0 {
153		generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, strategicMergePatches, release.MissingFileHandler)
154		if err != nil {
155			return nil, clean, err
156		}
157
158		for _, f := range generatedFiles {
159			chartify.Opts.StrategicMergePatches = append(chartify.Opts.StrategicMergePatches, f)
160		}
161
162		filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
163
164		shouldRun = true
165	}
166
167	transformers := release.Transformers
168	if len(transformers) > 0 {
169		generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, transformers, release.MissingFileHandler)
170		if err != nil {
171			return nil, clean, err
172		}
173
174		for _, f := range generatedFiles {
175			chartify.Opts.Transformers = append(chartify.Opts.Transformers, f)
176		}
177
178		filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
179
180		shouldRun = true
181	}
182
183	if release.ForceNamespace != "" {
184		chartify.Opts.OverrideNamespace = release.ForceNamespace
185
186		shouldRun = true
187	}
188
189	if shouldRun {
190		generatedFiles, err := st.generateValuesFiles(helm, release, workerIndex)
191		if err != nil {
192			return nil, clean, err
193		}
194
195		filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
196
197		chartify.Opts.ValuesFiles = generatedFiles
198
199		return chartify, clean, nil
200	}
201
202	return nil, clean, nil
203}
204