github.com/migueleliasweb/helm@v2.6.1+incompatible/pkg/chartutil/files.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package chartutil 17 18 import ( 19 "bytes" 20 "encoding/base64" 21 "encoding/json" 22 "path" 23 "strings" 24 25 "github.com/ghodss/yaml" 26 27 "github.com/BurntSushi/toml" 28 "github.com/gobwas/glob" 29 "github.com/golang/protobuf/ptypes/any" 30 ) 31 32 // Files is a map of files in a chart that can be accessed from a template. 33 type Files map[string][]byte 34 35 // NewFiles creates a new Files from chart files. 36 // Given an []*any.Any (the format for files in a chart.Chart), extract a map of files. 37 func NewFiles(from []*any.Any) Files { 38 files := map[string][]byte{} 39 if from != nil { 40 for _, f := range from { 41 files[f.TypeUrl] = f.Value 42 } 43 } 44 return files 45 } 46 47 // GetBytes gets a file by path. 48 // 49 // The returned data is raw. In a template context, this is identical to calling 50 // {{index .Files $path}}. 51 // 52 // This is intended to be accessed from within a template, so a missed key returns 53 // an empty []byte. 54 func (f Files) GetBytes(name string) []byte { 55 v, ok := f[name] 56 if !ok { 57 return []byte{} 58 } 59 return v 60 } 61 62 // Get returns a string representation of the given file. 63 // 64 // Fetch the contents of a file as a string. It is designed to be called in a 65 // template. 66 // 67 // {{.Files.Get "foo"}} 68 func (f Files) Get(name string) string { 69 return string(f.GetBytes(name)) 70 } 71 72 // Glob takes a glob pattern and returns another files object only containing 73 // matched files. 74 // 75 // This is designed to be called from a template. 76 // 77 // {{ range $name, $content := .Files.Glob("foo/**") }} 78 // {{ $name }}: | 79 // {{ .Files.Get($name) | indent 4 }}{{ end }} 80 func (f Files) Glob(pattern string) Files { 81 g, err := glob.Compile(pattern, '/') 82 if err != nil { 83 g, _ = glob.Compile("**") 84 } 85 86 nf := NewFiles(nil) 87 for name, contents := range f { 88 if g.Match(name) { 89 nf[name] = contents 90 } 91 } 92 93 return nf 94 } 95 96 // AsConfig turns a Files group and flattens it to a YAML map suitable for 97 // including in the 'data' section of a Kubernetes ConfigMap definition. 98 // Duplicate keys will be overwritten, so be aware that your file names 99 // (regardless of path) should be unique. 100 // 101 // This is designed to be called from a template, and will return empty string 102 // (via ToYaml function) if it cannot be serialized to YAML, or if the Files 103 // object is nil. 104 // 105 // The output will not be indented, so you will want to pipe this to the 106 // 'indent' template function. 107 // 108 // data: 109 // {{ .Files.Glob("config/**").AsConfig() | indent 4 }} 110 func (f Files) AsConfig() string { 111 if f == nil { 112 return "" 113 } 114 115 m := map[string]string{} 116 117 // Explicitly convert to strings, and file names 118 for k, v := range f { 119 m[path.Base(k)] = string(v) 120 } 121 122 return ToYaml(m) 123 } 124 125 // AsSecrets returns the base64-encoded value of a Files object suitable for 126 // including in the 'data' section of a Kubernetes Secret definition. 127 // Duplicate keys will be overwritten, so be aware that your file names 128 // (regardless of path) should be unique. 129 // 130 // This is designed to be called from a template, and will return empty string 131 // (via ToYaml function) if it cannot be serialized to YAML, or if the Files 132 // object is nil. 133 // 134 // The output will not be indented, so you will want to pipe this to the 135 // 'indent' template function. 136 // 137 // data: 138 // {{ .Files.Glob("secrets/*").AsSecrets() }} 139 func (f Files) AsSecrets() string { 140 if f == nil { 141 return "" 142 } 143 144 m := map[string]string{} 145 146 for k, v := range f { 147 m[path.Base(k)] = base64.StdEncoding.EncodeToString(v) 148 } 149 150 return ToYaml(m) 151 } 152 153 // Lines returns each line of a named file (split by "\n") as a slice, so it can 154 // be ranged over in your templates. 155 // 156 // This is designed to be called from a template. 157 // 158 // {{ range .Files.Lines "foo/bar.html" }} 159 // {{ . }}{{ end }} 160 func (f Files) Lines(path string) []string { 161 if f == nil || f[path] == nil { 162 return []string{} 163 } 164 165 return strings.Split(string(f[path]), "\n") 166 } 167 168 // ToYaml takes an interface, marshals it to yaml, and returns a string. It will 169 // always return a string, even on marshal error (empty string). 170 // 171 // This is designed to be called from a template. 172 func ToYaml(v interface{}) string { 173 data, err := yaml.Marshal(v) 174 if err != nil { 175 // Swallow errors inside of a template. 176 return "" 177 } 178 return string(data) 179 } 180 181 // FromYaml converts a YAML document into a map[string]interface{}. 182 // 183 // This is not a general-purpose YAML parser, and will not parse all valid 184 // YAML documents. Additionally, because its intended use is within templates 185 // it tolerates errors. It will insert the returned error message string into 186 // m["error"] in the returned map. 187 func FromYaml(str string) map[string]interface{} { 188 m := map[string]interface{}{} 189 190 if err := yaml.Unmarshal([]byte(str), &m); err != nil { 191 m["Error"] = err.Error() 192 } 193 return m 194 } 195 196 // ToToml takes an interface, marshals it to toml, and returns a string. It will 197 // always return a string, even on marshal error (empty string). 198 // 199 // This is designed to be called from a template. 200 func ToToml(v interface{}) string { 201 b := bytes.NewBuffer(nil) 202 e := toml.NewEncoder(b) 203 err := e.Encode(v) 204 if err != nil { 205 return err.Error() 206 } 207 return b.String() 208 } 209 210 // ToJson takes an interface, marshals it to json, and returns a string. It will 211 // always return a string, even on marshal error (empty string). 212 // 213 // This is designed to be called from a template. 214 func ToJson(v interface{}) string { 215 data, err := json.Marshal(v) 216 if err != nil { 217 // Swallow errors inside of a template. 218 return "" 219 } 220 return string(data) 221 } 222 223 // FromJson converts a YAML document into a map[string]interface{}. 224 // 225 // This is not a general-purpose JSON parser, and will not parse all valid 226 // YAML documents. Additionally, because its intended use is within templates 227 // it tolerates errors. It will insert the returned error message string into 228 // m["error"] in the returned map. 229 func FromJson(str string) map[string]interface{} { 230 m := map[string]interface{}{} 231 232 if err := json.Unmarshal([]byte(str), &m); err != nil { 233 m["Error"] = err.Error() 234 } 235 return m 236 }