remove printer helpers

This commit is contained in:
juanvallejo 2018-05-01 15:48:46 -04:00
parent d7d4381961
commit 5a34e4f594
24 changed files with 286 additions and 382 deletions

View File

@ -90,8 +90,10 @@ func NewCmdApiResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams
cmdutil.CheckErr(o.RunApiResources(cmd, f))
},
}
cmdutil.AddOutputFlags(cmd)
cmdutil.AddNoHeadersFlags(cmd)
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
cmd.Flags().StringP("output", "o", "", "Output format. One of: wide|name.")
cmd.Flags().StringVar(&o.APIGroup, "api-group", "", "Limit to resources in the specified API group.")
cmd.Flags().BoolVar(&o.Namespaced, "namespaced", true, "Namespaced indicates if a resource is namespaced or not.")
cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.")

View File

@ -102,8 +102,9 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IO
},
}
o.PrintFlags.AddFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddPrinterFlags(cmd)
cmd.Flags().BoolVar(&o.CreateAnnotation, "create-annotation", o.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
kubectl.AddJsonFilenameFlag(cmd, &o.FilenameOptions.Filenames, "Filename, directory, or URL to files that contains the last-applied-configuration annotations")

View File

@ -1121,7 +1121,7 @@ func TestRunApplySetLastApplied(t *testing.T) {
name: "set with exist object",
filePath: filenameRC,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc configured\n",
expectedOut: "replicationcontroller/test-rc\n",
output: "name",
},
{
@ -1142,14 +1142,14 @@ func TestRunApplySetLastApplied(t *testing.T) {
name: "set with exist object output json",
filePath: filenameRCJSON,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc configured\n",
expectedOut: "replicationcontroller/test-rc\n",
output: "name",
},
{
name: "set test for a directory of files",
filePath: dirName,
expectedErr: "",
expectedOut: "replicationcontroller/test-rc configured\nreplicationcontroller/test-rc configured\n",
expectedOut: "replicationcontroller/test-rc\nreplicationcontroller/test-rc\n",
output: "name",
},
}

View File

@ -24,7 +24,9 @@ go_library(
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/resource:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/registry/rbac/reconciliation:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",

View File

@ -17,24 +17,23 @@ limitations under the License.
package auth
import (
"io"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)
func NewCmdAuth(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
// Parent command to which all subcommands are added.
cmds := &cobra.Command{
Use: "auth",
Short: "Inspect authorization",
Long: `Inspect authorization`,
Run: cmdutil.DefaultSubCommandRun(errOut),
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
}
cmds.AddCommand(NewCmdCanI(f, out, errOut))
cmds.AddCommand(NewCmdReconcile(f, out, errOut))
cmds.AddCommand(NewCmdCanI(f, streams))
cmds.AddCommand(NewCmdReconcile(f, streams))
return cmds
}

View File

@ -19,12 +19,12 @@ package auth
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -48,8 +48,7 @@ type CanIOptions struct {
Subresource string
ResourceName string
Out io.Writer
Err io.Writer
genericclioptions.IOStreams
}
var (
@ -81,10 +80,9 @@ var (
kubectl auth can-i get /logs/`)
)
func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := &CanIOptions{
Out: out,
Err: err,
IOStreams: streams,
}
cmd := &cobra.Command{
@ -232,9 +230,9 @@ func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) sc
gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
if err != nil {
if len(groupResource.Group) == 0 {
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
} else {
fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
fmt.Fprintf(o.ErrOut, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
}
return schema.GroupVersionResource{Resource: resourceArg}
}

View File

@ -119,7 +119,7 @@ func TestRunAccessCheck(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
test.o.Out = ioutil.Discard
test.o.Err = ioutil.Discard
test.o.ErrOut = ioutil.Discard
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()

View File

@ -18,7 +18,6 @@ package auth
import (
"errors"
"io"
"github.com/golang/glog"
"github.com/spf13/cobra"
@ -29,21 +28,25 @@ import (
internalrbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/registry/rbac/reconciliation"
)
// ReconcileOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
// referencing the cmd.Flags()
type ReconcileOptions struct {
PrintFlags *printers.PrintFlags
FilenameOptions *resource.FilenameOptions
Visitor resource.Visitor
RBACClient internalrbacclient.RbacInterface
NamespaceClient internalcoreclient.NamespaceInterface
Print func(*resource.Info) error
PrintObject printers.ResourcePrinterFunc
Out io.Writer
Err io.Writer
genericclioptions.IOStreams
}
var (
@ -57,12 +60,16 @@ var (
kubectl auth reconcile -f my-rbac-rules.yaml`)
)
func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
fileOptions := &resource.FilenameOptions{}
o := &ReconcileOptions{
Out: out,
Err: err,
func NewReconcileOptions(ioStreams genericclioptions.IOStreams) *ReconcileOptions {
return &ReconcileOptions{
FilenameOptions: &resource.FilenameOptions{},
PrintFlags: printers.NewPrintFlags("reconciled"),
IOStreams: ioStreams,
}
}
func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewReconcileOptions(streams)
cmd := &cobra.Command{
Use: "reconcile -f FILENAME",
@ -71,21 +78,21 @@ func NewCmdReconcile(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
Long: reconcileLong,
Example: reconcileExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(cmd, f, args, fileOptions))
cmdutil.CheckErr(o.Complete(cmd, f, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunReconcile())
},
}
cmdutil.AddPrinterFlags(cmd)
usage := "identifying the resource to reconcile."
cmdutil.AddFilenameOptionFlags(cmd, fileOptions, usage)
o.PrintFlags.AddFlags(cmd)
cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to reconcile.")
cmd.MarkFlagRequired("filename")
return cmd
}
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string, options *resource.FilenameOptions) error {
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
if len(args) > 0 {
return errors.New("no arguments are allowed")
}
@ -99,7 +106,7 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args
WithScheme(legacyscheme.Scheme).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
FilenameParam(enforceNamespace, o.FilenameOptions).
Flatten().
Do()
@ -115,17 +122,12 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args
o.RBACClient = client.Rbac()
o.NamespaceClient = client.Core().Namespaces()
dryRun := false
output := cmdutil.GetFlagString(cmd, "output")
shortOutput := output == "name"
o.Print = func(info *resource.Info) error {
if len(output) > 0 && !shortOutput {
return cmdutil.PrintObject(cmd, info.Object, o.Out)
}
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "reconciled")
return nil
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObject = printer.PrintObj
return nil
}
@ -139,13 +141,13 @@ func (o *ReconcileOptions) Validate() error {
if o.NamespaceClient == nil {
return errors.New("ReconcileOptions.NamespaceClient must be set")
}
if o.Print == nil {
if o.PrintObject == nil {
return errors.New("ReconcileOptions.Print must be set")
}
if o.Out == nil {
return errors.New("ReconcileOptions.Out must be set")
}
if o.Err == nil {
if o.ErrOut == nil {
return errors.New("ReconcileOptions.Err must be set")
}
return nil
@ -157,10 +159,6 @@ func (o *ReconcileOptions) RunReconcile() error {
return err
}
// shallowInfoCopy this is used to later twiddle the Object for printing
// we really need more straightforward printing options
shallowInfoCopy := *info
switch t := info.Object.(type) {
case *rbac.Role:
reconcileOptions := reconciliation.ReconcileRoleOptions{
@ -176,8 +174,7 @@ func (o *ReconcileOptions) RunReconcile() error {
if err != nil {
return err
}
shallowInfoCopy.Object = result.Role.GetObject()
o.Print(&shallowInfoCopy)
o.PrintObject(result.Role.GetObject(), o.Out)
case *rbac.ClusterRole:
reconcileOptions := reconciliation.ReconcileRoleOptions{
@ -192,8 +189,7 @@ func (o *ReconcileOptions) RunReconcile() error {
if err != nil {
return err
}
shallowInfoCopy.Object = result.Role.GetObject()
o.Print(&shallowInfoCopy)
o.PrintObject(result.Role.GetObject(), o.Out)
case *rbac.RoleBinding:
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
@ -209,8 +205,7 @@ func (o *ReconcileOptions) RunReconcile() error {
if err != nil {
return err
}
shallowInfoCopy.Object = result.RoleBinding.GetObject()
o.Print(&shallowInfoCopy)
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
case *rbac.ClusterRoleBinding:
reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
@ -225,8 +220,7 @@ func (o *ReconcileOptions) RunReconcile() error {
if err != nil {
return err
}
shallowInfoCopy.Object = result.RoleBinding.GetObject()
o.Print(&shallowInfoCopy)
o.PrintObject(result.RoleBinding.GetObject(), o.Out)
default:
glog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())

View File

@ -123,8 +123,10 @@ func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOS
cmdutil.CheckErr(options.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
},
}
options.PrintFlags.AddFlags(cmd)
cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
cmdutil.AddOutputFlagsForMutation(cmd)
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
return cmd
@ -173,8 +175,10 @@ func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStre
cmdutil.CheckErr(options.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
},
}
options.PrintFlags.AddFlags(cmd)
cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
cmdutil.AddOutputFlagsForMutation(cmd)
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, "identifying the resource to update")
return cmd

View File

@ -309,7 +309,7 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
NewCmdPortForward(f, out, err),
NewCmdProxy(f, out),
NewCmdCp(f, ioStreams),
auth.NewCmdAuth(f, out, err),
auth.NewCmdAuth(f, ioStreams),
},
},
{
@ -355,7 +355,7 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
}
cmds.AddCommand(alpha)
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), out, err))
cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), ioStreams))
cmds.AddCommand(NewCmdPlugin(f, in, out, err))
cmds.AddCommand(NewCmdVersion(f, ioStreams))
cmds.AddCommand(NewCmdApiVersions(f, ioStreams))

