tvl-depot/context/context.go
Vincent Ambo 0147c3e13e feat ctx: Let sub-resource-sets inherit vars from parent
Users of kontemplate may expect variables defined on the parent resource to be
inherited by children.

This implements that functionality. Values defined twice are overwritten by the
child's definition.

Fixes #20
2017-02-14 19:12:53 +01:00

93 lines
2.3 KiB
Go

package context
import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"strings"
"github.com/ghodss/yaml"
"github.com/polydawn/meep"
"github.com/tazjin/kontemplate/util"
)
type ResourceSet struct {
Name string `json:"name"`
Values map[string]interface{} `json:"values"`
// Fields for resource set collections
Include []ResourceSet `json:"include"`
Parent string
}
type Context struct {
Name string `json:"context"`
Global map[string]interface{} `json:"global"`
ResourceSets []ResourceSet `json:"include"`
BaseDir string
}
type ContextLoadingError struct {
meep.AllTraits
Filename string
}
// Attempt to load and deserialise a Context from the specified file.
func LoadContextFromFile(filename string) (*Context, error) {
file, err := ioutil.ReadFile(filename)
if err != nil {
return nil, meep.New(
&ContextLoadingError{Filename: filename},
meep.Cause(err),
)
}
var c Context
if strings.HasSuffix(filename, "json") {
err = json.Unmarshal(file, &c)
} else if strings.HasSuffix(filename, "yaml") || strings.HasSuffix(filename, "yml") {
err = yaml.Unmarshal(file, &c)
} else {
return nil, meep.New(
&ContextLoadingError{Filename: filename},
meep.Cause(fmt.Errorf("File format not supported. Must be JSON or YAML.")),
)
}
if err != nil {
return nil, meep.New(
&ContextLoadingError{Filename: filename},
meep.Cause(err),
)
}
c.ResourceSets = *flattenResourceSetCollections(&c.ResourceSets)
c.BaseDir = path.Dir(filename)
return &c, nil
}
// Flattens resource set collections, i.e. resource sets that themselves have an additional 'include' field set.
// Those will be regarded as a short-hand for including multiple resource sets from a subfolder.
// See https://github.com/tazjin/kontemplate/issues/9 for more information.
func flattenResourceSetCollections(rs *[]ResourceSet) *[]ResourceSet {
flattened := make([]ResourceSet, 0)
for _, r := range *rs {
if len(r.Include) == 0 {
flattened = append(flattened, r)
} else {
for _, subResourceSet := range r.Include {
subResourceSet.Parent = r.Name
subResourceSet.Name = path.Join(r.Name, subResourceSet.Name)
subResourceSet.Values = *util.Merge(&r.Values, &subResourceSet.Values)
flattened = append(flattened, subResourceSet)
}
}
}
return &flattened
}