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