View File

@ -14,6 +14,7 @@ go_library(
"current_context.go",
"delete_cluster.go",
"delete_context.go",
"flags.go",
"get_clusters.go",
"get_contexts.go",
"navigation_step_parser.go",
@ -30,6 +31,7 @@ go_library(
deps = [
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
@ -64,6 +66,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",

View File

@ -18,7 +18,6 @@ package config
import (
"fmt"
"io"
"path"
"strconv"
@ -27,11 +26,12 @@ import (
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *cobra.Command {
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams genericclioptions.IOStreams) *cobra.Command {
if len(pathOptions.ExplicitFileFlag) == 0 {
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
}
@ -48,25 +48,26 @@ func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, out, er
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(errOut),
Run: cmdutil.DefaultSubCommandRun(streams.Out),
}
// file paths are common to all sub commands
cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
cmd.AddCommand(NewCmdConfigView(f, out, errOut, pathOptions))
cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions))
cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions))
cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigSet(out, pathOptions))
cmd.AddCommand(NewCmdConfigUnset(out, pathOptions))
cmd.AddCommand(NewCmdConfigCurrentContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigUseContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigGetContexts(out, pathOptions))
cmd.AddCommand(NewCmdConfigGetClusters(out, pathOptions))
cmd.AddCommand(NewCmdConfigDeleteCluster(out, pathOptions))
cmd.AddCommand(NewCmdConfigDeleteContext(out, errOut, pathOptions))
cmd.AddCommand(NewCmdConfigRenameContext(out, pathOptions))
// TODO(juanvallejo): update all subcommands to work with genericclioptions.IOStreams
cmd.AddCommand(NewCmdConfigView(f, streams, pathOptions))
cmd.AddCommand(NewCmdConfigSetCluster(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSetAuthInfo(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSetContext(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigSet(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigUnset(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigCurrentContext(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigUseContext(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigGetContexts(streams, pathOptions))
cmd.AddCommand(NewCmdConfigGetClusters(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigDeleteCluster(streams.Out, pathOptions))
cmd.AddCommand(NewCmdConfigDeleteContext(streams.Out, streams.ErrOut, pathOptions))
cmd.AddCommand(NewCmdConfigRenameContext(streams.Out, pathOptions))
return cmd
}

View File

@ -17,7 +17,6 @@ limitations under the License.
package config
import (
"bytes"
"fmt"
"io/ioutil"
"os"
@ -31,6 +30,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
func newRedFederalCowHammerConfig() clientcmdapi.Config {
@ -863,9 +863,8 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
argsToUse = append(argsToUse, args...)
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfig(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), buf, buf)
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdConfig(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), streams)
cmd.SetArgs(argsToUse)
cmd.Execute()

View File

@ -0,0 +1,95 @@
/*
Copyright 2018 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 config
import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/printers"
)
// PrintFlags 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 {
JSONYamlPrintFlags *printers.JSONYamlPrintFlags
NamePrintFlags *printers.NamePrintFlags
TemplateFlags *printers.KubeTemplatePrintFlags
OutputFormat *string
}
func (f *PrintFlags) Complete(successTemplate string) error {
return f.NamePrintFlags.Complete(successTemplate)
}
func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) {
outputFormat := ""
if f.OutputFormat != nil {
outputFormat = *f.OutputFormat
}
if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) {
return p, err
}
if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) {
return p, err
}
if p, err := f.TemplateFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) {
return p, err
}
return nil, printers.NoCompatiblePrinterError{Options: f}
}
func (f *PrintFlags) 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].")
}
}
// 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
return f
}
func NewPrintFlags(operation string) *PrintFlags {
outputFormat := ""
return &PrintFlags{
OutputFormat: &outputFormat,
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(operation),
TemplateFlags: printers.NewKubeTemplatePrintFlags(),
}
}

View File

@ -31,6 +31,7 @@ import (
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
)
@ -41,7 +42,8 @@ type GetContextsOptions struct {
nameOnly bool
showHeaders bool
contextNames []string
out io.Writer
genericclioptions.IOStreams
}
var (
@ -57,8 +59,12 @@ var (
// NewCmdConfigGetContexts creates a command object for the "get-contexts" action, which
// retrieves one or more contexts from a kubeconfig.
func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
options := &GetContextsOptions{configAccess: configAccess}
func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
options := &GetContextsOptions{
configAccess: configAccess,
IOStreams: streams,
}
cmd := &cobra.Command{
Use: "get-contexts [(-o|--output=)name)]",
@ -74,22 +80,22 @@ func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess)
cmdutil.CheckErr(fmt.Errorf("output must be one of '' or 'name': %v", outputFormat))
}
if !supportedOutputTypes.Has(outputFormat) {
fmt.Fprintf(out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
fmt.Fprintf(options.Out, "--output %v is not available in kubectl config get-contexts; resetting to default output format\n", outputFormat)
cmd.Flags().Set("output", "")
}
cmdutil.CheckErr(options.Complete(cmd, args, out))
cmdutil.CheckErr(options.Complete(cmd, args))
cmdutil.CheckErr(options.RunGetContexts())
},
}
cmdutil.AddOutputFlags(cmd)
cmdutil.AddNoHeadersFlags(cmd)
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
cmd.Flags().StringP("output", "o", "", "Output format. One of: name")
return cmd
}
// Complete assigns GetContextsOptions from the args.
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string, out io.Writer) error {
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
o.contextNames = args
o.out = out
o.nameOnly = false
if cmdutil.GetFlagString(cmd, "output") == "name" {
o.nameOnly = true
@ -109,9 +115,9 @@ func (o GetContextsOptions) RunGetContexts() error {
return err
}
out, found := o.out.(*tabwriter.Writer)
out, found := o.Out.(*tabwriter.Writer)
if !found {
out = printers.GetNewTabWriter(o.out)
out = printers.GetNewTabWriter(o.Out)
defer out.Flush()
}

View File

@ -17,13 +17,13 @@ limitations under the License.
package config
import (
"bytes"
"io/ioutil"
"os"
"testing"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
type getContextsTest struct {
@ -157,11 +157,11 @@ func (test getContextsTest) run(t *testing.T) {
pathOptions := clientcmd.NewDefaultPathOptions()
pathOptions.GlobalFile = fakeKubeFile.Name()
pathOptions.EnvVar = ""
buf := bytes.NewBuffer([]byte{})
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
options := GetContextsOptions{
configAccess: pathOptions,
}
cmd := NewCmdConfigGetContexts(buf, options.configAccess)
cmd := NewCmdConfigGetContexts(streams, options.configAccess)
if test.nameOnly {
cmd.Flags().Set("output", "name")
}

View File

@ -18,8 +18,6 @@ package config
import (
"errors"
"fmt"
"io"
"github.com/spf13/cobra"
@ -29,16 +27,24 @@ import (
"k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers"
)
type ViewOptions struct {
PrintFlags *PrintFlags
PrintObject printers.ResourcePrinterFunc
ConfigAccess clientcmd.ConfigAccess
Merge flag.Tristate
Flatten bool
Minify bool
RawByteData bool
OutputFormat string
genericclioptions.IOStreams
}
var (
@ -56,12 +62,17 @@ var (
# Get the password for the e2e user
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`)
defaultOutputFormat = "yaml"
)
func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
options := &ViewOptions{ConfigAccess: ConfigAccess}
// Default to yaml
defaultOutputFormat := "yaml"
func NewCmdConfigView(f cmdutil.Factory, streams genericclioptions.IOStreams, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
o := &ViewOptions{
PrintFlags: NewPrintFlags("").WithDefaultOutput("yaml"),
ConfigAccess: ConfigAccess,
IOStreams: streams,
}
cmd := &cobra.Command{
Use: "view",
@ -69,40 +80,48 @@ func NewCmdConfigView(f cmdutil.Factory, out, errOut io.Writer, ConfigAccess cli
Long: view_long,
Example: view_example,
Run: func(cmd *cobra.Command, args []string) {
options.Complete()
outputFormat := cmdutil.GetFlagString(cmd, "output")
if outputFormat == "wide" {
fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
// TODO: once printing is abstracted, this should be handled at flag declaration time
cmd.Flags().Set("output", defaultOutputFormat)
}
if outputFormat == "" {
fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
// TODO: once printing is abstracted, this should be handled at flag declaration time
cmd.Flags().Set("output", defaultOutputFormat)
}
printOpts := cmdutil.ExtractCmdPrintOptions(cmd, false)
printer, err := cmdutil.PrinterForOptions(printOpts)
cmdutil.CheckErr(err)
cmdutil.CheckErr(options.Run(out, printer))
cmdutil.CheckErr(o.Complete(cmd))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
}
cmdutil.AddPrinterFlags(cmd)
cmd.Flags().Set("output", defaultOutputFormat)
o.PrintFlags.AddFlags(cmd)
options.Merge.Default(true)
mergeFlag := cmd.Flags().VarPF(&options.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
o.Merge.Default(true)
mergeFlag := cmd.Flags().VarPF(&o.Merge, "merge", "", "Merge the full hierarchy of kubeconfig files")
mergeFlag.NoOptDefVal = "true"
cmd.Flags().BoolVar(&options.RawByteData, "raw", options.RawByteData, "Display raw byte data")
cmd.Flags().BoolVar(&options.Flatten, "flatten", options.Flatten, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
cmd.Flags().BoolVar(&options.Minify, "minify", options.Minify, "Remove all information not used by current-context from the output")
cmd.Flags().BoolVar(&o.RawByteData, "raw", o.RawByteData, "Display raw byte data")
cmd.Flags().BoolVar(&o.Flatten, "flatten", o.Flatten, "Flatten the resulting kubeconfig file into self-contained output (useful for creating portable kubeconfig files)")
cmd.Flags().BoolVar(&o.Minify, "minify", o.Minify, "Remove all information not used by current-context from the output")
return cmd
}
func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error {
func (o *ViewOptions) Complete(cmd *cobra.Command) error {
if o.ConfigAccess.IsExplicitFile() {
if !o.Merge.Provided() {
o.Merge.Set("false")
}
}
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObject = printer.PrintObj
return nil
}
func (o ViewOptions) Validate() error {
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
return errors.New("if merge==false a precise file must to specified")
}
return nil
}
func (o ViewOptions) Run() error {
config, err := o.loadConfig()
if err != nil {
return err
@ -127,22 +146,7 @@ func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error
return err
}
err = printer.PrintObj(convertedObj, out)
if err != nil {
return err
}
return nil
}
func (o *ViewOptions) Complete() bool {
if o.ConfigAccess.IsExplicitFile() {
if !o.Merge.Provided() {
o.Merge.Set("false")
}
}
return true
return o.PrintObject(convertedObj, o.Out)
}
func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
@ -155,14 +159,6 @@ func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
return config, err
}
func (o ViewOptions) Validate() error {
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
return errors.New("if merge==false a precise file must to specified")
}
return nil
}
// getStartingConfig returns the Config object built from the sources specified by the options, the filename read (only if it was a single file), and an error if something goes wrong
func (o *ViewOptions) getStartingConfig() (*clientcmdapi.Config, error) {
switch {

View File

@ -17,7 +17,6 @@ limitations under the License.
package config
import (
"bytes"
"io/ioutil"
"os"
"testing"
@ -25,6 +24,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
type viewClusterTest struct {
@ -141,9 +141,8 @@ func (test viewClusterTest) run(t *testing.T) {
pathOptions := clientcmd.NewDefaultPathOptions()
pathOptions.GlobalFile = fakeKubeFile.Name()
pathOptions.EnvVar = ""
buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfigView(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), buf, errBuf, pathOptions)
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdConfigView(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), streams, pathOptions)
cmd.Flags().Parse(test.flags)
if err := cmd.Execute(); err != nil {
t.Fatalf("unexpected error executing command: %v,kubectl config view flags: %v", err, test.flags)

View File

@ -124,8 +124,6 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
Example: delete_example,
Run: func(cmd *cobra.Command, args []string) {
options := deleteFlags.ToOptions(out, errOut)
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
cmdutil.CheckErr(err)
}
@ -185,6 +183,11 @@ 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.DeleteAll && len(o.LabelSelector) > 0 {
return fmt.Errorf("cannot set --all and --selector at the same time")
}

View File

@ -48,9 +48,7 @@ func fakecmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
},
Run: func(cmd *cobra.Command, args []string) {},
}
return cmd
}

View File

@ -91,8 +91,15 @@ type ReplaceOptions struct {
}
func NewReplaceOptions(out, errOut io.Writer) *ReplaceOptions {
outputFormat := ""
return &ReplaceOptions{
PrintFlags: printers.NewPrintFlags("replaced"),
// TODO(juanvallejo): figure out why we only support the "name" outputFormat in this command
// we only support "-o name" for this command, so only register the name printer
PrintFlags: &printers.PrintFlags{
OutputFormat: &outputFormat,
NamePrintFlags: printers.NewNamePrintFlags("replaced"),
},
DeleteFlags: NewDeleteFlags("to use to replace the resource."),
Out: out,
@ -110,7 +117,6 @@ func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
Long: replaceLong,
Example: replaceExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd))
cmdutil.CheckErr(o.Run())

View File

@ -93,9 +93,16 @@ type ScaleOptions struct {
}
func NewScaleOptions(ioStreams genericclioptions.IOStreams) *ScaleOptions {
outputFormat := ""
return &ScaleOptions{
// TODO(juanvallejo): figure out why we only support the "name" outputFormat in this command
// we only support "-o name" for this command, so only register the name printer
PrintFlags: &printers.PrintFlags{
OutputFormat: &outputFormat,
NamePrintFlags: printers.NewNamePrintFlags("scaled"),
},
RecordFlags: genericclioptions.NewRecordFlags(),
PrintFlags: printers.NewPrintFlags("scaled"),
CurrentReplicas: -1,
Recorder: genericclioptions.NoopRecorder{},
IOStreams: ioStreams,
@ -173,9 +180,6 @@ func (o *ScaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
}
func (o *ScaleOptions) Validate(cmd *cobra.Command) error {
if err := cmdutil.ValidateOutputArgs(cmd); err != nil {
return err
}
if o.Replicas < 0 {
return fmt.Errorf("The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0")
}

View File

@ -18,222 +18,12 @@ package util
import (
"fmt"
"io"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
kubectlscheme "k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
AddNonDeprecatedPrinterFlags(cmd)
cmd.Flags().String("output-version", "", "DEPRECATED: To use a specific API version, fully-qualify the resource, version, and group (for example: 'jobs.v1.batch/myjob').")
cmd.Flags().MarkDeprecated("output-version", "The resource is used exactly as fetched from the API. To get a specific API version, fully-qualify the resource, version, and group (for example: 'jobs.v1.batch/myjob').")
cmd.Flags().MarkHidden("output-version")
}
// AddNonDeprecatedPrinterFlags supports the conversion case which must logically have output-version. Once output-version
// is completely removed, this function can go away.
func AddNonDeprecatedPrinterFlags(cmd *cobra.Command) {
AddOutputFlags(cmd)
AddNoHeadersFlags(cmd)
cmd.Flags().Bool("show-labels", false, "When printing, show all labels as the last column (default hide labels column)")
cmd.Flags().String("template", "", "Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].")
cmd.MarkFlagFilename("template")
cmd.Flags().String("sort-by", "", "If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.")
cmd.Flags().BoolP("show-all", "a", true, "When printing, show all resources (default show all pods including terminated one.)")
cmd.Flags().MarkDeprecated("show-all", "will be removed in an upcoming release")
}
// AddOutputFlagsForMutation adds output related flags to a command. Used by mutations only.
func AddOutputFlagsForMutation(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
}
// AddOutputVarFlagsForMutation adds output related flags to a command. Used by mutations only.
func AddOutputVarFlagsForMutation(cmd *cobra.Command, output *string) {
cmd.Flags().StringVarP(output, "output", "o", *output, "Output mode. Use \"-o name\" for shorter output (resource/name).")
}
// AddOutputFlags adds output related flags to a command.
func AddOutputFlags(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "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().Bool("allow-missing-template-keys", true, "If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.")
}
// AddNoHeadersFlags adds no-headers flags to a command.
func AddNoHeadersFlags(cmd *cobra.Command) {
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
}
// ValidateOutputArgs validates -o flag args for mutations
func ValidateOutputArgs(cmd *cobra.Command) error {
outputMode := GetFlagString(cmd, "output")
if outputMode != "" && outputMode != "name" {
return UsageErrorf(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", outputMode)
}
return nil
}
// PrintSuccess prints a success message and can do a "-o name" as "shortOutput"
// TODO this should really just be a printer. It's got just about the exact same signature.
func PrintSuccess(shortOutput bool, out io.Writer, obj runtime.Object, dryRun bool, operation string) {
dryRunMsg := ""
if dryRun {
dryRunMsg = " (dry run)"
}
// match name printer format
name := "<unknown>"
if acc, err := meta.Accessor(obj); err == nil {
if n := acc.GetName(); len(n) > 0 {
name = n
}
}
// legacy scheme to be sure we work ok with internal types.
// TODO internal types aren't supposed to exist here
groupKind := printers.GetObjectGroupKind(obj, legacyscheme.Scheme)
kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
if len(groupKind.Group) == 0 {
kindString = strings.ToLower(groupKind.Kind)
}
if shortOutput {
// -o name: prints resource/name
fmt.Fprintf(out, "%s/%s\n", kindString, name)
return
}
// understandable output by default
fmt.Fprintf(out, "%s \"%s\" %s%s\n", kindString, name, operation, dryRunMsg)
}
// PrintObject prints a single object based on the default command options
// TODO this should go away once commands can embed the PrintOptions instead
func PrintObject(cmd *cobra.Command, obj runtime.Object, out io.Writer) error {
printer, err := PrinterForOptions(ExtractCmdPrintOptions(cmd, false))
if err != nil {
return err
}
return printer.PrintObj(obj, out)
}
// PrinterForOptions returns the printer for the outputOptions (if given) or
// returns the default printer for the command.
// TODO this should become a function on the PrintOptions struct
func PrinterForOptions(options *printers.PrintOptions) (printers.ResourcePrinter, error) {
// TODO: used by the custom column implementation and the name implementation, break this dependency
decoders := []runtime.Decoder{kubectlscheme.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}
encoder := kubectlscheme.Codecs.LegacyCodec(kubectlscheme.Registry.RegisteredGroupVersions()...)
printer, err := printers.GetStandardPrinter(kubectlscheme.Scheme, encoder, decoders, *options)
if err != nil {
return nil, err
}
// we try to convert to HumanReadablePrinter, if return ok, it must be no generic
// we execute AddHandlers() here before maybeWrapSortingPrinter so that we don't
// need to convert to delegatePrinter again then invoke AddHandlers()
// TODO this looks highly questionable. human readable printers are baked into code. This can just live in the definition of the handler itself
// TODO or be registered there
if humanReadablePrinter, ok := printer.(printers.PrintHandler); ok {
printersinternal.AddHandlers(humanReadablePrinter)
}
printer = maybeWrapSortingPrinter(printer, *options)
// wrap the printer in a versioning printer that understands when to convert and when not to convert
printer = printers.NewVersionedPrinter(printer, legacyscheme.Scheme, legacyscheme.Scheme, kubectlscheme.Versions...)
return printer, nil
}
// ExtractCmdPrintOptions parses printer specific commandline args and
// returns a PrintOptions object.
// Requires that printer flags have been added to cmd (see AddPrinterFlags)
func ExtractCmdPrintOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions {
flags := cmd.Flags()
columnLabel, err := flags.GetStringSlice("label-columns")
if err != nil {
columnLabel = []string{}
}
options := &printers.PrintOptions{
NoHeaders: GetFlagBool(cmd, "no-headers"),
Wide: GetWideFlag(cmd),
ShowAll: GetFlagBool(cmd, "show-all"),
ShowLabels: GetFlagBool(cmd, "show-labels"),
AbsoluteTimestamps: isWatch(cmd),
ColumnLabels: columnLabel,
WithNamespace: withNamespace,
}
var outputFormat string
if flags.Lookup("output") != nil {
outputFormat = GetFlagString(cmd, "output")
}
if flags.Lookup("sort-by") != nil {
options.SortBy = GetFlagString(cmd, "sort-by")
}
// templates are logically optional for specifying a format.
// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
var templateFile string
if flag := flags.Lookup("template"); flag != nil {
if flag.Value.Type() == "string" {
templateFile = GetFlagString(cmd, "template")
}
}
if len(outputFormat) == 0 && len(templateFile) != 0 {
outputFormat = "template"
}
templateFormats := []string{
"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file=", "custom-columns=", "custom-columns-file=",
}
for _, format := range templateFormats {
if strings.HasPrefix(outputFormat, format) {
templateFile = outputFormat[len(format):]
outputFormat = format[:len(format)-1]
}
}
// this function may be invoked by a command that did not call AddPrinterFlags first, so we need
// to be safe about how we access the allow-missing-template-keys flag
if flags.Lookup("allow-missing-template-keys") != nil {
options.AllowMissingKeys = GetFlagBool(cmd, "allow-missing-template-keys")
}
options.OutputFormatType = outputFormat
options.OutputFormatArgument = templateFile
return options
}
func maybeWrapSortingPrinter(printer printers.ResourcePrinter, printOpts printers.PrintOptions) printers.ResourcePrinter {
if len(printOpts.SortBy) != 0 {
return &kubectl.SortingPrinter{
Delegate: printer,
SortField: fmt.Sprintf("{%s}", printOpts.SortBy),
}
}
return printer
}
// SuggestApiResources returns a suggestion to use the "api-resources" command
// to retrieve a supported list of resources
func SuggestApiResources(parent string) string {

View File

@ -65,12 +65,16 @@ func (f *PrintFlags) ToPrinter() (ResourcePrinter, error) {
outputFormat = *f.OutputFormat
}
if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) {
return p, err
if f.JSONYamlPrintFlags != nil {
if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) {
return p, err
}
}
if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) {
return p, err
if f.NamePrintFlags != nil {
if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) {
return p, err
}
}
return nil, NoCompatiblePrinterError{Options: f, OutputFormat: f.OutputFormat}