github.com/danielqsj/helm@v2.0.0-alpha.4.0.20160908204436-976e0ba5199b+incompatible/pkg/chartutil/save.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	"errors"
    23  	"fmt"
    24  	"os"
    25  	"path/filepath"
    26  
    27  	"github.com/ghodss/yaml"
    28  
    29  	"k8s.io/helm/pkg/proto/hapi/chart"
    30  )
    31  
    32  var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
    33  
    34  // Save creates an archived chart to the given directory.
    35  //
    36  // This takes an existing chart and a destination directory.
    37  //
    38  // If the directory is /foo, and the chart is named bar, with version 1.0.0, this
    39  // will generate /foo/bar-1.0.0.tgz.
    40  //
    41  // This returns the absolute path to the chart archive file.
    42  func Save(c *chart.Chart, outDir string) (string, error) {
    43  	// Create archive
    44  	if fi, err := os.Stat(outDir); err != nil {
    45  		return "", err
    46  	} else if !fi.IsDir() {
    47  		return "", fmt.Errorf("location %s is not a directory", outDir)
    48  	}
    49  
    50  	if c.Metadata == nil {
    51  		return "", errors.New("no Chart.yaml data")
    52  	}
    53  
    54  	cfile := c.Metadata
    55  	if cfile.Name == "" {
    56  		return "", errors.New("no chart name specified (Chart.yaml)")
    57  	} else if cfile.Version == "" {
    58  		return "", errors.New("no chart version specified (Chart.yaml)")
    59  	}
    60  
    61  	filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
    62  	filename = filepath.Join(outDir, filename)
    63  	f, err := os.Create(filename)
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  
    68  	// Wrap in gzip writer
    69  	zipper := gzip.NewWriter(f)
    70  	zipper.Header.Extra = headerBytes
    71  	zipper.Header.Comment = "Helm"
    72  
    73  	// Wrap in tar writer
    74  	twriter := tar.NewWriter(zipper)
    75  	rollback := false
    76  	defer func() {
    77  		twriter.Close()
    78  		zipper.Close()
    79  		f.Close()
    80  		if rollback {
    81  			os.Remove(filename)
    82  		}
    83  	}()
    84  
    85  	if err := writeTarContents(twriter, c, ""); err != nil {
    86  		rollback = true
    87  	}
    88  	return filename, err
    89  }
    90  
    91  func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
    92  	base := filepath.Join(prefix, c.Metadata.Name)
    93  
    94  	// Save Chart.yaml
    95  	cdata, err := yaml.Marshal(c.Metadata)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
   100  		return err
   101  	}
   102  
   103  	// Save values.yaml
   104  	if c.Values != nil && len(c.Values.Raw) > 0 {
   105  		if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); err != nil {
   106  			return err
   107  		}
   108  	}
   109  
   110  	// Save templates
   111  	for _, f := range c.Templates {
   112  		n := filepath.Join(base, f.Name)
   113  		if err := writeToTar(out, n, f.Data); err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	// Save files
   119  	for _, f := range c.Files {
   120  		n := filepath.Join(base, f.TypeUrl)
   121  		if err := writeToTar(out, n, f.Value); err != nil {
   122  			return err
   123  		}
   124  	}
   125  
   126  	// Save dependencies
   127  	for _, dep := range c.Dependencies {
   128  		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
   129  			return err
   130  		}
   131  	}
   132  	return nil
   133  }
   134  
   135  // writeToTar writes a single file to a tar archive.
   136  func writeToTar(out *tar.Writer, name string, body []byte) error {
   137  	// TODO: Do we need to create dummy parent directory names if none exist?
   138  	h := &tar.Header{
   139  		Name: name,
   140  		Mode: 0755,
   141  		Size: int64(len(body)),
   142  	}
   143  	if err := out.WriteHeader(h); err != nil {
   144  		return err
   145  	}
   146  	if _, err := out.Write(body); err != nil {
   147  		return err
   148  	}
   149  	return nil
   150  }