github.com/pulumi/terraform@v1.4.0/pkg/command/jsonformat/computed/renderers/list.go (about) 1 package renderers 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/pulumi/terraform/pkg/command/jsonformat/computed" 8 "github.com/pulumi/terraform/pkg/plans" 9 ) 10 11 var _ computed.DiffRenderer = (*listRenderer)(nil) 12 13 func List(elements []computed.Diff) computed.DiffRenderer { 14 return &listRenderer{ 15 displayContext: true, 16 elements: elements, 17 } 18 } 19 20 func NestedList(elements []computed.Diff) computed.DiffRenderer { 21 return &listRenderer{ 22 elements: elements, 23 } 24 } 25 26 type listRenderer struct { 27 NoWarningsRenderer 28 29 displayContext bool 30 elements []computed.Diff 31 } 32 33 func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { 34 if len(renderer.elements) == 0 { 35 return fmt.Sprintf("[]%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) 36 } 37 38 elementOpts := opts.Clone() 39 elementOpts.OverrideNullSuffix = true 40 41 unchangedElementOpts := opts.Clone() 42 unchangedElementOpts.ShowUnchangedChildren = true 43 44 var unchangedElements []computed.Diff 45 46 // renderNext tells the renderer to print out the next element in the list 47 // whatever state it is in. So, even if a change is a NoOp we will still 48 // print it out if the last change we processed wants us to. 49 renderNext := false 50 51 var buf bytes.Buffer 52 buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(diff.Replace, opts))) 53 for _, element := range renderer.elements { 54 if element.Action == plans.NoOp && !renderNext && !opts.ShowUnchangedChildren { 55 unchangedElements = append(unchangedElements, element) 56 continue 57 } 58 renderNext = false 59 60 opts := elementOpts 61 62 // If we want to display the context around this change, we want to 63 // render the change immediately before this change in the list, and the 64 // change immediately after in the list, even if both these changes are 65 // NoOps. This will give the user reading the diff some context as to 66 // where in the list these changes are being made, as order matters. 67 if renderer.displayContext { 68 // If our list of unchanged elements contains more than one entry 69 // we'll print out a count of the number of unchanged elements that 70 // we skipped. Note, this is the length of the unchanged elements 71 // minus 1 as the most recent unchanged element will be printed out 72 // in full. 73 if len(unchangedElements) > 1 { 74 buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", len(unchangedElements)-1, opts))) 75 } 76 // If our list of unchanged elements contains at least one entry, 77 // we're going to print out the most recent change in full. That's 78 // what happens here. 79 if len(unchangedElements) > 0 { 80 lastElement := unchangedElements[len(unchangedElements)-1] 81 buf.WriteString(fmt.Sprintf("%s%s%s,\n", formatIndent(indent+1), writeDiffActionSymbol(lastElement.Action, unchangedElementOpts), lastElement.RenderHuman(indent+1, unchangedElementOpts))) 82 } 83 // We now reset the unchanged elements list, we've printed out a 84 // count of all the elements we skipped so we start counting from 85 // scratch again. This means that if we process a run of changed 86 // elements, they won't all start printing out summaries of every 87 // change that happened previously. 88 unchangedElements = nil 89 90 if element.Action == plans.NoOp { 91 // If this is a NoOp action then we're going to render it below 92 // so we need to just override the opts we're going to use to 93 // make sure we use the unchanged opts. 94 opts = unchangedElementOpts 95 } else { 96 // As we also want to render the element immediately after any 97 // changes, we make a note here to say we should render the next 98 // change whatever it is. But, we only want to render the next 99 // change if the current change isn't a NoOp. If the current change 100 // is a NoOp then it was told to print by the last change and we 101 // don't want to cascade and print all changes from now on. 102 renderNext = true 103 } 104 } 105 106 for _, warning := range element.WarningsHuman(indent+1, opts) { 107 buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) 108 } 109 buf.WriteString(fmt.Sprintf("%s%s%s,\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, opts), element.RenderHuman(indent+1, opts))) 110 } 111 112 // If we were not displaying any context alongside our changes then the 113 // unchangedElements list will contain every unchanged element, and we'll 114 // print that out as we do with every other collection. 115 // 116 // If we were displaying context, then this will contain any unchanged 117 // elements since our last change, so we should also print it out. 118 if len(unchangedElements) > 0 { 119 buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", len(unchangedElements), opts))) 120 } 121 122 buf.WriteString(fmt.Sprintf("%s%s]%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts))) 123 return buf.String() 124 }