Files
steampipe/pkg/control/controldisplay/control.go

133 lines
3.8 KiB
Go

package controldisplay
import (
"fmt"
"strings"
"github.com/spf13/viper"
typehelpers "github.com/turbot/go-kit/types"
"github.com/turbot/steampipe/pkg/constants"
"github.com/turbot/steampipe/pkg/control/controlexecute"
)
type ControlRenderer struct {
run *controlexecute.ControlRun
parent *GroupRenderer
maxFailedControls int
maxTotalControls int
// screen width
width int
colorGenerator *controlexecute.DimensionColorGenerator
lastChild bool
}
func NewControlRenderer(run *controlexecute.ControlRun, parent *GroupRenderer) *ControlRenderer {
r := &ControlRenderer{
run: run,
parent: parent,
maxFailedControls: parent.maxFailedControls,
maxTotalControls: parent.maxTotalControls,
colorGenerator: parent.resultTree.DimensionColorGenerator,
width: parent.width,
}
r.lastChild = r.isLastChild()
return r
}
// are we the last child of our parent?
// this affects the tree rendering
func (r ControlRenderer) isLastChild() bool {
if r.parent.group == nil || r.parent.group.GroupItem == nil {
return true
}
siblings := r.parent.group.GroupItem.GetChildren()
return r.run.Control.Name() == siblings[len(siblings)-1].Name()
}
// get the indent inherited from our parent
// - this will depend on whether we are our parents last child
func (r ControlRenderer) parentIndent() string {
if r.lastChild {
return r.parent.lastChildIndent()
}
return r.parent.childIndent()
}
// indent before first result
func (r ControlRenderer) preResultIndent() string {
// when we do not have any rows, do not add a '|' to indent
if viper.GetBool(constants.ArgDryRun) || len(r.run.Rows) == 0 {
return r.parentIndent()
}
return r.parentIndent() + "| "
}
// indent before first result
func (r ControlRenderer) resultIndent() string {
return r.parentIndent()
}
// indent after last result
func (r ControlRenderer) postResultIndent() string {
return r.parentIndent()
}
func (r ControlRenderer) Render() string {
var controlStrings []string
// use group heading renderer to render the control title and counts
controlHeadingRenderer := NewGroupHeadingRenderer(typehelpers.SafeString(r.run.Control.Title),
r.run.Summary.FailedCount(),
r.run.Summary.TotalCount(),
r.maxFailedControls,
r.maxTotalControls,
r.width,
r.parent.childGroupIndent())
// set the severity on the heading renderer
controlHeadingRenderer.severity = typehelpers.SafeString(r.run.Control.Severity)
// get formatted indents
formattedPostResultIndent := fmt.Sprintf("%s", ControlColors.Indent(r.postResultIndent()))
formattedPreResultIndent := fmt.Sprintf("%s", ControlColors.Indent(r.preResultIndent()))
controlStrings = append(controlStrings,
controlHeadingRenderer.Render(),
// newline after control heading
formattedPreResultIndent)
// if the control is in error, render an error
if r.run.GetError() != nil {
errorRenderer := NewErrorRenderer(r.run.GetError(), r.width, r.parentIndent())
controlStrings = append(controlStrings,
errorRenderer.Render(),
// newline after error
formattedPostResultIndent)
}
// now render the results (if any)
var resultStrings []string
for _, row := range r.run.Rows {
resultRenderer := NewResultRenderer(
row.Status,
row.Reason,
row.Dimensions,
r.colorGenerator,
r.width,
r.resultIndent())
// the result renderer may not render the result - in quiet mode only failures are rendered
if resultString := resultRenderer.Render(); resultString != "" {
resultStrings = append(resultStrings, resultString)
}
}
// newline after results
if len(resultStrings) > 0 {
controlStrings = append(controlStrings, resultStrings...)
if len(r.run.Rows) > 0 || r.run.GetError() != nil {
controlStrings = append(controlStrings, formattedPostResultIndent)
}
}
return strings.Join(controlStrings, "\n")
}