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  }