Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move all bash custom completions to Go #96087

Merged
merged 8 commits into from Jun 26, 2021
Merged
11 changes: 11 additions & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go
Expand Up @@ -35,6 +35,8 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
Expand Down Expand Up @@ -134,6 +136,15 @@ func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioption
Short: i18n.T("Update the annotations on a resource"),
Long: annotateLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: annotateExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
Expand Down
38 changes: 38 additions & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/apiresources/apiresources.go
Expand Up @@ -17,8 +17,11 @@ limitations under the License.
package apiresources

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"

Expand Down Expand Up @@ -275,3 +278,38 @@ func (s sortableResource) compareValues(i, j int) (string, string) {
}
return s.resources[i].APIGroup, s.resources[j].APIGroup
}

// CompGetResourceList returns the list of api resources which begin with `toComplete`.
func CompGetResourceList(f cmdutil.Factory, cmd *cobra.Command, toComplete string) []string {
buf := new(bytes.Buffer)
streams := genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: ioutil.Discard}
o := NewAPIResourceOptions(streams)

// Get the list of resources
o.Output = "name"
o.Cached = true
o.Verbs = []string{"get"}
// TODO:Should set --request-timeout=5s

// Ignore errors as the output may still be valid
o.RunAPIResources(cmd, f)

// Resources can be a comma-separated list. The last element is then
// the one we should complete. For example if toComplete=="pods,secre"
// we should return "pods,secrets"
prefix := ""
suffix := toComplete
lastIdx := strings.LastIndex(toComplete, ",")
if lastIdx != -1 {
prefix = toComplete[0 : lastIdx+1]
suffix = toComplete[lastIdx+1:]
}
var comps []string
resources := strings.Split(buf.String(), "\n")
for _, res := range resources {
if res != "" && strings.HasPrefix(res, suffix) {
comps = append(comps, fmt.Sprintf("%s%s", prefix, res))
}
}
return comps
}
Expand Up @@ -20,6 +20,8 @@ import (
"github.com/spf13/cobra"

"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/editor"
"k8s.io/kubectl/pkg/util/i18n"
Expand Down Expand Up @@ -66,6 +68,15 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
Short: i18n.T("Edit latest last-applied-configuration annotations of a resource/object"),
Long: applyEditLastAppliedLong,
Example: applyEditLastAppliedExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args, cmd))
cmdutil.CheckErr(o.Run())
Expand Down
Expand Up @@ -24,6 +24,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util"
"k8s.io/kubectl/pkg/util/i18n"
Expand Down Expand Up @@ -77,6 +79,15 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
Short: i18n.T("View latest last-applied-configuration annotations of a resource/object"),
Long: applyViewLastAppliedLong,
Example: applyViewLastAppliedExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(cmd, f, args))
cmdutil.CheckErr(options.Validate(cmd))
Expand Down
8 changes: 8 additions & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/attach/attach.go
Expand Up @@ -31,6 +31,7 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/cmd/exec"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
Expand Down Expand Up @@ -104,6 +105,13 @@ func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
Short: i18n.T("Attach to a running container"),
Long: i18n.T("Attach to a process that is already running inside an existing container."),
Example: attachExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
Expand Down
16 changes: 15 additions & 1 deletion staging/src/k8s.io/kubectl/pkg/cmd/autoscale/autoscale.go
Expand Up @@ -19,6 +19,7 @@ package autoscale
import (
"context"
"fmt"
"strings"

"github.com/spf13/cobra"
"k8s.io/klog/v2"
Expand All @@ -31,6 +32,7 @@ import (
"k8s.io/cli-runtime/pkg/resource"
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
"k8s.io/client-go/scale"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
Expand Down Expand Up @@ -107,12 +109,24 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
Short: i18n.T("Auto-scale a Deployment, ReplicaSet, StatefulSet, or ReplicationController"),
Long: autoscaleLong,
Example: autoscaleExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found more than 10 duplication of this loop (there are some more which are just similar but have some additional conditions)

I think this could be moved into some utility function:

func filterPrefix(toComplete string, options []string) []string {
	var comps []string
	for _, comp := range options {
		if strings.HasPrefix(comp, toComplete) {
			comps = append(comps, comp)
		}
	}
	return comps
}

See https://play.golang.org/p/yNuYztVCDv3 for some test cases

} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
ValidArgs: validArgs,
}

// bind flag structs
Expand Down