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