From 69b7bc5047843b85872a386292226ccac85bac3b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 19 Jul 2014 16:39:40 -0700 Subject: [PATCH] config: add Append function --- config/append.go | 58 ++++++++++++++++++++++++++++++ config/append_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 config/append.go create mode 100644 config/append_test.go diff --git a/config/append.go b/config/append.go new file mode 100644 index 000000000..dd20e8ac0 --- /dev/null +++ b/config/append.go @@ -0,0 +1,58 @@ +package config + +// Append appends one configuration to another. +// +// Append assumes that both configurations will not have +// conflicting variables, resources, etc. If they do, the +// problems will be caught in the validation phase. +// +// It is possible that c1, c2 on their own are not valid. For +// example, a resource in c2 may reference a variable in c1. But +// together, they would be valid. +func Append(c1, c2 *Config) (*Config, error) { + c := new(Config) + + // Append unknown keys, but keep them unique since it is a set + unknowns := make(map[string]struct{}) + for _, k := range c1.unknownKeys { + unknowns[k] = struct{}{} + } + for _, k := range c2.unknownKeys { + unknowns[k] = struct{}{} + } + for k, _ := range unknowns { + c.unknownKeys = append(c.unknownKeys, k) + } + + if len(c1.Outputs) > 0 || len(c2.Outputs) > 0 { + c.Outputs = make( + []*Output, 0, len(c1.Outputs)+len(c2.Outputs)) + c.Outputs = append(c.Outputs, c1.Outputs...) + c.Outputs = append(c.Outputs, c2.Outputs...) + } + + if len(c1.ProviderConfigs) > 0 || len(c2.ProviderConfigs) > 0 { + c.ProviderConfigs = make( + []*ProviderConfig, + 0, len(c1.ProviderConfigs)+len(c2.ProviderConfigs)) + c.ProviderConfigs = append(c.ProviderConfigs, c1.ProviderConfigs...) + c.ProviderConfigs = append(c.ProviderConfigs, c2.ProviderConfigs...) + } + + if len(c1.Resources) > 0 || len(c2.Resources) > 0 { + c.Resources = make( + []*Resource, + 0, len(c1.Resources)+len(c2.Resources)) + c.Resources = append(c.Resources, c1.Resources...) + c.Resources = append(c.Resources, c2.Resources...) + } + + if len(c1.Variables) > 0 || len(c2.Variables) > 0 { + c.Variables = make( + []*Variable, 0, len(c1.Variables)+len(c2.Variables)) + c.Variables = append(c.Variables, c1.Variables...) + c.Variables = append(c.Variables, c2.Variables...) + } + + return c, nil +} diff --git a/config/append_test.go b/config/append_test.go new file mode 100644 index 000000000..4a7fb9d1e --- /dev/null +++ b/config/append_test.go @@ -0,0 +1,83 @@ +package config + +import ( + "reflect" + "testing" +) + +func TestAppend(t *testing.T) { + cases := []struct { + c1, c2, result *Config + err bool + }{ + { + &Config{ + Outputs: []*Output{ + &Output{Name: "foo"}, + }, + ProviderConfigs: []*ProviderConfig{ + &ProviderConfig{Name: "foo"}, + }, + Resources: []*Resource{ + &Resource{Name: "foo"}, + }, + Variables: []*Variable{ + &Variable{Name: "foo"}, + }, + + unknownKeys: []string{"foo"}, + }, + + &Config{ + Outputs: []*Output{ + &Output{Name: "bar"}, + }, + ProviderConfigs: []*ProviderConfig{ + &ProviderConfig{Name: "bar"}, + }, + Resources: []*Resource{ + &Resource{Name: "bar"}, + }, + Variables: []*Variable{ + &Variable{Name: "bar"}, + }, + + unknownKeys: []string{"bar"}, + }, + + &Config{ + Outputs: []*Output{ + &Output{Name: "foo"}, + &Output{Name: "bar"}, + }, + ProviderConfigs: []*ProviderConfig{ + &ProviderConfig{Name: "foo"}, + &ProviderConfig{Name: "bar"}, + }, + Resources: []*Resource{ + &Resource{Name: "foo"}, + &Resource{Name: "bar"}, + }, + Variables: []*Variable{ + &Variable{Name: "foo"}, + &Variable{Name: "bar"}, + }, + + unknownKeys: []string{"foo", "bar"}, + }, + + false, + }, + } + + for i, tc := range cases { + actual, err := Append(tc.c1, tc.c2) + if (err != nil) != tc.err { + t.Fatalf("%d: error fail", i) + } + + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf("%d: bad:\n\n%#v", i, actual) + } + } +}