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  }