| package jsonformat |
| |
| import ( |
| "github.com/hashicorp/terraform/internal/command/jsonformat/computed" |
| "github.com/hashicorp/terraform/internal/command/jsonformat/differ" |
| "github.com/hashicorp/terraform/internal/command/jsonformat/structured" |
| "github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path" |
| "github.com/hashicorp/terraform/internal/command/jsonplan" |
| "github.com/hashicorp/terraform/internal/plans" |
| ) |
| |
| func precomputeDiffs(plan Plan, mode plans.Mode) diffs { |
| diffs := diffs{ |
| outputs: make(map[string]computed.Diff), |
| } |
| |
| for _, drift := range plan.ResourceDrift { |
| |
| var relevantAttrs attribute_path.Matcher |
| if mode == plans.RefreshOnlyMode { |
| // For a refresh only plan, we show all the drift. |
| relevantAttrs = attribute_path.AlwaysMatcher() |
| } else { |
| matcher := attribute_path.Empty(true) |
| |
| // Otherwise we only want to show the drift changes that are |
| // relevant. |
| for _, attr := range plan.RelevantAttributes { |
| if len(attr.Resource) == 0 || attr.Resource == drift.Address { |
| matcher = attribute_path.AppendSingle(matcher, attr.Attr) |
| } |
| } |
| |
| if len(matcher.Paths) > 0 { |
| relevantAttrs = matcher |
| } |
| } |
| |
| if relevantAttrs == nil { |
| // If we couldn't build a relevant attribute matcher, then we are |
| // not going to show anything for this drift. |
| continue |
| } |
| |
| schema := plan.getSchema(drift) |
| change := structured.FromJsonChange(drift.Change, relevantAttrs) |
| diffs.drift = append(diffs.drift, diff{ |
| change: drift, |
| diff: differ.ComputeDiffForBlock(change, schema.Block), |
| }) |
| } |
| |
| for _, change := range plan.ResourceChanges { |
| schema := plan.getSchema(change) |
| structuredChange := structured.FromJsonChange(change.Change, attribute_path.AlwaysMatcher()) |
| diffs.changes = append(diffs.changes, diff{ |
| change: change, |
| diff: differ.ComputeDiffForBlock(structuredChange, schema.Block), |
| }) |
| } |
| |
| for key, output := range plan.OutputChanges { |
| change := structured.FromJsonChange(output, attribute_path.AlwaysMatcher()) |
| diffs.outputs[key] = differ.ComputeDiffForOutput(change) |
| } |
| |
| return diffs |
| } |
| |
| type diffs struct { |
| drift []diff |
| changes []diff |
| outputs map[string]computed.Diff |
| } |
| |
| func (d diffs) Empty() bool { |
| for _, change := range d.changes { |
| if change.diff.Action != plans.NoOp || change.Moved() { |
| return false |
| } |
| } |
| |
| for _, output := range d.outputs { |
| if output.Action != plans.NoOp { |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| type diff struct { |
| change jsonplan.ResourceChange |
| diff computed.Diff |
| } |
| |
| func (d diff) Moved() bool { |
| return len(d.change.PreviousAddress) > 0 && d.change.PreviousAddress != d.change.Address |
| } |