diff --git a/pkg/engine/files.go b/pkg/engine/files.go index d7e62da5a..ed9ad757e 100644 --- a/pkg/engine/files.go +++ b/pkg/engine/files.go @@ -18,6 +18,7 @@ package engine import ( "encoding/base64" + "fmt" "path" "strings" @@ -46,11 +47,11 @@ func newFiles(from []*chart.File) files { // // This is intended to be accessed from within a template, so a missed key returns // an empty []byte. -func (f files) GetBytes(name string) []byte { +func (f files) GetBytes(name string) ([]byte, error) { if v, ok := f[name]; ok { - return v + return v, nil } - return []byte{} + return []byte{}, fmt.Errorf("file %s not included", name) } // Get returns a string representation of the given file. @@ -59,8 +60,13 @@ func (f files) GetBytes(name string) []byte { // template. // // {{.Files.Get "foo"}} -func (f files) Get(name string) string { - return string(f.GetBytes(name)) +func (f files) Get(name string) (string, error) { + content, err := f.GetBytes(name) + if err != nil { + return "", err + } + + return string(content), nil } // Glob takes a glob pattern and returns another files object only containing @@ -101,9 +107,9 @@ func (f files) Glob(pattern string) files { // // data: // {{ .Files.Glob("config/**").AsConfig() | indent 4 }} -func (f files) AsConfig() string { - if f == nil { - return "" +func (f files) AsConfig() (string, error) { + if f == nil || len(f) == 0 { + return "", fmt.Errorf("must pass files") } m := make(map[string]string) @@ -113,7 +119,7 @@ func (f files) AsConfig() string { m[path.Base(k)] = string(v) } - return toYAML(m) + return toYAML(m), nil } // AsSecrets returns the base64-encoded value of a Files object suitable for @@ -130,9 +136,9 @@ func (f files) AsConfig() string { // // data: // {{ .Files.Glob("secrets/*").AsSecrets() }} -func (f files) AsSecrets() string { - if f == nil { - return "" +func (f files) AsSecrets() (string, error) { + if f == nil || len(f) == 0 { + return "", fmt.Errorf("must pass files") } m := make(map[string]string) @@ -141,7 +147,7 @@ func (f files) AsSecrets() string { m[path.Base(k)] = base64.StdEncoding.EncodeToString(v) } - return toYAML(m) + return toYAML(m), nil } // Lines returns each line of a named file (split by "\n") as a slice, so it can @@ -151,10 +157,10 @@ func (f files) AsSecrets() string { // // {{ range .Files.Lines "foo/bar.html" }} // {{ . }}{{ end }} -func (f files) Lines(path string) []string { +func (f files) Lines(path string) ([]string, error) { if f == nil || f[path] == nil { - return []string{} + return nil, fmt.Errorf("must pass files") } - return strings.Split(string(f[path]), "\n") + return strings.Split(string(f[path]), "\n"), nil } diff --git a/pkg/engine/files_test.go b/pkg/engine/files_test.go index 4b37724f9..debb3089e 100644 --- a/pkg/engine/files_test.go +++ b/pkg/engine/files_test.go @@ -21,6 +21,8 @@ import ( "github.com/stretchr/testify/assert" ) +const NonExistingFileName = "no_such_file.txt" + var cases = []struct { path, data string }{ @@ -46,15 +48,30 @@ func TestNewFiles(t *testing.T) { } for i, f := range cases { - if got := string(files.GetBytes(f.path)); got != f.data { + gotBytes, err := files.GetBytes(f.path) + got := string(gotBytes) + if err != nil || got != f.data { t.Errorf("%d: expected %q, got %q", i, f.data, got) } - if got := files.Get(f.path); got != f.data { + + gotBytes, err = files.GetBytes(f.path) + got = string(gotBytes) + if err != nil || got != f.data { t.Errorf("%d: expected %q, got %q", i, f.data, got) } } } +func TestGetNonExistingFile(t *testing.T) { + as := assert.New(t) + + f := getTestFiles() + + content, err := f.Get(NonExistingFileName) + as.Empty(content) + as.Error(err, "not included") +} + func TestFileGlob(t *testing.T) { as := assert.New(t) @@ -63,18 +80,27 @@ func TestFileGlob(t *testing.T) { matched := f.Glob("story/**") as.Len(matched, 2, "Should be two files in glob story/**") - as.Equal("Joseph Conrad", matched.Get("story/author.txt")) + + content, err := matched.Get("story/author.txt") + as.Equal("Joseph Conrad", content) + as.NoError(err) } func TestToConfig(t *testing.T) { as := assert.New(t) f := getTestFiles() - out := f.Glob("**/captain.txt").AsConfig() + out, err := f.Glob("**/captain.txt").AsConfig() as.Equal("captain.txt: The Captain", out) + as.NoError(err) - out = f.Glob("ship/**").AsConfig() + out, err = f.Glob("ship/**").AsConfig() as.Equal("captain.txt: The Captain\nstowaway.txt: Legatt", out) + as.NoError(err) + + out, err = f.Glob(NonExistingFileName).AsConfig() + as.Empty(out) + as.Error(err, "must pass files") } func TestToSecret(t *testing.T) { @@ -82,8 +108,13 @@ func TestToSecret(t *testing.T) { f := getTestFiles() - out := f.Glob("ship/**").AsSecrets() + out, err := f.Glob("ship/**").AsSecrets() as.Equal("captain.txt: VGhlIENhcHRhaW4=\nstowaway.txt: TGVnYXR0", out) + as.NoError(err) + + out, err = f.Glob(NonExistingFileName).AsSecrets() + as.Empty(out) + as.Errorf(err, "must pass files") } func TestLines(t *testing.T) { @@ -91,8 +122,12 @@ func TestLines(t *testing.T) { f := getTestFiles() - out := f.Lines("multiline/test.txt") + out, err := f.Lines("multiline/test.txt") as.Len(out, 2) - as.Equal("bar", out[0]) + as.NoError(err) + + out, err = f.Lines(NonExistingFileName) + as.Nil(out) + as.Error(err, "must pass files") }