github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/chartutil/save.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 chartutil
    18  
    19  import (
    20  	"archive/tar"
    21  	"compress/gzip"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  
    27  	"github.com/ghodss/yaml"
    28  	"github.com/pkg/errors"
    29  
    30  	"helm.sh/helm/pkg/chart"
    31  )
    32  
    33  var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
    34  
    35  // SaveDir saves a chart as files in a directory.
    36  func SaveDir(c *chart.Chart, dest string) error {
    37  	// Create the chart directory
    38  	outdir := filepath.Join(dest, c.Name())
    39  	if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() {
    40  		return errors.Errorf("file %s already exists and is not a directory", outdir)
    41  	}
    42  	if err := os.MkdirAll(outdir, 0755); err != nil {
    43  		return err
    44  	}
    45  
    46  	// Save the chart file.
    47  	if err := SaveChartfile(filepath.Join(outdir, ChartfileName), c.Metadata); err != nil {
    48  		return err
    49  	}
    50  
    51  	// Save values.yaml
    52  	if c.Values != nil {
    53  		vf := filepath.Join(outdir, ValuesfileName)
    54  		b, _ := yaml.Marshal(c.Values)
    55  		if err := ioutil.WriteFile(vf, b, 0755); err != nil {
    56  			return err
    57  		}
    58  	}
    59  
    60  	for _, d := range []string{TemplatesDir, ChartsDir} {
    61  		if err := os.MkdirAll(filepath.Join(outdir, d), 0755); err != nil {
    62  			return err
    63  		}
    64  	}
    65  
    66  	// Save templates
    67  	for _, f := range c.Templates {
    68  		n := filepath.Join(outdir, f.Name)
    69  		if err := ioutil.WriteFile(n, f.Data, 0755); err != nil {
    70  			return err
    71  		}
    72  	}
    73  
    74  	// Save files
    75  	for _, f := range c.Files {
    76  		n := filepath.Join(outdir, f.Name)
    77  
    78  		d := filepath.Dir(n)
    79  		if err := os.MkdirAll(d, 0755); err != nil {
    80  			return err
    81  		}
    82  
    83  		if err := ioutil.WriteFile(n, f.Data, 0755); err != nil {
    84  			return err
    85  		}
    86  	}
    87  
    88  	// Save dependencies
    89  	base := filepath.Join(outdir, ChartsDir)
    90  	for _, dep := range c.Dependencies() {
    91  		// Here, we write each dependency as a tar file.
    92  		if _, err := Save(dep, base); err != nil {
    93  			return err
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  // Save creates an archived chart to the given directory.
   100  //
   101  // This takes an existing chart and a destination directory.
   102  //
   103  // If the directory is /foo, and the chart is named bar, with version 1.0.0, this
   104  // will generate /foo/bar-1.0.0.tgz.
   105  //
   106  // This returns the absolute path to the chart archive file.
   107  func Save(c *chart.Chart, outDir string) (string, error) {
   108  	// Create archive
   109  	if fi, err := os.Stat(outDir); err != nil {
   110  		return "", err
   111  	} else if !fi.IsDir() {
   112  		return "", errors.Errorf("location %s is not a directory", outDir)
   113  	}
   114  
   115  	if err := c.Validate(); err != nil {
   116  		return "", errors.Wrap(err, "chart validation")
   117  	}
   118  
   119  	filename := fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version)
   120  	filename = filepath.Join(outDir, filename)
   121  	if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
   122  		if err := os.MkdirAll(filepath.Dir(filename), 0755); !os.IsExist(err) {
   123  			return "", err
   124  		}
   125  	} else if !stat.IsDir() {
   126  		return "", errors.Errorf("is not a directory: %s", filepath.Dir(filename))
   127  	}
   128  
   129  	f, err := os.Create(filename)
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	// Wrap in gzip writer
   135  	zipper := gzip.NewWriter(f)
   136  	zipper.Header.Extra = headerBytes
   137  	zipper.Header.Comment = "Helm"
   138  
   139  	// Wrap in tar writer
   140  	twriter := tar.NewWriter(zipper)
   141  	rollback := false
   142  	defer func() {
   143  		twriter.Close()
   144  		zipper.Close()
   145  		f.Close()
   146  		if rollback {
   147  			os.Remove(filename)
   148  		}
   149  	}()
   150  
   151  	if err := writeTarContents(twriter, c, ""); err != nil {
   152  		rollback = true
   153  	}
   154  	return filename, err
   155  }
   156  
   157  func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
   158  	base := filepath.Join(prefix, c.Name())
   159  
   160  	// Save Chart.yaml
   161  	cdata, err := yaml.Marshal(c.Metadata)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
   166  		return err
   167  	}
   168  
   169  	// Save values.yaml
   170  	ydata, err := yaml.Marshal(c.Values)
   171  	if err != nil {
   172  		return err
   173  	}
   174  	if err := writeToTar(out, base+"/values.yaml", ydata); err != nil {
   175  		return err
   176  	}
   177  
   178  	// Save templates
   179  	for _, f := range c.Templates {
   180  		n := filepath.Join(base, f.Name)
   181  		if err := writeToTar(out, n, f.Data); err != nil {
   182  			return err
   183  		}
   184  	}
   185  
   186  	// Save files
   187  	for _, f := range c.Files {
   188  		n := filepath.Join(base, f.Name)
   189  		if err := writeToTar(out, n, f.Data); err != nil {
   190  			return err
   191  		}
   192  	}
   193  
   194  	// Save dependencies
   195  	for _, dep := range c.Dependencies() {
   196  		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
   197  			return err
   198  		}
   199  	}
   200  	return nil
   201  }
   202  
   203  // writeToTar writes a single file to a tar archive.
   204  func writeToTar(out *tar.Writer, name string, body []byte) error {
   205  	// TODO: Do we need to create dummy parent directory names if none exist?
   206  	h := &tar.Header{
   207  		Name: name,
   208  		Mode: 0755,
   209  		Size: int64(len(body)),
   210  	}
   211  	if err := out.WriteHeader(h); err != nil {
   212  		return err
   213  	}
   214  	_, err := out.Write(body)
   215  	return err
   216  }