config: RawConfig works, plus tests
This commit is contained in:
parent
a24b30b8d2
commit
e445f8db38
|
@ -1,5 +1,10 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/copystructure"
|
||||||
|
"github.com/mitchellh/reflectwalk"
|
||||||
|
)
|
||||||
|
|
||||||
// UnknownVariableValue is a sentinel value that can be used
|
// UnknownVariableValue is a sentinel value that can be used
|
||||||
// to denote that the value of a variable is unknown at this time.
|
// to denote that the value of a variable is unknown at this time.
|
||||||
// RawConfig uses this information to build up data about
|
// RawConfig uses this information to build up data about
|
||||||
|
@ -18,6 +23,23 @@ const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
|
||||||
type RawConfig struct {
|
type RawConfig struct {
|
||||||
Raw map[string]interface{}
|
Raw map[string]interface{}
|
||||||
Variables map[string]InterpolatedVariable
|
Variables map[string]InterpolatedVariable
|
||||||
|
|
||||||
|
config map[string]interface{}
|
||||||
|
unknownKeys []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRawConfig creates a new RawConfig structure and populates the
|
||||||
|
// publicly readable struct fields.
|
||||||
|
func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
|
||||||
|
walker := new(variableDetectWalker)
|
||||||
|
if err := reflectwalk.Walk(raw, walker); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RawConfig{
|
||||||
|
Raw: raw,
|
||||||
|
Variables: walker.Variables,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate uses the given mapping of variable values and uses
|
// Interpolate uses the given mapping of variable values and uses
|
||||||
|
@ -27,7 +49,21 @@ type RawConfig struct {
|
||||||
// Any prior calls to Interpolate are replaced with this one.
|
// Any prior calls to Interpolate are replaced with this one.
|
||||||
//
|
//
|
||||||
// If a variable key is missing, this will panic.
|
// If a variable key is missing, this will panic.
|
||||||
func (r *RawConfig) Interpolate(map[string]string) {
|
func (r *RawConfig) Interpolate(vs map[string]string) error {
|
||||||
|
config, err := copystructure.Copy(r.Raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &variableReplaceWalker{Values: vs}
|
||||||
|
r.config = config.(map[string]interface{})
|
||||||
|
err = reflectwalk.Walk(r.config, w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.unknownKeys = w.UnknownKeys
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config returns the entire configuration with the variables
|
// Config returns the entire configuration with the variables
|
||||||
|
@ -42,5 +78,11 @@ func (r *RawConfig) Interpolate(map[string]string) {
|
||||||
// structure will always successfully decode into its ultimate
|
// structure will always successfully decode into its ultimate
|
||||||
// structure using something like mapstructure.
|
// structure using something like mapstructure.
|
||||||
func (r *RawConfig) Config() map[string]interface{} {
|
func (r *RawConfig) Config() map[string]interface{} {
|
||||||
return nil
|
return r.config
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnknownKeys returns the keys of the configuration that are unknown
|
||||||
|
// because they had interpolated variables that must be computed.
|
||||||
|
func (r *RawConfig) UnknownKeys() []string {
|
||||||
|
return r.unknownKeys
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,77 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewRawConfig(t *testing.T) {
|
||||||
|
raw := map[string]interface{}{
|
||||||
|
"foo": "${var.bar}",
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := NewRawConfig(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rc.Variables) != 1 {
|
||||||
|
t.Fatalf("bad: %#v", rc.Variables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawConfig(t *testing.T) {
|
||||||
|
raw := map[string]interface{}{
|
||||||
|
"foo": "${var.bar}",
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := NewRawConfig(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := map[string]string{"var.bar": "baz"}
|
||||||
|
if err := rc.Interpolate(vars); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := rc.Config()
|
||||||
|
expected := map[string]interface{}{
|
||||||
|
"foo": "baz",
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
t.Fatalf("bad: %#v", actual)
|
||||||
|
}
|
||||||
|
if len(rc.UnknownKeys()) != 0 {
|
||||||
|
t.Fatalf("bad: %#v", rc.UnknownKeys())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawConfig_unknown(t *testing.T) {
|
||||||
|
raw := map[string]interface{}{
|
||||||
|
"foo": "${var.bar}",
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := NewRawConfig(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := map[string]string{"var.bar": UnknownVariableValue}
|
||||||
|
if err := rc.Interpolate(vars); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := rc.Config()
|
||||||
|
expected := map[string]interface{}{}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
t.Fatalf("bad: %#v", actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedKeys := []string{"foo"}
|
||||||
|
if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) {
|
||||||
|
t.Fatalf("bad: %#v", rc.UnknownKeys())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue