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  }