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