diff --git a/pkg/printers/tablegenerator.go b/pkg/printers/tablegenerator.go index d6bf97caf70..7b39f183ab7 100644 --- a/pkg/printers/tablegenerator.go +++ b/pkg/printers/tablegenerator.go @@ -43,30 +43,25 @@ type handlerEntry struct { args []reflect.Value } -// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide -// more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers -// will only be printed if the object type changes. This makes it useful for printing items -// received from watches. -type HumanReadablePrinter struct { - handlerMap map[reflect.Type]*handlerEntry - options PrintOptions - lastType interface{} - lastColumns []metav1beta1.TableColumnDefinition - printedHeaders bool +// HumanReadableGenerator is an implementation of TableGenerator used to generate +// a table for a specific resource. The table is printed with a TablePrinter using +// PrintObj(). +type HumanReadableGenerator struct { + handlerMap map[reflect.Type]*handlerEntry } -var _ TableGenerator = &HumanReadablePrinter{} -var _ PrintHandler = &HumanReadablePrinter{} +var _ TableGenerator = &HumanReadableGenerator{} +var _ PrintHandler = &HumanReadableGenerator{} -// NewTableGenerator creates a HumanReadablePrinter suitable for calling GenerateTable(). -func NewTableGenerator() *HumanReadablePrinter { - return &HumanReadablePrinter{ +// NewTableGenerator creates a HumanReadableGenerator suitable for calling GenerateTable(). +func NewTableGenerator() *HumanReadableGenerator { + return &HumanReadableGenerator{ handlerMap: make(map[reflect.Type]*handlerEntry), } } -// With method - accepts a list of builder functions that modify HumanReadablePrinter -func (h *HumanReadablePrinter) With(fns ...func(PrintHandler)) *HumanReadablePrinter { +// With method - accepts a list of builder functions that modify HumanReadableGenerator +func (h *HumanReadableGenerator) With(fns ...func(PrintHandler)) *HumanReadableGenerator { for _, fn := range fns { fn(h) } @@ -76,7 +71,7 @@ func (h *HumanReadablePrinter) With(fns ...func(PrintHandler)) *HumanReadablePri // GenerateTable returns a table for the provided object, using the printer registered for that type. It returns // a table that includes all of the information requested by options, but will not remove rows or columns. The // caller is responsible for applying rules related to filtering rows or columns. -func (h *HumanReadablePrinter) GenerateTable(obj runtime.Object, options PrintOptions) (*metav1beta1.Table, error) { +func (h *HumanReadableGenerator) GenerateTable(obj runtime.Object, options PrintOptions) (*metav1beta1.Table, error) { t := reflect.TypeOf(obj) handler, ok := h.handlerMap[t] if !ok { @@ -126,9 +121,9 @@ func (h *HumanReadablePrinter) GenerateTable(obj runtime.Object, options PrintOp return table, nil } -// TableHandler adds a print handler with a given set of columns to HumanReadablePrinter instance. +// TableHandler adds a print handler with a given set of columns to HumanReadableGenerator instance. // See ValidateRowPrintHandlerFunc for required method signature. -func (h *HumanReadablePrinter) TableHandler(columnDefinitions []metav1beta1.TableColumnDefinition, printFunc interface{}) error { +func (h *HumanReadableGenerator) TableHandler(columnDefinitions []metav1beta1.TableColumnDefinition, printFunc interface{}) error { printFuncValue := reflect.ValueOf(printFunc) if err := ValidateRowPrintHandlerFunc(printFuncValue); err != nil { utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err)) diff --git a/pkg/printers/tableprinter.go b/pkg/printers/tableprinter.go index 7b6ab4ecbca..9aba99246eb 100644 --- a/pkg/printers/tableprinter.go +++ b/pkg/printers/tableprinter.go @@ -61,13 +61,23 @@ var ( withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too. ) +// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide +// more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers +// will only be printed if the object type changes. This makes it useful for printing items +// received from watches. +type HumanReadablePrinter struct { + options PrintOptions + lastType interface{} + lastColumns []metav1beta1.TableColumnDefinition + printedHeaders bool +} + // NewTablePrinter creates a printer suitable for calling PrintObj(). // TODO(seans3): Change return type to ResourcePrinter interface once we no longer need // to constuct the "handlerMap". func NewTablePrinter(options PrintOptions) *HumanReadablePrinter { printer := &HumanReadablePrinter{ - handlerMap: make(map[reflect.Type]*handlerEntry), - options: options, + options: options, } return printer } @@ -81,6 +91,7 @@ func printHeader(columnNames []string, w io.Writer) error { // PrintObj prints the obj in a human-friendly format according to the type of the obj. func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error { + w, found := output.(*tabwriter.Writer) if !found { w = GetNewTabWriter(output) @@ -94,7 +105,7 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er obj = event.Object.Object } - // Case 1: Parameter "obj" is a table from server; print it. + // Parameter "obj" is a table from server; print it. // display tables following the rules of options if table, ok := obj.(*metav1beta1.Table); ok { // Do not print headers if this table has no column definitions, or they are the same as the last ones we printed @@ -117,6 +128,8 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er h.printedHeaders = true } + // TODO(seans3): Remove the following decorateTable call. Table modification + // (and creation) should only happen in table generation (tablegenerator.go). if err := decorateTable(table, localOptions); err != nil { return err } @@ -131,25 +144,7 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er return printTable(table, output, localOptions) } - // Case 2: Parameter "obj" is not a table; search for a handler to print it. - // TODO(seans3): Remove this case in 1.16, since table should be returned from server-side printing. - // print with a registered handler - t := reflect.TypeOf(obj) - if handler := h.handlerMap[t]; handler != nil { - includeHeaders := h.lastType != t && !h.options.NoHeaders - - if h.lastType != nil && h.lastType != t && !h.options.NoHeaders { - fmt.Fprintln(output) - } - - if err := printRowsForHandlerEntry(output, handler, eventType, obj, h.options, includeHeaders); err != nil { - return err - } - h.lastType = t - return nil - } - - // Case 3: Could not find print handler for "obj"; use the default or status print handler. + // Could not find print handler for "obj"; use the default or status print handler. // Print with the default or status handler, and use the columns from the last time var handler *handlerEntry if _, isStatus := obj.(*metav1.Status); isStatus { @@ -291,6 +286,9 @@ func addColumns(pos columnAddPosition, table *metav1beta1.Table, columns []metav return nil } +// TODO(seans3): This method modifies the table, to it should only happen +// during table generation (tablegenerator.go), and not during table printing. +// // decorateTable takes a table and attempts to add label columns and the // namespace column. It will fill empty columns with nil (if the object // does not expose metadata). It returns an error if the table cannot