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