Skip to content

Commit

Permalink
Merge pull request #3 from corneliusweig/json-yaml-separator
Browse files Browse the repository at this point in the history
Fix generated output for -o json/yaml
  • Loading branch information
Cornelius Weig authored Feb 18, 2019
2 parents 9d02e06 + 479337d commit 6f2c191
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 16 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635 // indirect
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.0.0-20181121191454-a61488babbd6 // indirect
k8s.io/api v0.0.0-20181121191454-a61488babbd6
k8s.io/apimachinery v0.0.0-20190211022232-e355a776c090
k8s.io/cli-runtime v0.0.0-20190202014047-491c94071cfa
k8s.io/client-go v10.0.0+incompatible // indirect
Expand Down
21 changes: 15 additions & 6 deletions pkg/ket_all.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/corneliusweig/ketall/pkg/printer"
"github.com/sirupsen/logrus"
"io"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"text/tabwriter"
)

Expand All @@ -37,20 +38,28 @@ func KetAll(w io.Writer, ketallOptions *options.KetallOptions) {
}

out := w
if p, ok := resourcePrinter.(*printer.TablePrinter); ok {
p := resourcePrinter
switch pr := resourcePrinter.(type) {
// yaml and json printers should operate on the full tree structure with nested lists
case *printers.JSONPrinter:
p = printer.NewListAdapterPrinter(pr)
case *printers.YAMLPrinter:
p = printer.NewListAdapterPrinter(pr)
// other printers should flatten the resource list and operate on leaf items
case *printer.TablePrinter:
logrus.Debug("Using tabwriter")
tw := tabwriter.NewWriter(w, 4, 4, 2, ' ', 0)
defer tw.Flush()
out = tw
if err := p.PrintHeader(out); err != nil {
if err := pr.PrintHeader(out); err != nil {
logrus.Fatal("print header", err)
}
} else {
logrus.Debug("Using default writer")
p = printer.NewFlattenListAdapterPrinter(pr)
default:
p = printer.NewFlattenListAdapterPrinter(pr)
}

printer := printer.NewListAdapterPrinter(resourcePrinter)
if err = printer.PrintObj(all, out); err != nil {
if err = p.PrintObj(all, out); err != nil {
logrus.Fatal(err)
}
}
46 changes: 46 additions & 0 deletions pkg/options/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Copyright 2019 Cornelius Weig
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.
*/

package options

import (
"github.com/corneliusweig/ketall/pkg/printer"
"github.com/stretchr/testify/assert"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"testing"
)

func TestKAPrintFlags_ToPrinter(t *testing.T) {
flags := KAPrintFlags{genericclioptions.NewPrintFlags("")}

flags.OutputFormat = nil
p, err := flags.ToPrinter()
assert.NoError(t, err)
assert.IsType(t, &printer.TablePrinter{}, p)

format := ""
flags.OutputFormat = &format
p, err = flags.ToPrinter()
assert.NoError(t, err)
assert.IsType(t, &printer.TablePrinter{}, p)

format = "json"
flags.OutputFormat = &format
p, err = flags.ToPrinter()
assert.NoError(t, err)
assert.IsType(t, &printers.JSONPrinter{}, p)
}
38 changes: 29 additions & 9 deletions pkg/printer/list_adapter.go → pkg/printer/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,53 @@ package printer

import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"io"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
)

type ListAdapterPrinter struct {
delegate printers.ResourcePrinter
type FlattenListAdapter struct {
printers.ResourcePrinter
}

func NewListAdapterPrinter(printer printers.ResourcePrinter) ListAdapterPrinter {
return ListAdapterPrinter{printer}
func NewFlattenListAdapterPrinter(printer printers.ResourcePrinter) printers.ResourcePrinter {
logrus.Debugf("Wrapping %T with FlattenListAdapterPrinter", printer)
return &FlattenListAdapter{printer}
}

func (n *ListAdapterPrinter) PrintObj(r runtime.Object, w io.Writer) error {
func (n *FlattenListAdapter) PrintObj(r runtime.Object, w io.Writer) error {
if meta.IsListType(r) {
subs, err := meta.ExtractList(r)
items, err := meta.ExtractList(r)
if err != nil {
return errors.Wrap(err, "extract resource list")
}
for _, o := range subs {
for _, o := range items {
if err := n.PrintObj(o, w); err != nil {
return err
return errors.Wrap(err, "print list item")
}
}
return nil
}

return n.delegate.PrintObj(r, w)
return n.ResourcePrinter.PrintObj(r, w)
}

type ListAdapterPrinter struct {
printers.ResourcePrinter
}

func NewListAdapterPrinter(printer printers.ResourcePrinter) printers.ResourcePrinter {
logrus.Debugf("Wrapping %T with ListAdapterPrinter", printer)
return &ListAdapterPrinter{printer}
}

func (n *ListAdapterPrinter) PrintObj(r runtime.Object, w io.Writer) error {
if meta.IsListType(r) {
r.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"})
}

return n.ResourcePrinter.PrintObj(r, w)
}
115 changes: 115 additions & 0 deletions pkg/printer/adapter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright 2019 Cornelius Weig
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.
*/

package printer

import (
"bytes"
"fmt"
"github.com/stretchr/testify/assert"
"io"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"testing"
)

type mockObject struct {
gvk schema.GroupVersionKind
content string
}

func (o *mockObject) GetObjectKind() schema.ObjectKind {
return o
}

func (o *mockObject) String() string {
return fmt.Sprintf("versionKind: %s/%s content: %s\n", o.gvk.Version, o.gvk.Kind, o.content)
}

func (o *mockObject) DeepCopyObject() runtime.Object {
clone := mockObject{
gvk: schema.GroupVersionKind{o.gvk.Group, o.gvk.Version, o.gvk.Kind},
content: o.content,
}
return &clone
}

func (c *mockObject) GroupVersionKind() schema.GroupVersionKind {
return c.gvk
}

func (c *mockObject) SetGroupVersionKind(gvk schema.GroupVersionKind) {
c.gvk = gvk
}

type mockList struct {
mockObject
Items []mockObject
}

type mockPrinter struct{}

func (*mockPrinter) PrintObj(r runtime.Object, w io.Writer) error {
var message string
switch r := r.(type) {
case *mockList:
message = r.String()
case *mockObject:
message = r.String()
}

_, err := io.WriteString(w, message)
return err
}

func TestListAdapterPrinter_PrintObj(t *testing.T) {
delegate := mockPrinter{}
buffer := &bytes.Buffer{}
printer := NewListAdapterPrinter(&delegate)

o := &mockObject{content: "mock object"}
err := printer.PrintObj(o, buffer)
assert.NoError(t, err)
assert.Equal(t, buffer.String(), "versionKind: / content: mock object\n")

buffer.Truncate(0)
l := &mockList{mockObject: mockObject{content: "mock list"}}
err = printer.PrintObj(l, buffer)
assert.NoError(t, err)
assert.Equal(t, buffer.String(), "versionKind: v1/List content: mock list\n")
}

func TestFlattenListAdapter_PrintObj(t *testing.T) {
delegate := mockPrinter{}
buffer := &bytes.Buffer{}
printer := NewFlattenListAdapterPrinter(&delegate)

gvk := schema.GroupVersionKind{"", "v1", "Test"}
list := &mockList{
Items: []mockObject{
{gvk, "object 1"},
{gvk, "object 2"},
{gvk, "object 3"},
},
}

err := printer.PrintObj(list, buffer)
assert.NoError(t, err)
assert.Equal(t, buffer.String(), `versionKind: v1/Test content: object 1
versionKind: v1/Test content: object 2
versionKind: v1/Test content: object 3
`)
}

0 comments on commit 6f2c191

Please sign in to comment.