github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/jsonformat/computed/diff.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package computed 5 6 import ( 7 "github.com/mitchellh/colorstring" 8 9 "github.com/terramate-io/tf/plans" 10 ) 11 12 // Diff captures the computed diff for a single block, element or attribute. 13 // 14 // It essentially merges common functionality across all types of changes, 15 // namely the replace logic and the action / change type. Any remaining 16 // behaviour can be offloaded to the renderer which will be unique for the 17 // various change types (eg. maps, objects, lists, blocks, primitives, etc.). 18 type Diff struct { 19 // Renderer captures the uncommon functionality across the different kinds 20 // of changes. Each type of change (lists, blocks, sets, etc.) will have a 21 // unique renderer. 22 Renderer DiffRenderer 23 24 // Action is the action described by this change (such as create, delete, 25 // update, etc.). 26 Action plans.Action 27 28 // Replace tells the Change that it should add the `# forces replacement` 29 // suffix. 30 // 31 // Every single change could potentially add this suffix, so we embed it in 32 // the change as common functionality instead of in the specific renderers. 33 Replace bool 34 } 35 36 // NewDiff creates a new Diff object with the provided renderer, action and 37 // replace context. 38 func NewDiff(renderer DiffRenderer, action plans.Action, replace bool) Diff { 39 return Diff{ 40 Renderer: renderer, 41 Action: action, 42 Replace: replace, 43 } 44 } 45 46 // RenderHuman prints the Change into a human-readable string referencing the 47 // specified RenderOpts. 48 // 49 // If the returned string is a single line, then indent should be ignored. 50 // 51 // If the return string is multiple lines, then indent should be used to offset 52 // the beginning of all lines but the first by the specified amount. 53 func (diff Diff) RenderHuman(indent int, opts RenderHumanOpts) string { 54 return diff.Renderer.RenderHuman(diff, indent, opts) 55 } 56 57 // WarningsHuman returns a list of strings that should be rendered as warnings 58 // before a given change is rendered. 59 // 60 // As with the RenderHuman function, the indent should only be applied on 61 // multiline warnings and on the second and following lines. 62 func (diff Diff) WarningsHuman(indent int, opts RenderHumanOpts) []string { 63 return diff.Renderer.WarningsHuman(diff, indent, opts) 64 } 65 66 type DiffRenderer interface { 67 RenderHuman(diff Diff, indent int, opts RenderHumanOpts) string 68 WarningsHuman(diff Diff, indent int, opts RenderHumanOpts) []string 69 } 70 71 // RenderHumanOpts contains options that can control how the human render 72 // function of the DiffRenderer will function. 73 type RenderHumanOpts struct { 74 Colorize *colorstring.Colorize 75 76 // OverrideNullSuffix tells the Renderer not to display the `-> null` suffix 77 // that is normally displayed when an element, attribute, or block is 78 // deleted. 79 OverrideNullSuffix bool 80 81 // OverrideForcesReplacement tells the Renderer to display the 82 // `# forces replacement` suffix, even if a diff doesn't have the Replace 83 // field set. 84 // 85 // Some renderers (like the Set renderer) don't display the suffix 86 // themselves but force their child diffs to display it instead. 87 OverrideForcesReplacement bool 88 89 // ShowUnchangedChildren instructs the Renderer to render all children of a 90 // given complex change, instead of hiding unchanged items and compressing 91 // them into a single line. 92 ShowUnchangedChildren bool 93 94 // HideDiffActionSymbols tells the renderer not to show the '+'/'-' symbols 95 // and to skip the places where the symbols would result in an offset. 96 HideDiffActionSymbols bool 97 } 98 99 // NewRenderHumanOpts creates a new RenderHumanOpts struct with the required 100 // fields set. 101 func NewRenderHumanOpts(colorize *colorstring.Colorize) RenderHumanOpts { 102 return RenderHumanOpts{ 103 Colorize: colorize, 104 } 105 } 106 107 // Clone returns a new RenderOpts object, that matches the original but can be 108 // edited without changing the original. 109 func (opts RenderHumanOpts) Clone() RenderHumanOpts { 110 return RenderHumanOpts{ 111 Colorize: opts.Colorize, 112 113 OverrideNullSuffix: opts.OverrideNullSuffix, 114 ShowUnchangedChildren: opts.ShowUnchangedChildren, 115 HideDiffActionSymbols: opts.HideDiffActionSymbols, 116 117 // OverrideForcesReplacement is a special case in that it doesn't 118 // cascade. So each diff should decide independently whether it's direct 119 // children should override their internal Replace logic, instead of 120 // an ancestor making the switch and affecting the entire tree. 121 OverrideForcesReplacement: false, 122 } 123 }