mirror of https://github.com/k3s-io/k3s
Denote if a printer is generic.
This fixes #38779. This allows us to avoid case in which printers.GetStandardPrinter returns nil for both printer and err removing any potential panics that may arise throughout kubectl commands. Please see #38779 and #38112 for complete context. Add comment explaining adding handlers to printers.HumanReadablePrinter also remove an unnecessary conversion of printers.HumanReadablePrinter to printers.ResourcePrinter.pull/6/head
parent
77a8c25839
commit
8442a118ea
|
@ -456,8 +456,7 @@ func TestApplyObjectOutput(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.CommandPrinter = &printers.YAMLPrinter{}
|
tf.Printer = &printers.YAMLPrinter{}
|
||||||
tf.GenericPrinter = true
|
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
|
|
@ -80,8 +80,9 @@ func defaultClientConfigForVersion(version *schema.GroupVersion) *restclient.Con
|
||||||
}
|
}
|
||||||
|
|
||||||
type testPrinter struct {
|
type testPrinter struct {
|
||||||
Objects []runtime.Object
|
Objects []runtime.Object
|
||||||
Err error
|
Err error
|
||||||
|
GenericPrinter bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||||
|
@ -99,6 +100,10 @@ func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *testPrinter) IsGeneric() bool {
|
||||||
|
return t.GenericPrinter
|
||||||
|
}
|
||||||
|
|
||||||
type testDescriber struct {
|
type testDescriber struct {
|
||||||
Name, Namespace string
|
Name, Namespace string
|
||||||
Settings printers.DescriberSettings
|
Settings printers.DescriberSettings
|
||||||
|
|
|
@ -81,7 +81,7 @@ func NewCmdConfigView(out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess
|
||||||
cmd.Flags().Set("output", defaultOutputFormat)
|
cmd.Flags().Set("output", defaultOutputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
printer, _, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, []runtime.Decoder{latest.Codec})
|
printer, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, printers.PrintOptions{})
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
|
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||||
cmd.Flags().Set("output", outputFormat)
|
cmd.Flags().Set("output", outputFormat)
|
||||||
}
|
}
|
||||||
o.encoder = f.JSONEncoder()
|
o.encoder = f.JSONEncoder()
|
||||||
o.printer, _, err = f.PrinterForCommand(cmd)
|
o.printer, err = f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,10 @@ func (t *testClusterRolePrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *testClusterRolePrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateClusterRole(t *testing.T) {
|
func TestCreateClusterRole(t *testing.T) {
|
||||||
clusterRoleName := "my-cluster-role"
|
clusterRoleName := "my-cluster-role"
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,10 @@ func (t *testRolePrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *testRolePrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateRole(t *testing.T) {
|
func TestCreateRole(t *testing.T) {
|
||||||
roleName := "my-role"
|
roleName := "my-role"
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
printer, generic, err := f.PrinterForCommand(cmd)
|
printer, err := f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||||
r.IgnoreErrors(kapierrors.IsNotFound)
|
r.IgnoreErrors(kapierrors.IsNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
if generic {
|
if printer.IsGeneric() {
|
||||||
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
|
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
|
||||||
// 1. if there is more than one item, combine them all into a single list
|
// 1. if there is more than one item, combine them all into a single list
|
||||||
// 2. if there is a single item and that item is a list, leave it as its specific list
|
// 2. if there is a single item and that item is a list, leave it as its specific list
|
||||||
|
@ -436,7 +436,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||||
mapping = infos[ix].Mapping
|
mapping = infos[ix].Mapping
|
||||||
original = infos[ix].Object
|
original = infos[ix].Object
|
||||||
}
|
}
|
||||||
if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource {
|
if shouldGetNewPrinterForMapping(printer, lastMapping, mapping) {
|
||||||
if printer != nil {
|
if printer != nil {
|
||||||
w.Flush()
|
w.Flush()
|
||||||
}
|
}
|
||||||
|
@ -513,3 +513,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||||
cmdutil.PrintFilterCount(errOut, len(objs), filteredResourceCount, len(allErrs), filterOpts, options.IgnoreNotFound)
|
cmdutil.PrintFilterCount(errOut, len(objs), filteredResourceCount, len(allErrs), filterOpts, options.IgnoreNotFound)
|
||||||
return utilerrors.NewAggregate(allErrs)
|
return utilerrors.NewAggregate(allErrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldGetNewPrinterForMapping(printer printers.ResourcePrinter, lastMapping, mapping *meta.RESTMapping) bool {
|
||||||
|
return printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource
|
||||||
|
}
|
||||||
|
|
|
@ -220,15 +220,16 @@ func TestGetObjectsFiltered(t *testing.T) {
|
||||||
second := &pods.Items[1]
|
second := &pods.Items[1]
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
resp runtime.Object
|
resp runtime.Object
|
||||||
flags map[string]string
|
flags map[string]string
|
||||||
expect []runtime.Object
|
expect []runtime.Object
|
||||||
|
genericPrinter bool
|
||||||
}{
|
}{
|
||||||
{args: []string{"pods", "foo"}, resp: first, expect: []runtime.Object{first}},
|
{args: []string{"pods", "foo"}, resp: first, expect: []runtime.Object{first}, genericPrinter: true},
|
||||||
{args: []string{"pods", "foo"}, flags: map[string]string{"show-all": "false"}, resp: first, expect: []runtime.Object{first}},
|
{args: []string{"pods", "foo"}, flags: map[string]string{"show-all": "false"}, resp: first, expect: []runtime.Object{first}, genericPrinter: true},
|
||||||
{args: []string{"pods"}, flags: map[string]string{"show-all": "true"}, resp: pods, expect: []runtime.Object{first, second}},
|
{args: []string{"pods"}, flags: map[string]string{"show-all": "true"}, resp: pods, expect: []runtime.Object{first, second}},
|
||||||
{args: []string{"pods/foo"}, resp: first, expect: []runtime.Object{first}},
|
{args: []string{"pods/foo"}, resp: first, expect: []runtime.Object{first}, genericPrinter: true},
|
||||||
{args: []string{"pods"}, flags: map[string]string{"output": "yaml"}, resp: pods, expect: []runtime.Object{second}},
|
{args: []string{"pods"}, flags: map[string]string{"output": "yaml"}, resp: pods, expect: []runtime.Object{second}},
|
||||||
{args: []string{}, flags: map[string]string{"filename": "../../../examples/storage/cassandra/cassandra-controller.yaml"}, resp: pods, expect: []runtime.Object{first, second}},
|
{args: []string{}, flags: map[string]string{"filename": "../../../examples/storage/cassandra/cassandra-controller.yaml"}, resp: pods, expect: []runtime.Object{first, second}},
|
||||||
|
|
||||||
|
@ -240,7 +241,7 @@ func TestGetObjectsFiltered(t *testing.T) {
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
t.Logf("%d", i)
|
t.Logf("%d", i)
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{GenericPrinter: test.genericPrinter}
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
@ -281,7 +282,7 @@ func TestGetObjectIgnoreNotFound(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{GenericPrinter: true}
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
@ -393,7 +394,7 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
|
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{GenericPrinter: true}
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
@ -561,8 +562,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||||
pods, svc, _ := testData()
|
pods, svc, _ := testData()
|
||||||
|
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.CommandPrinter = &testPrinter{}
|
tf.Printer = &testPrinter{GenericPrinter: true}
|
||||||
tf.GenericPrinter = true
|
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
@ -589,7 +589,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||||
cmd.Flags().Set("output", "json")
|
cmd.Flags().Set("output", "json")
|
||||||
cmd.Run(cmd, []string{"pods,services"})
|
cmd.Run(cmd, []string{"pods,services"})
|
||||||
|
|
||||||
actual := tf.CommandPrinter.(*testPrinter).Objects
|
actual := tf.Printer.(*testPrinter).Objects
|
||||||
fn := func(obj runtime.Object) unstructured.Unstructured {
|
fn := func(obj runtime.Object) unstructured.Unstructured {
|
||||||
data, err := runtime.Encode(api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"}), obj)
|
data, err := runtime.Encode(api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"}), obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -716,7 +716,7 @@ func TestGetByFormatForcesFlag(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
|
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.Printer = &testPrinter{}
|
tf.Printer = &testPrinter{GenericPrinter: true}
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
|
|
@ -161,8 +161,7 @@ func TestPatchObjectFromFileOutput(t *testing.T) {
|
||||||
svcCopy.Labels["post-patch"] = "post-patch-value"
|
svcCopy.Labels["post-patch"] = "post-patch-value"
|
||||||
|
|
||||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
tf.CommandPrinter = &printers.YAMLPrinter{}
|
tf.Printer = &printers.YAMLPrinter{}
|
||||||
tf.GenericPrinter = true
|
|
||||||
tf.UnstructuredClient = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: unstructuredSerializer,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
|
|
@ -221,13 +221,11 @@ type TestFactory struct {
|
||||||
UnstructuredClient kubectl.RESTClient
|
UnstructuredClient kubectl.RESTClient
|
||||||
Describer printers.Describer
|
Describer printers.Describer
|
||||||
Printer printers.ResourcePrinter
|
Printer printers.ResourcePrinter
|
||||||
CommandPrinter printers.ResourcePrinter
|
|
||||||
Validator validation.Schema
|
Validator validation.Schema
|
||||||
Namespace string
|
Namespace string
|
||||||
ClientConfig *restclient.Config
|
ClientConfig *restclient.Config
|
||||||
Err error
|
Err error
|
||||||
Command string
|
Command string
|
||||||
GenericPrinter bool
|
|
||||||
TmpDir string
|
TmpDir string
|
||||||
|
|
||||||
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||||
|
@ -338,8 +336,8 @@ func (f *FakeFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
||||||
return f.tf.Describer, f.tf.Err
|
return f.tf.Describer, f.tf.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||||
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
|
return f.tf.Printer, f.tf.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||||
|
@ -619,8 +617,8 @@ func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (reso
|
||||||
return f.tf.UnstructuredClient, f.tf.Err
|
return f.tf.UnstructuredClient, f.tf.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||||
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
|
return f.tf.Printer, f.tf.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
||||||
|
|
|
@ -230,10 +230,10 @@ type ObjectMappingFactory interface {
|
||||||
// Generally they depend upon client mapper functions
|
// Generally they depend upon client mapper functions
|
||||||
type BuilderFactory interface {
|
type BuilderFactory interface {
|
||||||
// PrinterForCommand returns the default printer for the command. It requires that certain options
|
// PrinterForCommand returns the default printer for the command. It requires that certain options
|
||||||
// are declared on the command (see AddPrinterFlags). Returns a printer, true if the printer is
|
// are declared on the command (see AddPrinterFlags). Returns a printer, or an error if a printer
|
||||||
// generic (is not internal), or an error if a printer could not be found.
|
// could not be found.
|
||||||
// TODO: Break the dependency on cmd here.
|
// TODO: Break the dependency on cmd here.
|
||||||
PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error)
|
PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error)
|
||||||
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
|
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
|
||||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||||
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
|
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ring2Factory struct {
|
type ring2Factory struct {
|
||||||
|
@ -47,24 +48,41 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||||
mapper, typer, err := f.objectMappingFactory.UnstructuredObject()
|
mapper, typer, err := f.objectMappingFactory.UnstructuredObject()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
||||||
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
||||||
return PrinterForCommand(cmd, mapper, typer, decoders)
|
encoder := f.clientAccessFactory.JSONEncoder()
|
||||||
|
return PrinterForCommand(cmd, mapper, typer, encoder, decoders, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||||
printer, generic, err := f.PrinterForCommand(cmd)
|
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||||
|
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||||
|
if err != nil {
|
||||||
|
columnLabel = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
options := printers.PrintOptions{
|
||||||
|
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
||||||
|
WithNamespace: withNamespace,
|
||||||
|
Wide: GetWideFlag(cmd),
|
||||||
|
ShowAll: GetFlagBool(cmd, "show-all"),
|
||||||
|
ShowLabels: GetFlagBool(cmd, "show-labels"),
|
||||||
|
AbsoluteTimestamps: isWatch(cmd),
|
||||||
|
ColumnLabels: columnLabel,
|
||||||
|
}
|
||||||
|
|
||||||
|
printer, err := f.PrinterForCommand(cmd, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we output versioned data for generic printers
|
// Make sure we output versioned data for generic printers
|
||||||
if generic {
|
if printer.IsGeneric() {
|
||||||
if mapping == nil {
|
if mapping == nil {
|
||||||
return nil, fmt.Errorf("no serialization format found")
|
return nil, fmt.Errorf("no serialization format found")
|
||||||
}
|
}
|
||||||
|
@ -74,25 +92,17 @@ func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTM
|
||||||
}
|
}
|
||||||
|
|
||||||
printer = printers.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
printer = printers.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
// We add handlers to the printer in case it is printers.HumanReadablePrinter.
|
||||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
// printers.AddHandlers expects concrete type of printers.HumanReadablePrinter
|
||||||
if err != nil {
|
// as its parameter because of this we have to do a type check on printer and
|
||||||
columnLabel = []string{}
|
// extract out concrete HumanReadablePrinter from it. We are then able to attach
|
||||||
|
// handlers on it.
|
||||||
|
if humanReadablePrinter, ok := printer.(*printers.HumanReadablePrinter); ok {
|
||||||
|
printersinternal.AddHandlers(humanReadablePrinter)
|
||||||
|
printer = humanReadablePrinter
|
||||||
}
|
}
|
||||||
printer, err = f.clientAccessFactory.Printer(mapping, printers.PrintOptions{
|
|
||||||
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
|
||||||
WithNamespace: withNamespace,
|
|
||||||
Wide: GetWideFlag(cmd),
|
|
||||||
ShowAll: GetFlagBool(cmd, "show-all"),
|
|
||||||
ShowLabels: GetFlagBool(cmd, "show-labels"),
|
|
||||||
AbsoluteTimestamps: isWatch(cmd),
|
|
||||||
ColumnLabels: columnLabel,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
printer = maybeWrapSortingPrinter(cmd, printer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return printer, nil
|
return printer, nil
|
||||||
|
|
|
@ -107,7 +107,7 @@ func ValidateOutputArgs(cmd *cobra.Command) error {
|
||||||
|
|
||||||
// PrinterForCommand returns the default printer for this command.
|
// PrinterForCommand returns the default printer for this command.
|
||||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||||
func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (printers.ResourcePrinter, bool, error) {
|
func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||||
outputFormat := GetFlagString(cmd, "output")
|
outputFormat := GetFlagString(cmd, "output")
|
||||||
|
|
||||||
// templates are logically optional for specifying a format.
|
// templates are logically optional for specifying a format.
|
||||||
|
@ -133,15 +133,15 @@ func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime
|
||||||
if cmd.Flags().Lookup("allow-missing-template-keys") != nil {
|
if cmd.Flags().Lookup("allow-missing-template-keys") != nil {
|
||||||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
|
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
|
||||||
}
|
}
|
||||||
printer, generic, err := printers.GetStandardPrinter(
|
printer, err := printers.GetStandardPrinter(
|
||||||
outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys,
|
outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys,
|
||||||
mapper, typer, decoders,
|
mapper, typer, encoder, decoders, options,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, generic, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return maybeWrapSortingPrinter(cmd, printer), generic, nil
|
return maybeWrapSortingPrinter(cmd, printer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintResourceInfoForCommand receives a *cobra.Command and a *resource.Info and
|
// PrintResourceInfoForCommand receives a *cobra.Command and a *resource.Info and
|
||||||
|
@ -149,11 +149,11 @@ func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime
|
||||||
// object passed is non-generic, it attempts to print the object using a HumanReadablePrinter.
|
// object passed is non-generic, it attempts to print the object using a HumanReadablePrinter.
|
||||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||||
func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error {
|
func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error {
|
||||||
printer, generic, err := f.PrinterForCommand(cmd)
|
printer, err := f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !generic || printer == nil {
|
if !printer.IsGeneric() {
|
||||||
printer, err = f.PrinterForMapping(cmd, nil, false)
|
printer, err = f.PrinterForMapping(cmd, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -60,10 +60,14 @@ func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement HandledResources()
|
// TODO: implement HandledResources()
|
||||||
func (p *SortingPrinter) HandledResources() []string {
|
func (s *SortingPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SortingPrinter) IsGeneric() bool {
|
||||||
|
return s.Delegate.IsGeneric()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SortingPrinter) sortObj(obj runtime.Object) error {
|
func (s *SortingPrinter) sortObj(obj runtime.Object) error {
|
||||||
objs, err := meta.ExtractList(obj)
|
objs, err := meta.ExtractList(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -239,3 +239,7 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
|
||||||
func (s *CustomColumnsPrinter) HandledResources() []string {
|
func (s *CustomColumnsPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CustomColumnsPrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -152,6 +152,10 @@ func (h *HumanReadablePrinter) AfterPrint(output io.Writer, res string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HumanReadablePrinter) IsGeneric() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||||
_, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
|
_, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -31,6 +31,8 @@ type ResourcePrinter interface {
|
||||||
//Can be used to print out warning/clarifications if needed
|
//Can be used to print out warning/clarifications if needed
|
||||||
//after all objects were printed
|
//after all objects were printed
|
||||||
AfterPrint(io.Writer, string) error
|
AfterPrint(io.Writer, string) error
|
||||||
|
// Identify if it is a generic printer
|
||||||
|
IsGeneric() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourcePrinterFunc is a function that can print objects
|
// ResourcePrinterFunc is a function that can print objects
|
||||||
|
@ -50,6 +52,10 @@ func (fn ResourcePrinterFunc) AfterPrint(io.Writer, string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fn ResourcePrinterFunc) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type PrintOptions struct {
|
type PrintOptions struct {
|
||||||
NoHeaders bool
|
NoHeaders bool
|
||||||
WithNamespace bool
|
WithNamespace bool
|
||||||
|
|
|
@ -81,12 +81,22 @@ func TestVersionedPrinter(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrintDefault(t *testing.T) {
|
func TestPrintDefault(t *testing.T) {
|
||||||
printer, found, err := printers.GetStandardPrinter("", "", false, false, nil, nil, nil)
|
printerTests := []struct {
|
||||||
if err != nil {
|
Name string
|
||||||
t.Fatalf("unexpected error: %#v", err)
|
Format string
|
||||||
|
}{
|
||||||
|
{"test wide", "wide"},
|
||||||
|
{"test blank format", ""},
|
||||||
}
|
}
|
||||||
if found {
|
|
||||||
t.Errorf("no printer should have been found: %#v / %v", printer, err)
|
for _, test := range printerTests {
|
||||||
|
printer, err := printers.GetStandardPrinter(test.Format, "", false, false, nil, nil, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||||
|
}
|
||||||
|
if printer.IsGeneric() {
|
||||||
|
t.Errorf("in %s, printer should not be generic: %#v", test.Name, printer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +146,11 @@ func TestPrinter(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range printerTests {
|
for _, test := range printerTests {
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
printer, generic, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, true, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
printer, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, true, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||||
}
|
}
|
||||||
if generic && len(test.OutputVersions) > 0 {
|
if printer.IsGeneric() && len(test.OutputVersions) > 0 {
|
||||||
printer = printers.NewVersionedPrinter(printer, api.Scheme, test.OutputVersions...)
|
printer = printers.NewVersionedPrinter(printer, api.Scheme, test.OutputVersions...)
|
||||||
}
|
}
|
||||||
if err := printer.PrintObj(test.Input, buf); err != nil {
|
if err := printer.PrintObj(test.Input, buf); err != nil {
|
||||||
|
@ -164,9 +174,10 @@ func TestBadPrinter(t *testing.T) {
|
||||||
{"bad template", "template", "{{ .Name", fmt.Errorf("error parsing template {{ .Name, template: output:1: unclosed action\n")},
|
{"bad template", "template", "{{ .Name", fmt.Errorf("error parsing template {{ .Name, template: output:1: unclosed action\n")},
|
||||||
{"bad templatefile", "templatefile", "", fmt.Errorf("templatefile format specified but no template file given")},
|
{"bad templatefile", "templatefile", "", fmt.Errorf("templatefile format specified but no template file given")},
|
||||||
{"bad jsonpath", "jsonpath", "{.Name", fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")},
|
{"bad jsonpath", "jsonpath", "{.Name", fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")},
|
||||||
|
{"unknown format", "anUnknownFormat", "", fmt.Errorf("output format \"anUnknownFormat\" not recognized")},
|
||||||
}
|
}
|
||||||
for _, test := range badPrinterTests {
|
for _, test := range badPrinterTests {
|
||||||
_, _, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
_, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||||
if err == nil || err.Error() != test.Error.Error() {
|
if err == nil || err.Error() != test.Error.Error() {
|
||||||
t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err)
|
t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err)
|
||||||
}
|
}
|
||||||
|
@ -359,7 +370,7 @@ func TestNamePrinter(t *testing.T) {
|
||||||
},
|
},
|
||||||
"pods/foo\npods/bar\n"},
|
"pods/foo\npods/bar\n"},
|
||||||
}
|
}
|
||||||
printer, _, _ := printers.GetStandardPrinter("name", "", false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
printer, _ := printers.GetStandardPrinter("name", "", false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||||
for name, item := range tests {
|
for name, item := range tests {
|
||||||
buff := &bytes.Buffer{}
|
buff := &bytes.Buffer{}
|
||||||
err := printer.PrintObj(item.obj, buff)
|
err := printer.PrintObj(item.obj, buff)
|
||||||
|
@ -2235,7 +2246,7 @@ func TestAllowMissingKeys(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
printer, _, err := printers.GetStandardPrinter(test.Format, test.Template, false, test.AllowMissingTemplateKeys, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
printer, err := printers.GetStandardPrinter(test.Format, test.Template, false, test.AllowMissingTemplateKeys, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,10 @@ func (p *JSONPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *JSONPrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
|
// YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
|
||||||
// The input object is assumed to be in the internal version of an API and is converted
|
// The input object is assumed to be in the internal version of an API and is converted
|
||||||
// to the given version first.
|
// to the given version first.
|
||||||
|
@ -99,3 +103,7 @@ func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||||
func (p *YAMLPrinter) HandledResources() []string {
|
func (p *YAMLPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *YAMLPrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -155,3 +155,7 @@ func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||||
func (p *JSONPathPrinter) HandledResources() []string {
|
func (p *JSONPathPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *JSONPathPrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -87,3 +87,7 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||||
func (p *NamePrinter) HandledResources() []string {
|
func (p *NamePrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *NamePrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -25,92 +25,102 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetStandardPrinter takes a format type, an optional format argument. It will return true
|
// GetStandardPrinter takes a format type, an optional format argument. It will return
|
||||||
// if the format is generic (untyped), otherwise it will return false. The printer
|
// a printer or an error. The printer is agnostic to schema versions, so you must
|
||||||
// is agnostic to schema versions, so you must send arguments to PrintObj in the
|
// send arguments to PrintObj in the version you wish them to be shown using a
|
||||||
// version you wish them to be shown using a VersionedPrinter (typically when
|
// VersionedPrinter (typically when generic is true).
|
||||||
// generic is true).
|
func GetStandardPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options PrintOptions) (ResourcePrinter, error) {
|
||||||
func GetStandardPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (ResourcePrinter, bool, error) {
|
|
||||||
var printer ResourcePrinter
|
var printer ResourcePrinter
|
||||||
switch format {
|
switch format {
|
||||||
|
|
||||||
case "json":
|
case "json":
|
||||||
printer = &JSONPrinter{}
|
printer = &JSONPrinter{}
|
||||||
|
|
||||||
case "yaml":
|
case "yaml":
|
||||||
printer = &YAMLPrinter{}
|
printer = &YAMLPrinter{}
|
||||||
|
|
||||||
case "name":
|
case "name":
|
||||||
printer = &NamePrinter{
|
printer = &NamePrinter{
|
||||||
Typer: typer,
|
Typer: typer,
|
||||||
Decoders: decoders,
|
Decoders: decoders,
|
||||||
Mapper: mapper,
|
Mapper: mapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
case "template", "go-template":
|
case "template", "go-template":
|
||||||
if len(formatArgument) == 0 {
|
if len(formatArgument) == 0 {
|
||||||
return nil, false, fmt.Errorf("template format specified but no template given")
|
return nil, fmt.Errorf("template format specified but no template given")
|
||||||
}
|
}
|
||||||
templatePrinter, err := NewTemplatePrinter([]byte(formatArgument))
|
templatePrinter, err := NewTemplatePrinter([]byte(formatArgument))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
|
return nil, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
|
||||||
}
|
}
|
||||||
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||||
printer = templatePrinter
|
printer = templatePrinter
|
||||||
|
|
||||||
case "templatefile", "go-template-file":
|
case "templatefile", "go-template-file":
|
||||||
if len(formatArgument) == 0 {
|
if len(formatArgument) == 0 {
|
||||||
return nil, false, fmt.Errorf("templatefile format specified but no template file given")
|
return nil, fmt.Errorf("templatefile format specified but no template file given")
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(formatArgument)
|
data, err := ioutil.ReadFile(formatArgument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||||
}
|
}
|
||||||
templatePrinter, err := NewTemplatePrinter(data)
|
templatePrinter, err := NewTemplatePrinter(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
return nil, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
||||||
}
|
}
|
||||||
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||||
printer = templatePrinter
|
printer = templatePrinter
|
||||||
|
|
||||||
case "jsonpath":
|
case "jsonpath":
|
||||||
if len(formatArgument) == 0 {
|
if len(formatArgument) == 0 {
|
||||||
return nil, false, fmt.Errorf("jsonpath template format specified but no template given")
|
return nil, fmt.Errorf("jsonpath template format specified but no template given")
|
||||||
}
|
}
|
||||||
jsonpathPrinter, err := NewJSONPathPrinter(formatArgument)
|
jsonpathPrinter, err := NewJSONPathPrinter(formatArgument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
|
return nil, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
|
||||||
}
|
}
|
||||||
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||||
printer = jsonpathPrinter
|
printer = jsonpathPrinter
|
||||||
|
|
||||||
case "jsonpath-file":
|
case "jsonpath-file":
|
||||||
if len(formatArgument) == 0 {
|
if len(formatArgument) == 0 {
|
||||||
return nil, false, fmt.Errorf("jsonpath file format specified but no template file file given")
|
return nil, fmt.Errorf("jsonpath file format specified but no template file file given")
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(formatArgument)
|
data, err := ioutil.ReadFile(formatArgument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||||
}
|
}
|
||||||
jsonpathPrinter, err := NewJSONPathPrinter(string(data))
|
jsonpathPrinter, err := NewJSONPathPrinter(string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
return nil, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
||||||
}
|
}
|
||||||
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||||
printer = jsonpathPrinter
|
printer = jsonpathPrinter
|
||||||
|
|
||||||
case "custom-columns":
|
case "custom-columns":
|
||||||
var err error
|
var err error
|
||||||
if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, decoders[0], noHeaders); err != nil {
|
if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, decoders[0], noHeaders); err != nil {
|
||||||
return nil, false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case "custom-columns-file":
|
case "custom-columns-file":
|
||||||
file, err := os.Open(formatArgument)
|
file, err := os.Open(formatArgument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if printer, err = NewCustomColumnsPrinterFromTemplate(file, decoders[0]); err != nil {
|
if printer, err = NewCustomColumnsPrinterFromTemplate(file, decoders[0]); err != nil {
|
||||||
return nil, false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case "wide":
|
case "wide":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "":
|
case "":
|
||||||
return nil, false, nil
|
|
||||||
|
printer = NewHumanReadablePrinter(encoder, decoders[0], options)
|
||||||
default:
|
default:
|
||||||
return nil, false, fmt.Errorf("output format %q not recognized", format)
|
return nil, fmt.Errorf("output format %q not recognized", format)
|
||||||
}
|
}
|
||||||
return printer, true, nil
|
return printer, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,10 @@ func (p *TemplatePrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *TemplatePrinter) IsGeneric() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// safeExecute tries to execute the template, but catches panics and returns an error
|
// safeExecute tries to execute the template, but catches panics and returns an error
|
||||||
// should the template engine panic.
|
// should the template engine panic.
|
||||||
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
|
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
|
||||||
|
|
|
@ -61,3 +61,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||||
func (p *VersionedPrinter) HandledResources() []string {
|
func (p *VersionedPrinter) HandledResources() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *VersionedPrinter) IsGeneric() bool {
|
||||||
|
return p.printer.IsGeneric()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue