...

Source file src/sigs.k8s.io/cli-utils/pkg/print/table/base.go

Documentation: sigs.k8s.io/cli-utils/pkg/print/table

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package table
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"strings"
    10  	"unicode/utf8"
    11  
    12  	"k8s.io/cli-runtime/pkg/genericclioptions"
    13  	pe "sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
    14  	"sigs.k8s.io/cli-utils/pkg/object"
    15  	"sigs.k8s.io/cli-utils/pkg/print/common"
    16  )
    17  
    18  // ColumnDefinition defines the columns that should be printed.
    19  type ColumnDefinition interface {
    20  	Name() string
    21  	Header() string
    22  	Width() int
    23  	PrintResource(w io.Writer, width int, r Resource) (int, error)
    24  }
    25  
    26  // ResourceStates defines the interface that must be implemented
    27  // by the object that provides information about the resources
    28  // that should be printed.
    29  type ResourceStates interface {
    30  	Resources() []Resource
    31  	Error() error
    32  }
    33  
    34  // Resource defines the interface that each of the Resource
    35  // objects must implement.
    36  type Resource interface {
    37  	Identifier() object.ObjMetadata
    38  	ResourceStatus() *pe.ResourceStatus
    39  	SubResources() []Resource
    40  }
    41  
    42  // BaseTablePrinter provides functionality for printing information
    43  // about a set of resources into a table format.
    44  // The printer will print to the Out stream defined in IOStreams,
    45  // and will print into the format defined by the Column definitions.
    46  type BaseTablePrinter struct {
    47  	IOStreams genericclioptions.IOStreams
    48  	Columns   []ColumnDefinition
    49  }
    50  
    51  // PrintTable prints the resources defined in ResourceStates. It will
    52  // print subresources if they exist.
    53  // moveUpCount defines how many lines the printer should move up
    54  // before starting printing. The return value is how many lines
    55  // were printed.
    56  func (t *BaseTablePrinter) PrintTable(rs ResourceStates,
    57  	moveUpCount int) int {
    58  	for i := 0; i < moveUpCount; i++ {
    59  		t.moveUp()
    60  		t.eraseCurrentLine()
    61  	}
    62  
    63  	linePrintCount := 0
    64  	for i, column := range t.Columns {
    65  		format := fmt.Sprintf("%%-%ds", column.Width())
    66  		t.printOrDie(format, column.Header())
    67  		if i == len(t.Columns)-1 {
    68  			t.printOrDie("\n")
    69  			linePrintCount++
    70  		} else {
    71  			t.printOrDie("  ")
    72  		}
    73  	}
    74  
    75  	for _, resource := range rs.Resources() {
    76  		for i, column := range t.Columns {
    77  			written, err := column.PrintResource(t.IOStreams.Out, column.Width(), resource)
    78  			if err != nil {
    79  				panic(err)
    80  			}
    81  			remainingSpace := column.Width() - written
    82  			t.printOrDie(strings.Repeat(" ", remainingSpace))
    83  			if i == len(t.Columns)-1 {
    84  				t.printOrDie("\n")
    85  				linePrintCount++
    86  			} else {
    87  				t.printOrDie("  ")
    88  			}
    89  		}
    90  
    91  		linePrintCount += t.printSubTable(resource.SubResources(), "")
    92  	}
    93  
    94  	return linePrintCount
    95  }
    96  
    97  // printSubTable prints out any subresources that belong to the
    98  // top-level resources. This function takes care of printing the correct tree
    99  // structure and indentation.
   100  func (t *BaseTablePrinter) printSubTable(resources []Resource,
   101  	prefix string) int {
   102  	linePrintCount := 0
   103  	for j, resource := range resources {
   104  		for i, column := range t.Columns {
   105  			availableWidth := column.Width()
   106  			if column.Name() == "resource" {
   107  				if j < len(resources)-1 {
   108  					t.printOrDie(prefix + `├─ `)
   109  				} else {
   110  					t.printOrDie(prefix + `└─ `)
   111  				}
   112  				availableWidth -= utf8.RuneCountInString(prefix) + 3
   113  			}
   114  			written, err := column.PrintResource(t.IOStreams.Out,
   115  				availableWidth, resource)
   116  			if err != nil {
   117  				panic(err)
   118  			}
   119  			remainingSpace := availableWidth - written
   120  			t.printOrDie(strings.Repeat(" ", remainingSpace))
   121  			if i == len(t.Columns)-1 {
   122  				t.printOrDie("\n")
   123  				linePrintCount++
   124  			} else {
   125  				t.printOrDie("  ")
   126  			}
   127  		}
   128  
   129  		var prefix string
   130  		if j < len(resources)-1 {
   131  			prefix = `│  `
   132  		} else {
   133  			prefix = "   "
   134  		}
   135  		linePrintCount += t.printSubTable(resource.SubResources(), prefix)
   136  	}
   137  	return linePrintCount
   138  }
   139  
   140  func (t *BaseTablePrinter) printOrDie(format string, a ...interface{}) {
   141  	_, err := fmt.Fprintf(t.IOStreams.Out, format, a...)
   142  	if err != nil {
   143  		panic(err)
   144  	}
   145  }
   146  
   147  func (t *BaseTablePrinter) moveUp() {
   148  	t.printOrDie("%c[%dA", common.ESC, 1)
   149  }
   150  
   151  func (t *BaseTablePrinter) eraseCurrentLine() {
   152  	t.printOrDie("%c[2K\r", common.ESC)
   153  }
   154  

View as plain text