github.com/opentofu/opentofu@v1.7.1/internal/command/jsonformat/computed/renderers/util.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package renderers 7 8 import ( 9 "fmt" 10 "strings" 11 12 "github.com/opentofu/opentofu/internal/command/format" 13 14 "github.com/hashicorp/hcl/v2/hclsyntax" 15 16 "github.com/opentofu/opentofu/internal/command/jsonformat/computed" 17 "github.com/opentofu/opentofu/internal/plans" 18 ) 19 20 // NoWarningsRenderer defines a Warnings function that returns an empty list of 21 // warnings. This can be used by other renderers to ensure we don't see lots of 22 // repeats of this empty function. 23 type NoWarningsRenderer struct{} 24 25 // WarningsHuman returns an empty slice, as the name NoWarningsRenderer suggests. 26 func (render NoWarningsRenderer) WarningsHuman(_ computed.Diff, _ int, _ computed.RenderHumanOpts) []string { 27 return nil 28 } 29 30 // nullSuffix returns the `-> null` suffix if the change is a delete action, and 31 // it has not been overridden. 32 func nullSuffix(action plans.Action, opts computed.RenderHumanOpts) string { 33 if !opts.OverrideNullSuffix && action == plans.Delete { 34 return opts.Colorize.Color(" [dark_gray]-> null[reset]") 35 } 36 return "" 37 } 38 39 // forcesReplacement returns the `# forces replacement` suffix if this change is 40 // driving the entire resource to be replaced. 41 func forcesReplacement(replace bool, opts computed.RenderHumanOpts) string { 42 if replace || opts.OverrideForcesReplacement { 43 return opts.Colorize.Color(" [red]# forces replacement[reset]") 44 } 45 return "" 46 } 47 48 // indent returns whitespace that is the required length for the specified 49 // indent. 50 func formatIndent(indent int) string { 51 return strings.Repeat(" ", indent) 52 } 53 54 // unchanged prints out a description saying how many of 'keyword' have been 55 // hidden because they are unchanged or noop actions. 56 func unchanged(keyword string, count int, opts computed.RenderHumanOpts) string { 57 if count == 1 { 58 return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", count, keyword)) 59 } 60 return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %ss hidden)[reset]", count, keyword)) 61 } 62 63 // EnsureValidAttributeName checks if `name` contains any HCL syntax and calls 64 // and returns hclEscapeString. 65 func EnsureValidAttributeName(name string) string { 66 if !hclsyntax.ValidIdentifier(name) { 67 return hclEscapeString(name) 68 } 69 return name 70 } 71 72 // hclEscapeString formats the input string into a format that is safe for 73 // rendering within HCL. 74 // 75 // Note, this function doesn't actually do a very good job of this currently. We 76 // need to expose some internal functions from HCL in a future version and call 77 // them from here. For now, just use "%q" formatting. 78 func hclEscapeString(str string) string { 79 // TODO: Replace this with more complete HCL logic instead of the simple 80 // go workaround. 81 return fmt.Sprintf("%q", str) 82 } 83 84 // writeDiffActionSymbol writes out the symbols for the associated action, and 85 // handles localized colorization of the symbol as well as indenting the symbol 86 // to be 4 spaces wide. 87 // 88 // If the opts has HideDiffActionSymbols set then this function returns an empty 89 // string. 90 func writeDiffActionSymbol(action plans.Action, opts computed.RenderHumanOpts) string { 91 if opts.HideDiffActionSymbols { 92 return "" 93 } 94 return fmt.Sprintf("%s ", opts.Colorize.Color(format.DiffActionSymbol(action))) 95 }