mirror of https://github.com/helm/helm
This adds code to parse TOML files into Values maps. These can then easily be passed into the template engine. Included in this is support for TOML "tables", subsections of TOML files. We will be using those to pass config data to dependent charts.pull/613/head
parent
2d9563b483
commit
619e1e2a0a
@ -0,0 +1,11 @@
|
||||
poet = "Coleridge"
|
||||
title = "Rime of the Ancient Mariner"
|
||||
stanza = ["at", "length", "did", "cross", "an", "Albatross"]
|
||||
|
||||
[mariner]
|
||||
with = "crossbow"
|
||||
shot = "ALBATROSS"
|
||||
|
||||
[water.water]
|
||||
where = "everywhere"
|
||||
nor = "any drop to drink"
|
@ -0,0 +1,67 @@
|
||||
package chart
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
var ErrNoTable = errors.New("no table")
|
||||
|
||||
type Values map[string]interface{}
|
||||
|
||||
// Table gets a table (TOML subsection) from a Values object.
|
||||
//
|
||||
// The table is returned as a Values.
|
||||
//
|
||||
// Compound table names may be specified with dots:
|
||||
//
|
||||
// foo.bar
|
||||
//
|
||||
// The above will be evaluated as "The table bar inside the table
|
||||
// foo".
|
||||
//
|
||||
// An ErrNoTable is returned if the table does not exist.
|
||||
func (v Values) Table(name string) (Values, error) {
|
||||
names := strings.Split(name, ".")
|
||||
table := v
|
||||
var err error
|
||||
|
||||
for _, n := range names {
|
||||
table, err = tableLookup(table, n)
|
||||
if err != nil {
|
||||
return table, err
|
||||
}
|
||||
}
|
||||
return table, err
|
||||
}
|
||||
|
||||
func tableLookup(v Values, simple string) (Values, error) {
|
||||
v2, ok := v[simple]
|
||||
if !ok {
|
||||
return v, ErrNoTable
|
||||
}
|
||||
vv, ok := v2.(map[string]interface{})
|
||||
if !ok {
|
||||
return vv, ErrNoTable
|
||||
}
|
||||
return vv, nil
|
||||
}
|
||||
|
||||
// ReadValues will parse TOML byte data into a Values.
|
||||
func ReadValues(data []byte) (Values, error) {
|
||||
out := map[string]interface{}{}
|
||||
err := toml.Unmarshal(data, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// ReadValuesFile will parse a TOML file into a Values.
|
||||
func ReadValuesFile(filename string) (Values, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return map[string]interface{}{}, err
|
||||
}
|
||||
return ReadValues(data)
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package chart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func TestReadValues(t *testing.T) {
|
||||
doc := `# Test TOML parse
|
||||
poet = "Coleridge"
|
||||
title = "Rime of the Ancient Mariner"
|
||||
stanza = ["at", "length", "did", "cross", "an", "Albatross"]
|
||||
|
||||
[mariner]
|
||||
with = "crossbow"
|
||||
shot = "ALBATROSS"
|
||||
|
||||
[water.water]
|
||||
where = "everywhere"
|
||||
nor = "any drop to drink"
|
||||
`
|
||||
|
||||
data, err := ReadValues([]byte(doc))
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing bytes: %s", err)
|
||||
}
|
||||
matchValues(t, data)
|
||||
}
|
||||
|
||||
func TestReadValuesFile(t *testing.T) {
|
||||
data, err := ReadValuesFile("./testdata/coleridge.toml")
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading TOML file: %s", err)
|
||||
}
|
||||
matchValues(t, data)
|
||||
}
|
||||
|
||||
func ExampleValues() {
|
||||
doc := `title="Moby Dick"
|
||||
[chapter.one]
|
||||
title = "Loomings"
|
||||
|
||||
[chapter.two]
|
||||
title = "The Carpet-Bag"
|
||||
|
||||
[chapter.three]
|
||||
title = "The Spouter Inn"
|
||||
`
|
||||
d, err := ReadValues([]byte(doc))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ch1, err := d.Table("chapter.one")
|
||||
if err != nil {
|
||||
panic("could not find chapter one")
|
||||
}
|
||||
fmt.Print(ch1["title"])
|
||||
// Output:
|
||||
// Loomings
|
||||
}
|
||||
|
||||
func TestTable(t *testing.T) {
|
||||
doc := `title="Moby Dick"
|
||||
[chapter.one]
|
||||
title = "Loomings"
|
||||
|
||||
[chapter.two]
|
||||
title = "The Carpet-Bag"
|
||||
|
||||
[chapter.three]
|
||||
title = "The Spouter Inn"
|
||||
`
|
||||
d, err := ReadValues([]byte(doc))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse the White Whale: %s", err)
|
||||
}
|
||||
|
||||
if _, err := d.Table("title"); err == nil {
|
||||
t.Fatalf("Title is not a table.")
|
||||
}
|
||||
|
||||
if _, err := d.Table("chapter"); err != nil {
|
||||
t.Fatalf("Failed to get the chapter table: %s\n%v", err, d)
|
||||
}
|
||||
|
||||
if v, err := d.Table("chapter.one"); err != nil {
|
||||
t.Errorf("Failed to get chapter.one: %s", err)
|
||||
} else if v["title"] != "Loomings" {
|
||||
t.Errorf("Unexpected title: %s", v["title"])
|
||||
}
|
||||
|
||||
if _, err := d.Table("chapter.three"); err != nil {
|
||||
t.Errorf("Chapter three is missing: %s\n%v", err, d)
|
||||
}
|
||||
|
||||
if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil {
|
||||
t.Errorf("I think you mean 'Epilogue'")
|
||||
}
|
||||
}
|
||||
|
||||
func matchValues(t *testing.T, data map[string]interface{}) {
|
||||
if data["poet"] != "Coleridge" {
|
||||
t.Errorf("Unexpected poet: %s", data["poet"])
|
||||
}
|
||||
|
||||
if o, err := ttpl("{{len .stanza}}", data); err != nil {
|
||||
t.Errorf("len stanza: %s", err)
|
||||
} else if o != "6" {
|
||||
t.Errorf("Expected 6, got %s", o)
|
||||
}
|
||||
|
||||
if o, err := ttpl("{{.mariner.shot}}", data); err != nil {
|
||||
t.Errorf(".mariner.shot: %s", err)
|
||||
} else if o != "ALBATROSS" {
|
||||
t.Errorf("Expected that mariner shot ALBATROSS")
|
||||
}
|
||||
|
||||
if o, err := ttpl("{{.water.water.where}}", data); err != nil {
|
||||
t.Errorf(".water.water.where: %s", err)
|
||||
} else if o != "everywhere" {
|
||||
t.Errorf("Expected water water everywhere")
|
||||
}
|
||||
}
|
||||
|
||||
func ttpl(tpl string, v map[string]interface{}) (string, error) {
|
||||
var b bytes.Buffer
|
||||
tt := template.Must(template.New("t").Parse(tpl))
|
||||
if err := tt.Execute(&b, v); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
Loading…
Reference in new issue