github.com/kruglovmax/helm@v3.0.0-beta.3+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 "log" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/pkg/errors" 27 "sigs.k8s.io/yaml" 28 29 "helm.sh/helm/pkg/chart" 30 ) 31 32 // ChartLoader loads a chart. 33 type ChartLoader interface { 34 Load() (*chart.Chart, error) 35 } 36 37 // Loader returns a new ChartLoader appropriate for the given chart name 38 func Loader(name string) (ChartLoader, error) { 39 fi, err := os.Stat(name) 40 if err != nil { 41 return nil, err 42 } 43 if fi.IsDir() { 44 return DirLoader(name), nil 45 } 46 return FileLoader(name), nil 47 48 } 49 50 // Load takes a string name, tries to resolve it to a file or directory, and then loads it. 51 // 52 // This is the preferred way to load a chart. It will discover the chart encoding 53 // and hand off to the appropriate chart reader. 54 // 55 // If a .helmignore file is present, the directory loader will skip loading any files 56 // matching it. But .helmignore is not evaluated when reading out of an archive. 57 func Load(name string) (*chart.Chart, error) { 58 l, err := Loader(name) 59 if err != nil { 60 return nil, err 61 } 62 return l.Load() 63 } 64 65 // BufferedFile represents an archive file buffered for later processing. 66 type BufferedFile struct { 67 Name string 68 Data []byte 69 } 70 71 // LoadFiles loads from in-memory files. 72 func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { 73 c := new(chart.Chart) 74 subcharts := make(map[string][]*BufferedFile) 75 76 for _, f := range files { 77 switch { 78 case f.Name == "Chart.yaml": 79 if c.Metadata == nil { 80 c.Metadata = new(chart.Metadata) 81 } 82 if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { 83 return c, errors.Wrap(err, "cannot load Chart.yaml") 84 } 85 // NOTE(bacongobbler): while the chart specification says that APIVersion must be set, 86 // Helm 2 accepted charts that did not provide an APIVersion in their chart metadata. 87 // Because of that, if APIVersion is unset, we should assume we're loading a v1 chart. 88 if c.Metadata.APIVersion == "" { 89 c.Metadata.APIVersion = chart.APIVersionV1 90 } 91 case f.Name == "Chart.lock": 92 c.Lock = new(chart.Lock) 93 if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { 94 return c, errors.Wrap(err, "cannot load Chart.lock") 95 } 96 case f.Name == "values.yaml": 97 c.Values = make(map[string]interface{}) 98 if err := yaml.Unmarshal(f.Data, &c.Values); err != nil { 99 return c, errors.Wrap(err, "cannot load values.yaml") 100 } 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.APIVersion != chart.APIVersionV1 { 108 log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.") 109 } 110 if c.Metadata == nil { 111 c.Metadata = new(chart.Metadata) 112 } 113 if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { 114 return c, errors.Wrap(err, "cannot load requirements.yaml") 115 } 116 // Deprecated: requirements.lock is deprecated use Chart.lock. 117 case f.Name == "requirements.lock": 118 c.Lock = new(chart.Lock) 119 if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { 120 return c, errors.Wrap(err, "cannot load requirements.lock") 121 } 122 123 case strings.HasPrefix(f.Name, "templates/"): 124 c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) 125 case strings.HasPrefix(f.Name, "charts/"): 126 if filepath.Ext(f.Name) == ".prov" { 127 c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) 128 continue 129 } 130 131 fname := strings.TrimPrefix(f.Name, "charts/") 132 cname := strings.SplitN(fname, "/", 2)[0] 133 subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data}) 134 default: 135 c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) 136 } 137 } 138 139 if err := c.Validate(); err != nil { 140 return c, err 141 } 142 143 for n, files := range subcharts { 144 var sc *chart.Chart 145 var err error 146 switch { 147 case strings.IndexAny(n, "_.") == 0: 148 continue 149 case filepath.Ext(n) == ".tgz": 150 file := files[0] 151 if file.Name != n { 152 return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name) 153 } 154 // Untar the chart and add to c.Dependencies 155 sc, err = LoadArchive(bytes.NewBuffer(file.Data)) 156 default: 157 // We have to trim the prefix off of every file, and ignore any file 158 // that is in charts/, but isn't actually a chart. 159 buff := make([]*BufferedFile, 0, len(files)) 160 for _, f := range files { 161 parts := strings.SplitN(f.Name, "/", 2) 162 if len(parts) < 2 { 163 continue 164 } 165 f.Name = parts[1] 166 buff = append(buff, f) 167 } 168 sc, err = LoadFiles(buff) 169 } 170 171 if err != nil { 172 return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name()) 173 } 174 c.AddDependency(sc) 175 } 176 177 return c, nil 178 }