Skip to content

Commit

Permalink
shell autocomplete for k8s flags
Browse files Browse the repository at this point in the history
  • Loading branch information
wjiec committed Jan 16, 2024
1 parent ff17fff commit 616dfba
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
65 changes: 64 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
package cmd

import (
"errors"
"fmt"
"os"
"runtime/debug"
"strings"

"github.com/derailed/k9s/internal/config/data"
"k8s.io/client-go/tools/clientcmd/api"

"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/color"
Expand Down Expand Up @@ -44,11 +47,19 @@ var (
out = colorable.NewColorableStdout()
)

type FlagError struct{ err error }

func (e *FlagError) Error() string { return e.err.Error() }

func init() {
if err := config.InitLogLoc(); err != nil {
fmt.Printf("Fail to init k9s logs location %s\n", err)
}

rootCmd.SetFlagErrorFunc(func(command *cobra.Command, err error) error {
return &FlagError{err: err}
})

rootCmd.AddCommand(versionCmd(), infoCmd())
initK9sFlags()
initK8sFlags()
Expand All @@ -57,7 +68,10 @@ func init() {
// Execute root command.
func Execute() {
if err := rootCmd.Execute(); err != nil {
panic(err)
var flagError *FlagError
if !errors.As(err, &flagError) {
panic(err)
}
}
}

Expand Down Expand Up @@ -281,6 +295,7 @@ func initK8sFlags() {

initAsFlags()
initCertFlags()
initK8sFlagCompletion()
}

func initAsFlags() {
Expand Down Expand Up @@ -335,3 +350,51 @@ func initCertFlags() {
"Bearer token for authentication to the API server",
)
}

func initK8sFlagCompletion() {
_ = rootCmd.RegisterFlagCompletionFunc("context", k8sFlagCompletionFunc(func(cfg *api.Config) map[string]*api.Context {
return cfg.Contexts
}))

_ = rootCmd.RegisterFlagCompletionFunc("cluster", k8sFlagCompletionFunc(func(cfg *api.Config) map[string]*api.Cluster {
return cfg.Clusters
}))

_ = rootCmd.RegisterFlagCompletionFunc("user", k8sFlagCompletionFunc(func(cfg *api.Config) map[string]*api.AuthInfo {
return cfg.AuthInfos
}))

_ = rootCmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
conn, err := client.InitConnection(client.NewConfig(k8sFlags))
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

nss, err := conn.ValidNamespaceNames()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

return filterFlagCompletions(nss, toComplete)
})
}

func k8sFlagCompletionFunc[T any](picker func(cfg *api.Config) map[string]T) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
k8sCfg, err := client.NewConfig(k8sFlags).RawConfig()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return filterFlagCompletions(picker(&k8sCfg), toComplete)
}
}

func filterFlagCompletions[T any](m map[string]T, toComplete string) ([]string, cobra.ShellCompDirective) {
var completions []string
for name := range m {
if strings.HasPrefix(name, toComplete) {
completions = append(completions, name)
}
}
return completions, cobra.ShellCompDirectiveNoFileComp
}
2 changes: 1 addition & 1 deletion internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func InitConnection(config *Config) (*APIClient, error) {
if err != nil {
log.Error().Err(err).Msgf("Fail to locate metrics-server")
}
if errors.Is(err, noMetricServerErr) || errors.Is(err, metricsUnsupportedErr) {
if err == nil || errors.Is(err, noMetricServerErr) || errors.Is(err, metricsUnsupportedErr) {
return &a, nil
}
a.connOK = false
Expand Down

0 comments on commit 616dfba

Please sign in to comment.