cli-utils/pkg/print/list/base.go

132 lines
3.8 KiB
Go

// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package list
import (
"sigs.k8s.io/cli-utils/pkg/apply/event"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/object"
printcommon "sigs.k8s.io/cli-utils/pkg/print/common"
"sigs.k8s.io/cli-utils/pkg/print/stats"
)
type Formatter interface {
FormatValidationEvent(ve event.ValidationEvent) error
FormatApplyEvent(ae event.ApplyEvent) error
FormatStatusEvent(se event.StatusEvent) error
FormatPruneEvent(pe event.PruneEvent) error
FormatDeleteEvent(de event.DeleteEvent) error
FormatWaitEvent(we event.WaitEvent) error
FormatErrorEvent(ee event.ErrorEvent) error
FormatActionGroupEvent(
age event.ActionGroupEvent,
ags []event.ActionGroup,
s stats.Stats,
c Collector,
) error
}
type FormatterFactory func(previewStrategy common.DryRunStrategy) Formatter
type BaseListPrinter struct {
FormatterFactory FormatterFactory
}
type Collector interface {
LatestStatus() map[object.ObjMetadata]event.StatusEvent
}
type StatusCollector struct {
latestStatus map[object.ObjMetadata]event.StatusEvent
}
func (sc *StatusCollector) updateStatus(id object.ObjMetadata, se event.StatusEvent) {
sc.latestStatus[id] = se
}
func (sc *StatusCollector) LatestStatus() map[object.ObjMetadata]event.StatusEvent {
return sc.latestStatus
}
// Print outputs the events from the provided channel in a simple
// format on StdOut. As we support other printer implementations
// this should probably be an interface.
// This function will block until the channel is closed.
//nolint:gocyclo
func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.DryRunStrategy, printStatus bool) error {
var actionGroups []event.ActionGroup
var statsCollector stats.Stats
statusCollector := &StatusCollector{
latestStatus: make(map[object.ObjMetadata]event.StatusEvent),
}
formatter := b.FormatterFactory(previewStrategy)
for e := range ch {
statsCollector.Handle(e)
switch e.Type {
case event.InitType:
actionGroups = e.InitEvent.ActionGroups
case event.ErrorType:
_ = formatter.FormatErrorEvent(e.ErrorEvent)
return e.ErrorEvent.Err
case event.ValidationType:
if err := formatter.FormatValidationEvent(e.ValidationEvent); err != nil {
return err
}
case event.ApplyType:
if err := formatter.FormatApplyEvent(e.ApplyEvent); err != nil {
return err
}
case event.StatusType:
statusCollector.updateStatus(e.StatusEvent.Identifier, e.StatusEvent)
if printStatus {
if err := formatter.FormatStatusEvent(e.StatusEvent); err != nil {
return err
}
}
case event.PruneType:
if err := formatter.FormatPruneEvent(e.PruneEvent); err != nil {
return err
}
case event.DeleteType:
if err := formatter.FormatDeleteEvent(e.DeleteEvent); err != nil {
return err
}
case event.WaitType:
if err := formatter.FormatWaitEvent(e.WaitEvent); err != nil {
return err
}
case event.ActionGroupType:
if err := formatter.FormatActionGroupEvent(
e.ActionGroupEvent,
actionGroups,
statsCollector,
statusCollector,
); err != nil {
return err
}
}
}
return printcommon.ResultErrorFromStats(statsCollector)
}
// IsLastActionGroup returns true if the passed ActionGroupEvent is the
// last of its type in the slice of ActionGroup; false otherwise. For example,
// this function will determine if an ApplyAction is the last ApplyAction in
// the initialized task queue. This functionality is current used to determine
// when to print stats.
func IsLastActionGroup(age event.ActionGroupEvent, ags []event.ActionGroup) bool {
var found bool
var action event.ResourceAction
for _, ag := range ags {
if found && (action == ag.Action) {
return false
}
if age.GroupName == ag.Name {
found = true
action = age.Action
}
}
return true
}