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  }