From 908c3aeb704b47e57d2c2f977d408dcc298ddd7a Mon Sep 17 00:00:00 2001 From: Pat Gavlin Date: Tue, 8 Dec 2020 12:34:32 -0800 Subject: [PATCH] Update message --- pkg/resource/deploy/plan.go | 14 ++++++-- sdk/go/common/resource/properties_diff.go | 43 +++++++++++++++++++++++ sdk/go/common/resource/properties_path.go | 34 ++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/pkg/resource/deploy/plan.go b/pkg/resource/deploy/plan.go index c36267488..38706a178 100644 --- a/pkg/resource/deploy/plan.go +++ b/pkg/resource/deploy/plan.go @@ -188,9 +188,19 @@ func (rp *ResourcePlan) checkGoal(programGoal *resource.Goal) error { } // Check that the properties meet the constraints set in the plan. - if _, constrained := programGoal.Properties.ConstrainedTo(rp.Goal.Properties); !constrained { + if diff, constrained := programGoal.Properties.ConstrainedTo(rp.Goal.Properties); !constrained { // TODO(pdg-plan): message! - return fmt.Errorf("properties changed") + var paths []string + for k := range diff.Adds { + paths = append(paths, "+"+string(k)) + } + for k := range diff.Deletes { + paths = append(paths, "-"+string(k)) + } + for k := range diff.Updates { + paths = append(paths, "~"+string(k)) + } + return fmt.Errorf("properties changed: %v", strings.Join(paths, ", ")) } // Check that the property dependencies match. Note that because it is legal for a property that is unknown in the diff --git a/sdk/go/common/resource/properties_diff.go b/sdk/go/common/resource/properties_diff.go index 837f1a463..4386dec5a 100644 --- a/sdk/go/common/resource/properties_diff.go +++ b/sdk/go/common/resource/properties_diff.go @@ -74,6 +74,22 @@ func (diff *ObjectDiff) Keys() []PropertyKey { return ks } +func (diff *ObjectDiff) Paths() []PropertyPath { + var paths []PropertyPath + for k := range diff.Adds { + paths = append(paths, PropertyPath{string(k)}) + } + for k := range diff.Adds { + paths = append(paths, PropertyPath{string(k)}) + } + for k, d := range diff.Updates { + for _, child := range d.Paths() { + paths = append(paths, append(PropertyPath{string(k)}, child...)) + } + } + return paths +} + // ValueDiff holds the results of diffing two property values. type ValueDiff struct { Old PropertyValue // the old value. @@ -82,6 +98,17 @@ type ValueDiff struct { Object *ObjectDiff // the object's detailed diffs (only for objects). } +func (diff ValueDiff) Paths() []PropertyPath { + switch { + case diff.Array != nil: + return diff.Array.Paths() + case diff.Object != nil: + return diff.Object.Paths() + default: + return nil + } +} + // ArrayDiff holds the results of diffing two arrays of property values. type ArrayDiff struct { Adds map[int]PropertyValue // elements added in the new. @@ -90,6 +117,22 @@ type ArrayDiff struct { Updates map[int]ValueDiff // elements that have changed in the new. } +func (diff *ArrayDiff) Paths() []PropertyPath { + var paths []PropertyPath + for k := range diff.Adds { + paths = append(paths, PropertyPath{k}) + } + for k := range diff.Adds { + paths = append(paths, PropertyPath{k}) + } + for k, d := range diff.Updates { + for _, child := range d.Paths() { + paths = append(paths, append(PropertyPath{k}, child...)) + } + } + return paths +} + // Len computes the length of this array, taking into account adds, deletes, sames, and updates. func (diff *ArrayDiff) Len() int { len := 0 diff --git a/sdk/go/common/resource/properties_path.go b/sdk/go/common/resource/properties_path.go index 98ce3363f..8c66ff083 100644 --- a/sdk/go/common/resource/properties_path.go +++ b/sdk/go/common/resource/properties_path.go @@ -1,6 +1,8 @@ package resource import ( + "bytes" + "fmt" "strconv" "strings" @@ -291,3 +293,35 @@ func (p PropertyPath) Contains(other PropertyPath) bool { return true } + +func requiresQuote(c rune) bool { + return !(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '_') +} + +func (p PropertyPath) String() string { + var buf bytes.Buffer + for _, k := range p { + switch k := k.(type) { + case string: + var keyBuf bytes.Buffer + quoted := false + for _, c := range k { + if requiresQuote(c) { + quoted = true + if c == '"' { + keyBuf.WriteByte('\\') + } + } + keyBuf.WriteRune(c) + } + if !quoted { + fmt.Fprintf(&buf, ".%s", keyBuf.String()) + } else { + fmt.Fprintf(&buf, `["%s"]`, keyBuf.String()) + } + case int: + fmt.Fprintf(&buf, "[%d]", k) + } + } + return buf.String() +}