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  }