mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #56629 from luksa/fix_custom_column_alignment
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Fix bad column alignment when using custom columns from OpenAPI schema Columns printed by `kubectl get` weren't aligned properly when they were coming from the OpenAPI schema. This was caused by `CustomColumnPrinter.PrintObj`, which was creating a new `tabwriter.Writer` instead of re-using the tabwriter received through the `out` method parameter (basically, a tabwriter was writing to another tabwriter). Because the PrintObj flushed the tabwriter after writing each individual line, the column widths would reset. **What this PR does / why we need it**: This PR fixes the bad column alignment. **Which issue(s) this PR fixes** Fixes #56282 **Special notes for your reviewer**: I've aligned how `CustomColumnPrinter.PrintObj` handles tabwriter with how `HumanReadablePrinter.PrintObj` does it (see https://github.com/kubernetes/kubernetes/blob/master/pkg/printers/humanreadable.go#L299-L303) **Release note**: ```release-note Fixed column alignment when kubectl get is used with custom columns from OpenAPI schema ```
This commit is contained in:
commit
9f4b851e91
@ -31,14 +31,6 @@ import (
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
)
|
||||
|
||||
const (
|
||||
columnwidth = 10
|
||||
tabwidth = 4
|
||||
padding = 3
|
||||
padding_character = ' '
|
||||
flags = 0
|
||||
)
|
||||
|
||||
var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$")
|
||||
|
||||
// RelaxedJSONPathExpression attempts to be flexible with JSONPath expressions, it accepts:
|
||||
@ -163,7 +155,11 @@ func (s *CustomColumnsPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
|
||||
if w, found := out.(*tabwriter.Writer); !found {
|
||||
w = GetNewTabWriter(out)
|
||||
out = w
|
||||
defer w.Flush()
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(obj)
|
||||
if !s.NoHeaders && t != s.lastType {
|
||||
@ -171,7 +167,7 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
|
||||
for ix := range s.Columns {
|
||||
headers[ix] = s.Columns[ix].Header
|
||||
}
|
||||
fmt.Fprintln(w, strings.Join(headers, "\t"))
|
||||
fmt.Fprintln(out, strings.Join(headers, "\t"))
|
||||
s.lastType = t
|
||||
}
|
||||
parsers := make([]*jsonpath.JSONPath, len(s.Columns))
|
||||
@ -188,16 +184,16 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
|
||||
return err
|
||||
}
|
||||
for ix := range objs {
|
||||
if err := s.printOneObject(objs[ix], parsers, w); err != nil {
|
||||
if err := s.printOneObject(objs[ix], parsers, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := s.printOneObject(obj, parsers, w); err != nil {
|
||||
if err := s.printOneObject(obj, parsers, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jsonpath.JSONPath, out io.Writer) error {
|
||||
|
@ -323,3 +323,45 @@ foo baz <none>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this mimics how resource/get.go calls the customcolumn printer
|
||||
func TestIndividualPrintObjOnExistingTabWriter(t *testing.T) {
|
||||
columns := []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
},
|
||||
{
|
||||
Header: "LONG COLUMN NAME", // name is longer than all values of label1
|
||||
FieldSpec: "{.metadata.labels.label1}",
|
||||
},
|
||||
{
|
||||
Header: "LABEL 2",
|
||||
FieldSpec: "{.metadata.labels.label2}",
|
||||
},
|
||||
}
|
||||
objects := []*v1.Pod{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{"label1": "foo", "label2": "foo"}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{"label1": "bar", "label2": "bar"}}},
|
||||
}
|
||||
expectedOutput := `NAME LONG COLUMN NAME LABEL 2
|
||||
foo foo foo
|
||||
bar bar bar
|
||||
`
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
tabWriter := printers.GetNewTabWriter(buffer)
|
||||
printer := &printers.CustomColumnsPrinter{
|
||||
Columns: columns,
|
||||
Decoder: legacyscheme.Codecs.UniversalDecoder(),
|
||||
}
|
||||
for _, obj := range objects {
|
||||
if err := printer.PrintObj(obj, tabWriter); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
tabWriter.Flush()
|
||||
if buffer.String() != expectedOutput {
|
||||
t.Errorf("\nexpected:\n'%s'\nsaw\n'%s'\n", expectedOutput, buffer.String())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user