github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/control/controldisplay/control.go (about) 1 package controldisplay 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/spf13/viper" 8 typehelpers "github.com/turbot/go-kit/types" 9 "github.com/turbot/steampipe/pkg/constants" 10 "github.com/turbot/steampipe/pkg/control/controlexecute" 11 ) 12 13 type ControlRenderer struct { 14 run *controlexecute.ControlRun 15 parent *GroupRenderer 16 maxFailedControls int 17 maxTotalControls int 18 // screen width 19 width int 20 colorGenerator *controlexecute.DimensionColorGenerator 21 lastChild bool 22 } 23 24 func NewControlRenderer(run *controlexecute.ControlRun, parent *GroupRenderer) *ControlRenderer { 25 r := &ControlRenderer{ 26 run: run, 27 parent: parent, 28 maxFailedControls: parent.maxFailedControls, 29 maxTotalControls: parent.maxTotalControls, 30 colorGenerator: parent.resultTree.DimensionColorGenerator, 31 width: parent.width, 32 } 33 r.lastChild = r.isLastChild() 34 return r 35 } 36 37 // are we the last child of our parent? 38 // this affects the tree rendering 39 func (r ControlRenderer) isLastChild() bool { 40 if r.parent.group == nil || r.parent.group.GroupItem == nil { 41 return true 42 } 43 siblings := r.parent.group.GroupItem.GetChildren() 44 return r.run.Control.Name() == siblings[len(siblings)-1].Name() 45 } 46 47 // get the indent inherited from our parent 48 // - this will depend on whether we are our parents last child 49 func (r ControlRenderer) parentIndent() string { 50 if r.lastChild { 51 return r.parent.lastChildIndent() 52 } 53 return r.parent.childIndent() 54 } 55 56 // indent before first result 57 func (r ControlRenderer) preResultIndent() string { 58 // when we do not have any rows, do not add a '|' to indent 59 if viper.GetBool(constants.ArgDryRun) || len(r.run.Rows) == 0 { 60 return r.parentIndent() 61 } 62 return r.parentIndent() + "| " 63 } 64 65 // indent before first result 66 func (r ControlRenderer) resultIndent() string { 67 return r.parentIndent() 68 } 69 70 // indent after last result 71 func (r ControlRenderer) postResultIndent() string { 72 return r.parentIndent() 73 } 74 75 func (r ControlRenderer) Render() string { 76 var controlStrings []string 77 // use group heading renderer to render the control title and counts 78 controlHeadingRenderer := NewGroupHeadingRenderer(typehelpers.SafeString(r.run.Control.Title), 79 r.run.Summary.FailedCount(), 80 r.run.Summary.TotalCount(), 81 r.maxFailedControls, 82 r.maxTotalControls, 83 r.width, 84 r.parent.childGroupIndent()) 85 86 // set the severity on the heading renderer 87 controlHeadingRenderer.severity = typehelpers.SafeString(r.run.Control.Severity) 88 89 // get formatted indents 90 formattedPostResultIndent := fmt.Sprintf("%s", ControlColors.Indent(r.postResultIndent())) 91 formattedPreResultIndent := fmt.Sprintf("%s", ControlColors.Indent(r.preResultIndent())) 92 93 controlStrings = append(controlStrings, 94 controlHeadingRenderer.Render(), 95 // newline after control heading 96 formattedPreResultIndent) 97 98 // if the control is in error, render an error 99 if r.run.GetError() != nil { 100 errorRenderer := NewErrorRenderer(r.run.GetError(), r.width, r.parentIndent()) 101 controlStrings = append(controlStrings, 102 errorRenderer.Render(), 103 // newline after error 104 formattedPostResultIndent) 105 } 106 107 // now render the results (if any) 108 var resultStrings []string 109 for _, row := range r.run.Rows { 110 resultRenderer := NewResultRenderer( 111 row.Status, 112 row.Reason, 113 row.Dimensions, 114 r.colorGenerator, 115 r.width, 116 r.resultIndent()) 117 // the result renderer may not render the result - in quiet mode only failures are rendered 118 if resultString := resultRenderer.Render(); resultString != "" { 119 resultStrings = append(resultStrings, resultString) 120 } 121 } 122 123 // newline after results 124 if len(resultStrings) > 0 { 125 controlStrings = append(controlStrings, resultStrings...) 126 if len(r.run.Rows) > 0 || r.run.GetError() != nil { 127 controlStrings = append(controlStrings, formattedPostResultIndent) 128 } 129 } 130 131 return strings.Join(controlStrings, "\n") 132 }