diff --git a/pkg/kubectl/cmd/config/config.go b/pkg/kubectl/cmd/config/config.go index 12f3991fe6d..dbfa53efb28 100644 --- a/pkg/kubectl/cmd/config/config.go +++ b/pkg/kubectl/cmd/config/config.go @@ -48,7 +48,7 @@ func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams 1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place. 2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list. 3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`), - Run: cmdutil.DefaultSubCommandRun(streams.Out), + Run: cmdutil.DefaultSubCommandRun(streams.ErrOut), } // file paths are common to all sub commands diff --git a/pkg/kubectl/cmd/config/flags.go b/pkg/kubectl/cmd/config/flags.go index ebba3b7f22f..ab4243f40da 100644 --- a/pkg/kubectl/cmd/config/flags.go +++ b/pkg/kubectl/cmd/config/flags.go @@ -22,10 +22,10 @@ import ( "k8s.io/kubernetes/pkg/printers" ) -// PrintFlags composes common printer flag structs +// kubectlConfigPrintFlags composes common printer flag structs // used across all config commands, and provides a method // of retrieving a known printer based on flag values provided. -type PrintFlags struct { +type kubectlConfigPrintFlags struct { JSONYamlPrintFlags *printers.JSONYamlPrintFlags NamePrintFlags *printers.NamePrintFlags TemplateFlags *printers.KubeTemplatePrintFlags @@ -33,11 +33,11 @@ type PrintFlags struct { OutputFormat *string } -func (f *PrintFlags) Complete(successTemplate string) error { +func (f *kubectlConfigPrintFlags) Complete(successTemplate string) error { return f.NamePrintFlags.Complete(successTemplate) } -func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) { +func (f *kubectlConfigPrintFlags) ToPrinter() (printers.ResourcePrinter, error) { outputFormat := "" if f.OutputFormat != nil { outputFormat = *f.OutputFormat @@ -58,34 +58,26 @@ func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) { return nil, printers.NoCompatiblePrinterError{Options: f} } -func (f *PrintFlags) AddFlags(cmd *cobra.Command) { +func (f *kubectlConfigPrintFlags) AddFlags(cmd *cobra.Command) { f.JSONYamlPrintFlags.AddFlags(cmd) f.NamePrintFlags.AddFlags(cmd) f.TemplateFlags.AddFlags(cmd) if f.OutputFormat != nil { - cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].") + cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, "Output format. One of: json|yaml|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].") } } // WithDefaultOutput sets a default output format if one is not provided through a flag value -func (f *PrintFlags) WithDefaultOutput(output string) *PrintFlags { - existingFormat := "" - if f.OutputFormat != nil { - existingFormat = *f.OutputFormat - } - if len(existingFormat) == 0 { - existingFormat = output - } - f.OutputFormat = &existingFormat - +func (f *kubectlConfigPrintFlags) WithDefaultOutput(output string) *kubectlConfigPrintFlags { + f.OutputFormat = &output return f } -func NewPrintFlags(operation string) *PrintFlags { +func newKubeConfigPrintFlags(operation string) *kubectlConfigPrintFlags { outputFormat := "" - return &PrintFlags{ + return &kubectlConfigPrintFlags{ OutputFormat: &outputFormat, JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), diff --git a/pkg/kubectl/cmd/config/view.go b/pkg/kubectl/cmd/config/view.go index 76036cf1c2a..d3eae2a3056 100644 --- a/pkg/kubectl/cmd/config/view.go +++ b/pkg/kubectl/cmd/config/view.go @@ -33,7 +33,7 @@ import ( ) type ViewOptions struct { - PrintFlags *PrintFlags + PrintFlags *kubectlConfigPrintFlags PrintObject printers.ResourcePrinterFunc ConfigAccess clientcmd.ConfigAccess @@ -68,7 +68,7 @@ var ( func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, ConfigAccess clientcmd.ConfigAccess) *cobra.Command { o := &ViewOptions{ - PrintFlags: NewPrintFlags("").WithDefaultOutput("yaml"), + PrintFlags: newKubeConfigPrintFlags("").WithDefaultOutput("yaml"), ConfigAccess: ConfigAccess, IOStreams: streams, diff --git a/pkg/kubectl/cmd/delete.go b/pkg/kubectl/cmd/delete.go index c24c27adc7e..640a52bf364 100644 --- a/pkg/kubectl/cmd/delete.go +++ b/pkg/kubectl/cmd/delete.go @@ -183,9 +183,8 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args } func (o *DeleteOptions) Validate(cmd *cobra.Command) error { - outputMode := cmdutil.GetFlagString(cmd, "output") - if outputMode != "" && outputMode != "name" { - return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", outputMode) + if o.Output != "" && o.Output != "name" { + return cmdutil.UsageErrorf(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", o.Output) } if o.DeleteAll && len(o.LabelSelector) > 0 { diff --git a/pkg/kubectl/cmd/util/printing.go b/pkg/kubectl/cmd/util/printing.go index 1603a3c8eb1..dab4792c1ee 100644 --- a/pkg/kubectl/cmd/util/printing.go +++ b/pkg/kubectl/cmd/util/printing.go @@ -20,8 +20,6 @@ import ( "fmt" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" - "k8s.io/kubernetes/pkg/printers" - printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" ) // SuggestApiResources returns a suggestion to use the "api-resources" command diff --git a/pkg/printers/BUILD b/pkg/printers/BUILD index 578a62d0b19..32e5629c577 100644 --- a/pkg/printers/BUILD +++ b/pkg/printers/BUILD @@ -21,7 +21,6 @@ go_library( "kube_template_flags.go", "name.go", "name_flags.go", - "printers.go", "tabwriter.go", "template.go", "template_flags.go", diff --git a/pkg/printers/flags.go b/pkg/printers/flags.go index 405f01261cc..244a893262a 100644 --- a/pkg/printers/flags.go +++ b/pkg/printers/flags.go @@ -91,15 +91,7 @@ func (f *PrintFlags) AddFlags(cmd *cobra.Command) { // WithDefaultOutput sets a default output format if one is not provided through a flag value func (f *PrintFlags) WithDefaultOutput(output string) *PrintFlags { - existingFormat := "" - if f.OutputFormat != nil { - existingFormat = *f.OutputFormat - } - if len(existingFormat) == 0 { - existingFormat = output - } - f.OutputFormat = &existingFormat - + f.OutputFormat = &output return f } diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 47199b5a10f..82e666e90b0 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -229,78 +229,6 @@ func (obj *TestUnknownType) DeepCopyObject() runtime.Object { return &clone } -func TestPrinter(t *testing.T) { - //test inputs - simpleTest := &TestPrintType{"foo"} - podTest := &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} - podListTest := &api.PodList{ - Items: []api.Pod{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar"}}, - }, - } - emptyListTest := &api.PodList{} - testapi, err := legacyscheme.Scheme.ConvertToVersion(podTest, schema.GroupVersion{Group: "", Version: "v1"}) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - printerTests := []struct { - Name string - PrintOpts *printers.PrintOptions - Input runtime.Object - OutputVersions []schema.GroupVersion - Expect string - }{ - {"test json", &printers.PrintOptions{OutputFormatType: "json", AllowMissingKeys: true}, simpleTest, nil, "{\n \"Data\": \"foo\"\n}\n"}, - {"test yaml", &printers.PrintOptions{OutputFormatType: "yaml", AllowMissingKeys: true}, simpleTest, nil, "Data: foo\n"}, - {"test template", &printers.PrintOptions{OutputFormatType: "template", OutputFormatArgument: "{{if .id}}{{.id}}{{end}}{{if .metadata.name}}{{.metadata.name}}{{end}}", AllowMissingKeys: true}, - podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"}, - {"test jsonpath", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.metadata.name}", AllowMissingKeys: true}, podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"}, - {"test jsonpath list", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.items[*].metadata.name}", AllowMissingKeys: true}, podListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo bar"}, - {"test jsonpath empty list", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.items[*].metadata.name}", AllowMissingKeys: true}, emptyListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, ""}, - {"test name", &printers.PrintOptions{OutputFormatType: "name", AllowMissingKeys: true}, podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "pod/foo\n"}, - {"emits versioned objects", &printers.PrintOptions{OutputFormatType: "template", OutputFormatArgument: "{{.kind}}", AllowMissingKeys: true}, testapi, []schema.GroupVersion{v1.SchemeGroupVersion}, "Pod"}, - } - for _, test := range printerTests { - buf := bytes.NewBuffer([]byte{}) - printer, err := printers.GetStandardPrinter(legacyscheme.Scheme, legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.RegisteredGroupVersions()...), []runtime.Decoder{legacyscheme.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, *test.PrintOpts) - if err != nil { - t.Errorf("in %s, unexpected error: %#v", test.Name, err) - } - if len(test.OutputVersions) > 0 { - printer = printers.NewVersionedPrinter(printer, legacyscheme.Scheme, legacyscheme.Scheme, test.OutputVersions...) - } - if err := printer.PrintObj(test.Input, buf); err != nil { - t.Errorf("in %s, unexpected error: %#v", test.Name, err) - } - if buf.String() != test.Expect { - t.Errorf("in %s, expect %q, got %q", test.Name, test.Expect, buf.String()) - } - } - -} - -func TestBadPrinter(t *testing.T) { - badPrinterTests := []struct { - Name string - PrintOpts *printers.PrintOptions - Error error - }{ - {"empty template", &printers.PrintOptions{OutputFormatType: "template", AllowMissingKeys: false}, fmt.Errorf("template format specified but no template given")}, - {"bad template", &printers.PrintOptions{OutputFormatType: "template", OutputFormatArgument: "{{ .Name", AllowMissingKeys: false}, fmt.Errorf("error parsing template {{ .Name, template: output:1: unclosed action\n")}, - {"bad templatefile", &printers.PrintOptions{OutputFormatType: "templatefile", AllowMissingKeys: false}, fmt.Errorf("template format specified but no template given")}, - {"bad jsonpath", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.Name", AllowMissingKeys: false}, fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")}, - {"unknown format", &printers.PrintOptions{OutputFormatType: "anUnknownFormat", OutputFormatArgument: "", AllowMissingKeys: false}, fmt.Errorf("output format \"anUnknownFormat\" not recognized")}, - } - for _, test := range badPrinterTests { - _, err := printers.GetStandardPrinter(legacyscheme.Scheme, legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.RegisteredGroupVersions()...), []runtime.Decoder{legacyscheme.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, *test.PrintOpts) - if err == nil || err.Error() != test.Error.Error() { - t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err) - } - } -} - func testPrinter(t *testing.T, printer printers.ResourcePrinter, unmarshalFunc func(data []byte, v interface{}) error) { buf := bytes.NewBuffer([]byte{}) @@ -471,8 +399,13 @@ func TestNamePrinter(t *testing.T) { }, "pod/foo\npod/bar\n"}, } - printOpts := &printers.PrintOptions{OutputFormatType: "name", AllowMissingKeys: false} - printer, _ := printers.GetStandardPrinter(legacyscheme.Scheme, legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.RegisteredGroupVersions()...), []runtime.Decoder{legacyscheme.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, *printOpts) + + printFlags := printers.NewPrintFlags("").WithDefaultOutput("name") + printer, err := printFlags.ToPrinter() + if err != nil { + t.Fatalf("unexpected err: %v", err) + } + for name, item := range tests { buff := &bytes.Buffer{} err := printer.PrintObj(item.obj, buff) @@ -2987,44 +2920,6 @@ func TestPrintPodDisruptionBudget(t *testing.T) { } } -func TestAllowMissingKeys(t *testing.T) { - tests := []struct { - Name string - PrintOpts *printers.PrintOptions - Input runtime.Object - Expect string - Error string - }{ - {"test template, allow missing keys", &printers.PrintOptions{OutputFormatType: "template", OutputFormatArgument: "{{.blarg}}", AllowMissingKeys: true}, &api.Pod{}, "", ""}, - {"test template, strict", &printers.PrintOptions{OutputFormatType: "template", OutputFormatArgument: "{{.blarg}}", AllowMissingKeys: false}, &api.Pod{}, "", `error executing template "{{.blarg}}": template: output:1:2: executing "output" at <.blarg>: map has no entry for key "blarg"`}, - {"test jsonpath, allow missing keys", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.blarg}", AllowMissingKeys: true}, &api.Pod{}, "", ""}, - {"test jsonpath, strict", &printers.PrintOptions{OutputFormatType: "jsonpath", OutputFormatArgument: "{.blarg}", AllowMissingKeys: false}, &api.Pod{}, "", "error executing jsonpath \"{.blarg}\": blarg is not found\n"}, - } - for _, test := range tests { - buf := bytes.NewBuffer([]byte{}) - printer, err := printers.GetStandardPrinter(legacyscheme.Scheme, legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.RegisteredGroupVersions()...), []runtime.Decoder{legacyscheme.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, *test.PrintOpts) - if err != nil { - t.Errorf("in %s, unexpected error: %#v", test.Name, err) - } - err = printer.PrintObj(test.Input, buf) - if len(test.Error) == 0 && err != nil { - t.Errorf("in %s, unexpected error: %v", test.Name, err) - continue - } - if len(test.Error) > 0 { - if err == nil { - t.Errorf("in %s, expected to get error: %v", test.Name, test.Error) - } else if e, a := test.Error, err.Error(); e != a { - t.Errorf("in %s, expected error %q, got %q", test.Name, e, a) - } - continue - } - if buf.String() != test.Expect { - t.Errorf("in %s, expect %q, got %q", test.Name, test.Expect, buf.String()) - } - } -} - func TestPrintControllerRevision(t *testing.T) { tests := []struct { history apps.ControllerRevision diff --git a/pkg/printers/printers.go b/pkg/printers/printers.go deleted file mode 100644 index 9daee38807d..00000000000 --- a/pkg/printers/printers.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -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. -*/ - -package printers - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime" -) - -// GetStandardPrinter takes a format type, an optional format argument. It will return -// a printer or an error. The printer is agnostic to schema versions, so you must -// send arguments to PrintObj in the version you wish them to be shown using a -// VersionedPrinter (typically when generic is true). -func GetStandardPrinter(typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options PrintOptions) (ResourcePrinter, error) { - format, formatArgument, allowMissingTemplateKeys := options.OutputFormatType, options.OutputFormatArgument, options.AllowMissingKeys - - var printer ResourcePrinter - switch format { - - case "json", "yaml": - jsonYamlFlags := NewJSONYamlPrintFlags() - p, err := jsonYamlFlags.ToPrinter(format) - if err != nil { - return nil, err - } - - printer = p - - case "name": - nameFlags := NewNamePrintFlags("") - namePrinter, err := nameFlags.ToPrinter(format) - if err != nil { - return nil, err - } - - printer = namePrinter - - case "template", "go-template", "jsonpath", "templatefile", "go-template-file", "jsonpath-file": - // TODO: construct and bind this separately (at the command level) - kubeTemplateFlags := KubeTemplatePrintFlags{ - GoTemplatePrintFlags: &GoTemplatePrintFlags{ - AllowMissingKeys: &allowMissingTemplateKeys, - TemplateArgument: &formatArgument, - }, - JSONPathPrintFlags: &JSONPathPrintFlags{ - AllowMissingKeys: &allowMissingTemplateKeys, - TemplateArgument: &formatArgument, - }, - } - - kubeTemplatePrinter, err := kubeTemplateFlags.ToPrinter(format) - if err != nil { - return nil, err - } - - printer = kubeTemplatePrinter - - case "custom-columns", "custom-columns-file": - customColumnsFlags := &CustomColumnsPrintFlags{ - NoHeaders: options.NoHeaders, - TemplateArgument: formatArgument, - } - customColumnsPrinter, err := customColumnsFlags.ToPrinter(format) - if err != nil { - return nil, err - } - - printer = customColumnsPrinter - - default: - return nil, fmt.Errorf("output format %q not recognized", format) - } - return printer, nil -}