github.com/Beeketing/helm@v2.12.1+incompatible/pkg/chartutil/files.go (about) 1 /* 2 Copyright The Helm Authors. 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 for _, f := range from { 40 files[f.TypeUrl] = f.Value 41 } 42 return files 43 } 44 45 // GetBytes gets a file by path. 46 // 47 // The returned data is raw. In a template context, this is identical to calling 48 // {{index .Files $path}}. 49 // 50 // This is intended to be accessed from within a template, so a missed key returns 51 // an empty []byte. 52 func (f Files) GetBytes(name string) []byte { 53 v, ok := f[name] 54 if !ok { 55 return []byte{} 56 } 57 return v 58 } 59 60 // Get returns a string representation of the given file. 61 // 62 // Fetch the contents of a file as a string. It is designed to be called in a 63 // template. 64 // 65 // {{.Files.Get "foo"}} 66 func (f Files) Get(name string) string { 67 return string(f.GetBytes(name)) 68 } 69 70 // Glob takes a glob pattern and returns another files object only containing 71 // matched files. 72 // 73 // This is designed to be called from a template. 74 // 75 // {{ range $name, $content := .Files.Glob("foo/**") }} 76 // {{ $name }}: | 77 // {{ .Files.Get($name) | indent 4 }}{{ end }} 78 func (f Files) Glob(pattern string) Files { 79 g, err := glob.Compile(pattern, '/') 80 if err != nil { 81 g, _ = glob.Compile("**") 82 } 83 84 nf := NewFiles(nil) 85 for name, contents := range f { 86 if g.Match(name) { 87 nf[name] = contents 88 } 89 } 90 91 return nf 92 } 93 94 // AsConfig turns a Files group and flattens it to a YAML map suitable for 95 // including in the 'data' section of a Kubernetes ConfigMap definition. 96 // Duplicate keys will be overwritten, so be aware that your file names 97 // (regardless of path) should be unique. 98 // 99 // This is designed to be called from a template, and will return empty string 100 // (via ToYaml function) if it cannot be serialized to YAML, or if the Files 101 // object is nil. 102 // 103 // The output will not be indented, so you will want to pipe this to the 104 // 'indent' template function. 105 // 106 // data: 107 // {{ .Files.Glob("config/**").AsConfig() | indent 4 }} 108 func (f Files) AsConfig() string { 109 if f == nil { 110 return "" 111 } 112 113 m := map[string]string{} 114 115 // Explicitly convert to strings, and file names 116 for k, v := range f { 117 m[path.Base(k)] = string(v) 118 } 119 120 return ToYaml(m) 121 } 122 123 // AsSecrets returns the base64-encoded value of a Files object suitable for 124 // including in the 'data' section of a Kubernetes Secret definition. 125 // Duplicate keys will be overwritten, so be aware that your file names 126 // (regardless of path) should be unique. 127 // 128 // This is designed to be called from a template, and will return empty string 129 // (via ToYaml function) if it cannot be serialized to YAML, or if the Files 130 // object is nil. 131 // 132 // The output will not be indented, so you will want to pipe this to the 133 // 'indent' template function. 134 // 135 // data: 136 // {{ .Files.Glob("secrets/*").AsSecrets() }} 137 func (f Files) AsSecrets() string { 138 if f == nil { 139 return "" 140 } 141 142 m := map[string]string{} 143 144 for k, v := range f { 145 m[path.Base(k)] = base64.StdEncoding.EncodeToString(v) 146 } 147 148 return ToYaml(m) 149 } 150 151 // Lines returns each line of a named file (split by "\n") as a slice, so it can 152 // be ranged over in your templates. 153 // 154 // This is designed to be called from a template. 155 // 156 // {{ range .Files.Lines "foo/bar.html" }} 157 // {{ . }}{{ end }} 158 func (f Files) Lines(path string) []string { 159 if f == nil || f[path] == nil { 160 return []string{} 161 } 162 163 return strings.Split(string(f[path]), "\n") 164 } 165 166 // ToYaml takes an interface, marshals it to yaml, and returns a string. It will 167 // always return a string, even on marshal error (empty string). 168 // 169 // This is designed to be called from a template. 170 func ToYaml(v interface{}) string { 171 data, err := yaml.Marshal(v) 172 if err != nil { 173 // Swallow errors inside of a template. 174 return "" 175 } 176 return string(data) 177 } 178 179 // FromYaml converts a YAML document into a map[string]interface{}. 180 // 181 // This is not a general-purpose YAML parser, and will not parse all valid 182 // YAML documents. Additionally, because its intended use is within templates 183 // it tolerates errors. It will insert the returned error message string into 184 // m["Error"] in the returned map. 185 func FromYaml(str string) map[string]interface{} { 186 m := map[string]interface{}{} 187 188 if err := yaml.Unmarshal([]byte(str), &m); err != nil { 189 m["Error"] = err.Error() 190 } 191 return m 192 } 193 194 // ToToml takes an interface, marshals it to toml, and returns a string. It will 195 // always return a string, even on marshal error (empty string). 196 // 197 // This is designed to be called from a template. 198 func ToToml(v interface{}) string { 199 b := bytes.NewBuffer(nil) 200 e := toml.NewEncoder(b) 201 err := e.Encode(v) 202 if err != nil { 203 return err.Error() 204 } 205 return b.String() 206 } 207 208 // ToJson takes an interface, marshals it to json, and returns a string. It will 209 // always return a string, even on marshal error (empty string). 210 // 211 // This is designed to be called from a template. 212 // TODO: change the function signature in Helm 3 213 func ToJson(v interface{}) string { // nolint 214 data, err := json.Marshal(v) 215 if err != nil { 216 // Swallow errors inside of a template. 217 return "" 218 } 219 return string(data) 220 } 221 222 // FromJson converts a JSON document into a map[string]interface{}. 223 // 224 // This is not a general-purpose JSON parser, and will not parse all valid 225 // JSON documents. Additionally, because its intended use is within templates 226 // it tolerates errors. It will insert the returned error message string into 227 // m["Error"] in the returned map. 228 // TODO: change the function signature in Helm 3 229 func FromJson(str string) map[string]interface{} { // nolint 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 }