github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/jsonformat/computed/renderers/block.go (about) 1 package renderers 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 8 "github.com/hashicorp/terraform/internal/command/jsonformat/computed" 9 10 "github.com/hashicorp/terraform/internal/plans" 11 ) 12 13 var ( 14 _ computed.DiffRenderer = (*blockRenderer)(nil) 15 16 importantAttributes = []string{ 17 "id", 18 "name", 19 "tags", 20 } 21 ) 22 23 func importantAttribute(attr string) bool { 24 for _, attribute := range importantAttributes { 25 if attribute == attr { 26 return true 27 } 28 } 29 return false 30 } 31 32 func Block(attributes map[string]computed.Diff, blocks Blocks) computed.DiffRenderer { 33 return &blockRenderer{ 34 attributes: attributes, 35 blocks: blocks, 36 } 37 } 38 39 type blockRenderer struct { 40 NoWarningsRenderer 41 42 attributes map[string]computed.Diff 43 blocks Blocks 44 } 45 46 func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { 47 if len(renderer.attributes) == 0 && len(renderer.blocks.GetAllKeys()) == 0 { 48 return fmt.Sprintf("{}%s", forcesReplacement(diff.Replace, opts)) 49 } 50 51 unchangedAttributes := 0 52 unchangedBlocks := 0 53 54 maximumAttributeKeyLen := 0 55 var attributeKeys []string 56 escapedAttributeKeys := make(map[string]string) 57 for key := range renderer.attributes { 58 attributeKeys = append(attributeKeys, key) 59 escapedKey := EnsureValidAttributeName(key) 60 escapedAttributeKeys[key] = escapedKey 61 if maximumAttributeKeyLen < len(escapedKey) { 62 maximumAttributeKeyLen = len(escapedKey) 63 } 64 } 65 sort.Strings(attributeKeys) 66 67 importantAttributeOpts := opts.Clone() 68 importantAttributeOpts.ShowUnchangedChildren = true 69 70 attributeOpts := opts.Clone() 71 72 var buf bytes.Buffer 73 buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts))) 74 for _, key := range attributeKeys { 75 attribute := renderer.attributes[key] 76 if importantAttribute(key) { 77 78 // Always display the important attributes. 79 for _, warning := range attribute.WarningsHuman(indent+1, importantAttributeOpts) { 80 buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) 81 } 82 buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, importantAttributeOpts), maximumAttributeKeyLen, key, attribute.RenderHuman(indent+1, importantAttributeOpts))) 83 continue 84 } 85 if attribute.Action == plans.NoOp && !opts.ShowUnchangedChildren { 86 unchangedAttributes++ 87 continue 88 } 89 90 for _, warning := range attribute.WarningsHuman(indent+1, opts) { 91 buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) 92 } 93 buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, attributeOpts), maximumAttributeKeyLen, escapedAttributeKeys[key], attribute.RenderHuman(indent+1, attributeOpts))) 94 } 95 96 if unchangedAttributes > 0 { 97 buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("attribute", unchangedAttributes, opts))) 98 } 99 100 blockKeys := renderer.blocks.GetAllKeys() 101 for _, key := range blockKeys { 102 103 foundChangedBlock := false 104 renderBlock := func(diff computed.Diff, mapKey string, opts computed.RenderHumanOpts) { 105 106 creatingSensitiveValue := diff.Action == plans.Create && renderer.blocks.AfterSensitiveBlocks[key] 107 deletingSensitiveValue := diff.Action == plans.Delete && renderer.blocks.BeforeSensitiveBlocks[key] 108 modifyingSensitiveValue := (diff.Action == plans.Update || diff.Action == plans.NoOp) && (renderer.blocks.AfterSensitiveBlocks[key] || renderer.blocks.BeforeSensitiveBlocks[key]) 109 110 if creatingSensitiveValue || deletingSensitiveValue || modifyingSensitiveValue { 111 // Intercept the renderer here if the sensitive data was set 112 // across all the blocks instead of individually. 113 action := diff.Action 114 if diff.Action == plans.NoOp && renderer.blocks.BeforeSensitiveBlocks[key] != renderer.blocks.AfterSensitiveBlocks[key] { 115 action = plans.Update 116 } 117 118 diff = computed.NewDiff(SensitiveBlock(diff, renderer.blocks.BeforeSensitiveBlocks[key], renderer.blocks.AfterSensitiveBlocks[key]), action, diff.Replace) 119 } 120 121 if diff.Action == plans.NoOp && !opts.ShowUnchangedChildren { 122 unchangedBlocks++ 123 return 124 } 125 126 if !foundChangedBlock && len(renderer.attributes) > 0 { 127 // We always want to put an extra new line between the 128 // attributes and blocks, and between groups of blocks. 129 buf.WriteString("\n") 130 foundChangedBlock = true 131 } 132 133 // If the force replacement metadata was set for every entry in the 134 // block we need to override that here. Our child blocks will only 135 // know about the replace function if it was set on them 136 // specifically, and not if it was set for all the blocks. 137 blockOpts := opts.Clone() 138 blockOpts.OverrideForcesReplacement = renderer.blocks.ReplaceBlocks[key] 139 140 for _, warning := range diff.WarningsHuman(indent+1, blockOpts) { 141 buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) 142 } 143 buf.WriteString(fmt.Sprintf("%s%s%s%s %s\n", formatIndent(indent+1), writeDiffActionSymbol(diff.Action, blockOpts), EnsureValidAttributeName(key), mapKey, diff.RenderHuman(indent+1, blockOpts))) 144 145 } 146 147 switch { 148 case renderer.blocks.IsSingleBlock(key): 149 renderBlock(renderer.blocks.SingleBlocks[key], "", opts) 150 case renderer.blocks.IsMapBlock(key): 151 var keys []string 152 for key := range renderer.blocks.MapBlocks[key] { 153 keys = append(keys, key) 154 } 155 sort.Strings(keys) 156 157 for _, innerKey := range keys { 158 renderBlock(renderer.blocks.MapBlocks[key][innerKey], fmt.Sprintf(" %q", innerKey), opts) 159 } 160 case renderer.blocks.IsSetBlock(key): 161 162 setOpts := opts.Clone() 163 setOpts.OverrideForcesReplacement = diff.Replace 164 165 for _, block := range renderer.blocks.SetBlocks[key] { 166 renderBlock(block, "", opts) 167 } 168 case renderer.blocks.IsListBlock(key): 169 for _, block := range renderer.blocks.ListBlocks[key] { 170 renderBlock(block, "", opts) 171 } 172 } 173 } 174 175 if unchangedBlocks > 0 { 176 buf.WriteString(fmt.Sprintf("\n%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("block", unchangedBlocks, opts))) 177 } 178 179 buf.WriteString(fmt.Sprintf("%s%s}", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts))) 180 return buf.String() 181 }