mirror of https://github.com/knative/client.git
Adds human-friendly table printing for resource listing (#85)
* Adds human-friendly printer All the credits goes to authors of https://github.com/kubernetes/kubernetes/tree/master/pkg/printers * Updates the vendor/modules.txt As its updated after running hack/verify-codegen.sh * Removes WithKind and WithNamespace printing options Lets start with bare minimum printer * Adds licenses and references the original implementation file link. Removes pkg/printers/printers.go * Removes unused imports
This commit is contained in:
parent
ba59ad8b9a
commit
b6d1bb47e7
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following is a subset of original implementation
|
||||||
|
// at https://github.com/kubernetes/kubernetes/blob/v1.15.0-alpha.2/pkg/printers/interface.go
|
||||||
|
|
||||||
|
package printers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourcePrinter is an interface that knows how to print runtime objects.
|
||||||
|
type ResourcePrinter interface {
|
||||||
|
// Print receives a runtime object, formats it and prints it to a writer.
|
||||||
|
PrintObj(runtime.Object, io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourcePrinterFunc is a function that can print objects
|
||||||
|
type ResourcePrinterFunc func(runtime.Object, io.Writer) error
|
||||||
|
|
||||||
|
// PrintObj implements ResourcePrinter
|
||||||
|
func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||||
|
return fn(obj, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintOptions for different table printing options
|
||||||
|
type PrintOptions struct {
|
||||||
|
//TODO: Add options for eg: with-kind, server-printing, wide etc
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following is a subset of original implementation
|
||||||
|
// at https://github.com/kubernetes/kubernetes/blob/v1.15.0-alpha.2/pkg/printers/tablegenerator.go
|
||||||
|
|
||||||
|
package printers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TableGenerator interface {
|
||||||
|
GenerateTable(obj runtime.Object, options PrintOptions) (*metav1beta1.Table, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrintHandler interface {
|
||||||
|
TableHandler(columns []metav1beta1.TableColumnDefinition, printFunc interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type handlerEntry struct {
|
||||||
|
columnDefinitions []metav1beta1.TableColumnDefinition
|
||||||
|
printFunc reflect.Value
|
||||||
|
args []reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide
|
||||||
|
// more elegant output.
|
||||||
|
type HumanReadablePrinter struct {
|
||||||
|
handlerMap map[reflect.Type]*handlerEntry
|
||||||
|
options PrintOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TableGenerator = &HumanReadablePrinter{}
|
||||||
|
var _ PrintHandler = &HumanReadablePrinter{}
|
||||||
|
|
||||||
|
// NewTableGenerator creates a HumanReadablePrinter suitable for calling GenerateTable().
|
||||||
|
func NewTableGenerator() *HumanReadablePrinter {
|
||||||
|
return &HumanReadablePrinter{
|
||||||
|
handlerMap: make(map[reflect.Type]*handlerEntry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
t := reflect.TypeOf(obj)
|
||||||
|
handler, ok := h.handlerMap[t]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no table handler registered for this type %v", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
|
||||||
|
results := handler.printFunc.Call(args)
|
||||||
|
if !results[1].IsNil() {
|
||||||
|
return nil, results[1].Interface().(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var columns []metav1beta1.TableColumnDefinition
|
||||||
|
|
||||||
|
columns = make([]metav1beta1.TableColumnDefinition, 0, len(handler.columnDefinitions))
|
||||||
|
for i := range handler.columnDefinitions {
|
||||||
|
columns = append(columns, handler.columnDefinitions[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
table := &metav1beta1.Table{
|
||||||
|
ListMeta: metav1.ListMeta{
|
||||||
|
ResourceVersion: "",
|
||||||
|
},
|
||||||
|
ColumnDefinitions: columns,
|
||||||
|
Rows: results[0].Interface().([]metav1beta1.TableRow),
|
||||||
|
}
|
||||||
|
if m, err := meta.ListAccessor(obj); err == nil {
|
||||||
|
table.ResourceVersion = m.GetResourceVersion()
|
||||||
|
table.SelfLink = m.GetSelfLink()
|
||||||
|
table.Continue = m.GetContinue()
|
||||||
|
} else {
|
||||||
|
if m, err := meta.CommonAccessor(obj); err == nil {
|
||||||
|
table.ResourceVersion = m.GetResourceVersion()
|
||||||
|
table.SelfLink = m.GetSelfLink()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return table, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableHandler adds a print handler with a given set of columns to HumanReadablePrinter instance.
|
||||||
|
// See ValidateRowPrintHandlerFunc for required method signature.
|
||||||
|
func (h *HumanReadablePrinter) 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))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
entry := &handlerEntry{
|
||||||
|
columnDefinitions: columnDefinitions,
|
||||||
|
printFunc: printFuncValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
objType := printFuncValue.Type().In(0)
|
||||||
|
if _, ok := h.handlerMap[objType]; ok {
|
||||||
|
err := fmt.Errorf("registered duplicate printer for %v", objType)
|
||||||
|
utilruntime.HandleError(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.handlerMap[objType] = entry
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateRowPrintHandlerFunc validates print handler signature.
|
||||||
|
// printFunc is the function that will be called to print an object.
|
||||||
|
// It must be of the following type:
|
||||||
|
// func printFunc(object ObjectType, options PrintOptions) ([]metav1beta1.TableRow, error)
|
||||||
|
// where ObjectType is the type of the object that will be printed, and the first
|
||||||
|
// return value is an array of rows, with each row containing a number of cells that
|
||||||
|
// match the number of columns defined for that printer function.
|
||||||
|
func ValidateRowPrintHandlerFunc(printFunc reflect.Value) error {
|
||||||
|
if printFunc.Kind() != reflect.Func {
|
||||||
|
return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
|
||||||
|
}
|
||||||
|
funcType := printFunc.Type()
|
||||||
|
if funcType.NumIn() != 2 || funcType.NumOut() != 2 {
|
||||||
|
return fmt.Errorf("invalid print handler." +
|
||||||
|
"Must accept 2 parameters and return 2 value.")
|
||||||
|
}
|
||||||
|
if funcType.In(1) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
|
||||||
|
funcType.Out(0) != reflect.TypeOf((*[]metav1beta1.TableRow)(nil)).Elem() ||
|
||||||
|
funcType.Out(1) != reflect.TypeOf((*error)(nil)).Elem() {
|
||||||
|
return fmt.Errorf("invalid print handler. The expected signature is: "+
|
||||||
|
"func handler(obj %v, options PrintOptions) ([]metav1beta1.TableRow, error)", funcType.In(0))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following is a subset of original implementation
|
||||||
|
// at https://github.com/kubernetes/kubernetes/blob/v1.15.0-alpha.2/pkg/printers/tableprinter.go
|
||||||
|
|
||||||
|
package printers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ ResourcePrinter = &HumanReadablePrinter{}
|
||||||
|
|
||||||
|
// NewTablePrinter creates a printer suitable for calling PrintObj().
|
||||||
|
func NewTablePrinter(options PrintOptions) *HumanReadablePrinter {
|
||||||
|
printer := &HumanReadablePrinter{
|
||||||
|
handlerMap: make(map[reflect.Type]*handlerEntry),
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
return printer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
output = w
|
||||||
|
defer w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for a handler registered handler to print it
|
||||||
|
t := reflect.TypeOf(obj)
|
||||||
|
if handler := h.handlerMap[t]; handler != nil {
|
||||||
|
|
||||||
|
if err := printRowsForHandlerEntry(output, handler, obj, h.options); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// we failed all reasonable printing efforts, report failure
|
||||||
|
return fmt.Errorf("error: unknown type %#v", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printRowsForHandlerEntry prints the incremental table output
|
||||||
|
// including all the rows in the object. It returns the current type
|
||||||
|
// or an error, if any.
|
||||||
|
func printRowsForHandlerEntry(output io.Writer, handler *handlerEntry, obj runtime.Object, options PrintOptions) error {
|
||||||
|
var results []reflect.Value
|
||||||
|
|
||||||
|
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
|
||||||
|
results = handler.printFunc.Call(args)
|
||||||
|
if !results[1].IsNil() {
|
||||||
|
return results[1].Interface().(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers []string
|
||||||
|
for _, column := range handler.columnDefinitions {
|
||||||
|
headers = append(headers, strings.ToUpper(column.Name))
|
||||||
|
}
|
||||||
|
printHeader(headers, output)
|
||||||
|
|
||||||
|
if results[1].IsNil() {
|
||||||
|
rows := results[0].Interface().([]metav1beta1.TableRow)
|
||||||
|
printRows(output, rows, options)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return results[1].Interface().(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHeader(columnNames []string, w io.Writer) error {
|
||||||
|
if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// printRows writes the provided rows to output.
|
||||||
|
func printRows(output io.Writer, rows []metav1beta1.TableRow, options PrintOptions) {
|
||||||
|
for _, row := range rows {
|
||||||
|
for i, cell := range row.Cells {
|
||||||
|
if i != 0 {
|
||||||
|
fmt.Fprint(output, "\t")
|
||||||
|
}
|
||||||
|
fmt.Fprint(output, cell)
|
||||||
|
}
|
||||||
|
output.Write([]byte("\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following is a subset of original implementation
|
||||||
|
// at https://github.com/kubernetes/kubernetes/blob/v1.15.0-alpha.2/pkg/printers/tabwriter.go
|
||||||
|
|
||||||
|
package printers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tabwriterMinWidth = 6
|
||||||
|
tabwriterWidth = 4
|
||||||
|
tabwriterPadding = 3
|
||||||
|
tabwriterPadChar = ' '
|
||||||
|
tabwriterFlags = tabwriter.TabIndent
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
|
||||||
|
func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
|
||||||
|
return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
|
||||||
|
}
|
||||||
|
|
@ -196,10 +196,13 @@ k8s.io/api/storage/v1beta1
|
||||||
k8s.io/apimachinery/pkg/api/resource
|
k8s.io/apimachinery/pkg/api/resource
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1
|
k8s.io/apimachinery/pkg/apis/meta/v1
|
||||||
k8s.io/apimachinery/pkg/runtime/schema
|
k8s.io/apimachinery/pkg/runtime/schema
|
||||||
|
k8s.io/apimachinery/pkg/api/meta
|
||||||
|
k8s.io/apimachinery/pkg/apis/meta/v1beta1
|
||||||
|
k8s.io/apimachinery/pkg/runtime
|
||||||
|
k8s.io/apimachinery/pkg/util/runtime
|
||||||
k8s.io/apimachinery/pkg/api/equality
|
k8s.io/apimachinery/pkg/api/equality
|
||||||
k8s.io/apimachinery/pkg/api/validation
|
k8s.io/apimachinery/pkg/api/validation
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
|
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
|
||||||
k8s.io/apimachinery/pkg/runtime
|
|
||||||
k8s.io/apimachinery/pkg/util/intstr
|
k8s.io/apimachinery/pkg/util/intstr
|
||||||
k8s.io/apimachinery/pkg/util/sets
|
k8s.io/apimachinery/pkg/util/sets
|
||||||
k8s.io/apimachinery/pkg/util/validation
|
k8s.io/apimachinery/pkg/util/validation
|
||||||
|
|
@ -210,16 +213,14 @@ k8s.io/apimachinery/pkg/conversion
|
||||||
k8s.io/apimachinery/pkg/fields
|
k8s.io/apimachinery/pkg/fields
|
||||||
k8s.io/apimachinery/pkg/labels
|
k8s.io/apimachinery/pkg/labels
|
||||||
k8s.io/apimachinery/pkg/selection
|
k8s.io/apimachinery/pkg/selection
|
||||||
k8s.io/apimachinery/pkg/util/runtime
|
|
||||||
k8s.io/apimachinery/pkg/api/meta
|
|
||||||
k8s.io/apimachinery/pkg/util/json
|
k8s.io/apimachinery/pkg/util/json
|
||||||
k8s.io/apimachinery/pkg/util/net
|
k8s.io/apimachinery/pkg/util/net
|
||||||
k8s.io/apimachinery/pkg/util/yaml
|
k8s.io/apimachinery/pkg/util/yaml
|
||||||
k8s.io/apimachinery/pkg/util/errors
|
k8s.io/apimachinery/pkg/util/errors
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1/validation
|
|
||||||
k8s.io/apimachinery/pkg/util/validation/field
|
|
||||||
k8s.io/apimachinery/pkg/conversion/queryparams
|
k8s.io/apimachinery/pkg/conversion/queryparams
|
||||||
k8s.io/apimachinery/pkg/util/naming
|
k8s.io/apimachinery/pkg/util/naming
|
||||||
|
k8s.io/apimachinery/pkg/apis/meta/v1/validation
|
||||||
|
k8s.io/apimachinery/pkg/util/validation/field
|
||||||
k8s.io/apimachinery/pkg/runtime/serializer/json
|
k8s.io/apimachinery/pkg/runtime/serializer/json
|
||||||
k8s.io/apimachinery/pkg/runtime/serializer/protobuf
|
k8s.io/apimachinery/pkg/runtime/serializer/protobuf
|
||||||
k8s.io/apimachinery/pkg/runtime/serializer/recognizer
|
k8s.io/apimachinery/pkg/runtime/serializer/recognizer
|
||||||
|
|
@ -227,7 +228,6 @@ k8s.io/apimachinery/pkg/runtime/serializer/versioning
|
||||||
k8s.io/apimachinery/pkg/api/errors
|
k8s.io/apimachinery/pkg/api/errors
|
||||||
k8s.io/apimachinery/pkg/runtime/serializer/streaming
|
k8s.io/apimachinery/pkg/runtime/serializer/streaming
|
||||||
k8s.io/apimachinery/third_party/forked/golang/reflect
|
k8s.io/apimachinery/third_party/forked/golang/reflect
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1beta1
|
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme
|
k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme
|
||||||
k8s.io/apimachinery/pkg/version
|
k8s.io/apimachinery/pkg/version
|
||||||
k8s.io/apimachinery/pkg/util/strategicpatch
|
k8s.io/apimachinery/pkg/util/strategicpatch
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue