github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/chart/loader/load.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package loader 18 19 import ( 20 "bytes" 21 "os" 22 "path/filepath" 23 "strings" 24 25 "github.com/ghodss/yaml" 26 "github.com/pkg/errors" 27 28 "helm.sh/helm/pkg/chart" 29 ) 30 31 // ChartLoader loads a chart. 32 type ChartLoader interface { 33 Load() (*chart.Chart, error) 34 } 35 36 // Loader returns a new ChartLoader appropriate for the given chart name 37 func Loader(name string) (ChartLoader, error) { 38 fi, err := os.Stat(name) 39 if err != nil { 40 return nil, err 41 } 42 if fi.IsDir() { 43 return DirLoader(name), nil 44 } 45 return FileLoader(name), nil 46 47 } 48 49 // Load takes a string name, tries to resolve it to a file or directory, and then loads it. 50 // 51 // This is the preferred way to load a chart. It will discover the chart encoding 52 // and hand off to the appropriate chart reader. 53 // 54 // If a .helmignore file is present, the directory loader will skip loading any files 55 // matching it. But .helmignore is not evaluated when reading out of an archive. 56 func Load(name string) (*chart.Chart, error) { 57 l, err := Loader(name) 58 if err != nil { 59 return nil, err 60 } 61 return l.Load() 62 } 63 64 // BufferedFile represents an archive file buffered for later processing. 65 type BufferedFile struct { 66 Name string 67 Data []byte 68 } 69 70 // LoadFiles loads from in-memory files. 71 func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { 72 c := new(chart.Chart) 73 subcharts := make(map[string][]*BufferedFile) 74 75 for _, f := range files { 76 switch { 77 case f.Name == "Chart.yaml": 78 if c.Metadata == nil { 79 c.Metadata = new(chart.Metadata) 80 } 81 if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { 82 return c, errors.Wrap(err, "cannot load Chart.yaml") 83 } 84 // NOTE(bacongobbler): while the chart specification says that APIVersion must be set, 85 // Helm 2 accepted charts that did not provide an APIVersion in their chart metadata. 86 // Because of that, if APIVersion is unset, we should assume we're loading a v1 chart. 87 if c.Metadata.APIVersion == "" { 88 c.Metadata.APIVersion = chart.APIVersionV1 89 } 90 case f.Name == "Chart.lock": 91 c.Lock = new(chart.Lock) 92 if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { 93 return c, errors.Wrap(err, "cannot load Chart.lock") 94 } 95 case f.Name == "values.yaml": 96 c.Values = make(map[string]interface{}) 97 if err := yaml.Unmarshal(f.Data, &c.Values); err != nil { 98 return c, errors.Wrap(err, "cannot load values.yaml") 99 } 100 c.RawValues = f.Data 101 case f.Name == "values.schema.json": 102 c.Schema = f.Data 103 104 // Deprecated: requirements.yaml is deprecated use Chart.yaml. 105 // We will handle it for you because we are nice people 106 case f.Name == "requirements.yaml": 107 if c.Metadata == nil { 108 c.Metadata = new(chart.Metadata) 109 } 110 if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { 111 return c, errors.Wrap(err, "cannot load requirements.yaml") 112 } 113 // Deprecated: requirements.lock is deprecated use Chart.lock. 114 case f.Name == "requirements.lock": 115 c.Lock = new(chart.Lock) 116 if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { 117 return c, errors.Wrap(err, "cannot load requirements.lock") 118 } 119 120 case strings.HasPrefix(f.Name, "templates/"): 121 c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) 122 case strings.HasPrefix(f.Name, "charts/"): 123 if filepath.Ext(f.Name) == ".prov" { 124 c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) 125 continue 126 } 127 128 fname := strings.TrimPrefix(f.Name, "charts/") 129 cname := strings.SplitN(fname, "/", 2)[0] 130 subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data}) 131 default: 132 c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) 133 } 134 } 135 136 if err := c.Validate(); err != nil { 137 return c, err 138 } 139 140 for n, files := range subcharts { 141 var sc *chart.Chart 142 var err error 143 switch { 144 case strings.IndexAny(n, "_.") == 0: 145 continue 146 case filepath.Ext(n) == ".tgz": 147 file := files[0] 148 if file.Name != n { 149 return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name) 150 } 151 // Untar the chart and add to c.Dependencies 152 sc, err = LoadArchive(bytes.NewBuffer(file.Data)) 153 default: 154 // We have to trim the prefix off of every file, and ignore any file 155 // that is in charts/, but isn't actually a chart. 156 buff := make([]*BufferedFile, 0, len(files)) 157 for _, f := range files { 158 parts := strings.SplitN(f.Name, "/", 2) 159 if len(parts) < 2 { 160 continue 161 } 162 f.Name = parts[1] 163 buff = append(buff, f) 164 } 165 sc, err = LoadFiles(buff) 166 } 167 168 if err != nil { 169 return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name()) 170 } 171 c.AddDependency(sc) 172 } 173 174 return c, nil 175 }