diff --git a/CHANGELOG.md b/CHANGELOG.md index a219116..abbfc6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,9 @@ -## v0.0.4 (UNRELEASED) -* Allow for listing of current config and context using `-l` and `-lc` flags. +## v0.0.4 (September 25, 2023) +* Allow for listing of current config and context. ## v0.0.3 (September 23, 2023) * Added support for default config at `~/.kube/config`. -* Added context switcher using `-c` flag. +* Added context switcher. ## v0.0.2 (September 22, 2023) * Added `KXD_MATCHER` environment variable for specifying different config matchers. diff --git a/README.md b/README.md index 842d734..8db66bd 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,14 @@ By default, Kubeconfig Switcher looks for files with an extension of `.conf`. Yo ## Usage + * See docs for more info [kxd](docs/kxd.md) + ### Switching Kubeconfig Files To switch between different kubeconfig files, use the following command: ```bash -kxd +kxd f s ``` This command will display a list of available kubeconfig files in your `~/.kube` directory. Select the one you want to use. @@ -63,7 +65,7 @@ This command will display a list of available kubeconfig files in your `~/.kube` To switch between Kubernetes contexts within a kubeconfig file, use the following command: ```bash -kxd -c +kxd ctx s ``` This command will display a list of available contexts in your current kubeconfig file. Select the one you want to switch to. @@ -74,13 +76,13 @@ This command will display a list of available contexts in your current kubeconfi To list the currently set Kubeconfig or Kubernetes Context, use the following commands: ```bash -kxd -l +kxd f c ``` This command will display the currently set kubeconfig file. ```bash -kxd -x +kxd ctx c ``` This command will display the currently set Kubernetes Context. @@ -90,7 +92,7 @@ This command will display the currently set Kubernetes Context. To check the version of Kubeconfig Switcher, use the following command: ```bash -kxd -v +kxd version ``` ### Show your set kubeconfig in your shell prompt diff --git a/docs/kxd.md b/docs/kxd.md new file mode 100644 index 0000000..97f665a --- /dev/null +++ b/docs/kxd.md @@ -0,0 +1,22 @@ +## kxd + +kxd - switch between Kubeconfigs and contexts. + +### Synopsis + +Allows for switching kubeconfig files and contexts, as well as getting the current set ones. + +### Options + +``` + -h, --help help for kxd +``` + +### SEE ALSO + +* [kxd completion](kxd_completion.md) - Generate the autocompletion script for the specified shell +* [kxd context](kxd_context.md) - Kubeconfig context command +* [kxd file](kxd_file.md) - Kubeconfig file command +* [kxd version](kxd_version.md) - kxd version command + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_completion.md b/docs/kxd_completion.md new file mode 100644 index 0000000..5f68039 --- /dev/null +++ b/docs/kxd_completion.md @@ -0,0 +1,25 @@ +## kxd completion + +Generate the autocompletion script for the specified shell + +### Synopsis + +Generate the autocompletion script for kxd for the specified shell. +See each sub-command's help for details on how to use the generated script. + + +### Options + +``` + -h, --help help for completion +``` + +### SEE ALSO + +* [kxd](kxd.md) - kxd - switch between Kubeconfigs and contexts. +* [kxd completion bash](kxd_completion_bash.md) - Generate the autocompletion script for bash +* [kxd completion fish](kxd_completion_fish.md) - Generate the autocompletion script for fish +* [kxd completion powershell](kxd_completion_powershell.md) - Generate the autocompletion script for powershell +* [kxd completion zsh](kxd_completion_zsh.md) - Generate the autocompletion script for zsh + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_completion_bash.md b/docs/kxd_completion_bash.md new file mode 100644 index 0000000..8381838 --- /dev/null +++ b/docs/kxd_completion_bash.md @@ -0,0 +1,44 @@ +## kxd completion bash + +Generate the autocompletion script for bash + +### Synopsis + +Generate the autocompletion script for the bash shell. + +This script depends on the 'bash-completion' package. +If it is not installed already, you can install it via your OS's package manager. + +To load completions in your current shell session: + + source <(kxd completion bash) + +To load completions for every new session, execute once: + +#### Linux: + + kxd completion bash > /etc/bash_completion.d/kxd + +#### macOS: + + kxd completion bash > $(brew --prefix)/etc/bash_completion.d/kxd + +You will need to start a new shell for this setup to take effect. + + +``` +kxd completion bash +``` + +### Options + +``` + -h, --help help for bash + --no-descriptions disable completion descriptions +``` + +### SEE ALSO + +* [kxd completion](kxd_completion.md) - Generate the autocompletion script for the specified shell + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_completion_fish.md b/docs/kxd_completion_fish.md new file mode 100644 index 0000000..2b9952a --- /dev/null +++ b/docs/kxd_completion_fish.md @@ -0,0 +1,35 @@ +## kxd completion fish + +Generate the autocompletion script for fish + +### Synopsis + +Generate the autocompletion script for the fish shell. + +To load completions in your current shell session: + + kxd completion fish | source + +To load completions for every new session, execute once: + + kxd completion fish > ~/.config/fish/completions/kxd.fish + +You will need to start a new shell for this setup to take effect. + + +``` +kxd completion fish [flags] +``` + +### Options + +``` + -h, --help help for fish + --no-descriptions disable completion descriptions +``` + +### SEE ALSO + +* [kxd completion](kxd_completion.md) - Generate the autocompletion script for the specified shell + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_completion_powershell.md b/docs/kxd_completion_powershell.md new file mode 100644 index 0000000..75c3196 --- /dev/null +++ b/docs/kxd_completion_powershell.md @@ -0,0 +1,32 @@ +## kxd completion powershell + +Generate the autocompletion script for powershell + +### Synopsis + +Generate the autocompletion script for powershell. + +To load completions in your current shell session: + + kxd completion powershell | Out-String | Invoke-Expression + +To load completions for every new session, add the output of the above command +to your powershell profile. + + +``` +kxd completion powershell [flags] +``` + +### Options + +``` + -h, --help help for powershell + --no-descriptions disable completion descriptions +``` + +### SEE ALSO + +* [kxd completion](kxd_completion.md) - Generate the autocompletion script for the specified shell + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_completion_zsh.md b/docs/kxd_completion_zsh.md new file mode 100644 index 0000000..0e7d258 --- /dev/null +++ b/docs/kxd_completion_zsh.md @@ -0,0 +1,46 @@ +## kxd completion zsh + +Generate the autocompletion script for zsh + +### Synopsis + +Generate the autocompletion script for the zsh shell. + +If shell completion is not already enabled in your environment you will need +to enable it. You can execute the following once: + + echo "autoload -U compinit; compinit" >> ~/.zshrc + +To load completions in your current shell session: + + source <(kxd completion zsh) + +To load completions for every new session, execute once: + +#### Linux: + + kxd completion zsh > "${fpath[1]}/_kxd" + +#### macOS: + + kxd completion zsh > $(brew --prefix)/share/zsh/site-functions/_kxd + +You will need to start a new shell for this setup to take effect. + + +``` +kxd completion zsh [flags] +``` + +### Options + +``` + -h, --help help for zsh + --no-descriptions disable completion descriptions +``` + +### SEE ALSO + +* [kxd completion](kxd_completion.md) - Generate the autocompletion script for the specified shell + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_context.md b/docs/kxd_context.md new file mode 100644 index 0000000..a155ec6 --- /dev/null +++ b/docs/kxd_context.md @@ -0,0 +1,21 @@ +## kxd context + +Kubeconfig context command + +### Synopsis + +This is the default context command. + +### Options + +``` + -h, --help help for context +``` + +### SEE ALSO + +* [kxd](kxd.md) - kxd - switch between Kubeconfigs and contexts. +* [kxd context current](kxd_context_current.md) - Shows currently set kubeconfig context +* [kxd context switch](kxd_context_switch.md) - Switch kubeconfig contexts + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_context_current.md b/docs/kxd_context_current.md new file mode 100644 index 0000000..591a9dc --- /dev/null +++ b/docs/kxd_context_current.md @@ -0,0 +1,23 @@ +## kxd context current + +Shows currently set kubeconfig context + +### Synopsis + +This shows the current set kubeconfig context. + +``` +kxd context current [flags] +``` + +### Options + +``` + -h, --help help for current +``` + +### SEE ALSO + +* [kxd context](kxd_context.md) - Kubeconfig context command + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_context_switch.md b/docs/kxd_context_switch.md new file mode 100644 index 0000000..560a490 --- /dev/null +++ b/docs/kxd_context_switch.md @@ -0,0 +1,23 @@ +## kxd context switch + +Switch kubeconfig contexts + +### Synopsis + +This allows for switching of your kubeconfig context. + +``` +kxd context switch [flags] +``` + +### Options + +``` + -h, --help help for switch +``` + +### SEE ALSO + +* [kxd context](kxd_context.md) - Kubeconfig context command + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_file.md b/docs/kxd_file.md new file mode 100644 index 0000000..bcc4792 --- /dev/null +++ b/docs/kxd_file.md @@ -0,0 +1,21 @@ +## kxd file + +Kubeconfig file command + +### Synopsis + +This is the default file command. + +### Options + +``` + -h, --help help for file +``` + +### SEE ALSO + +* [kxd](kxd.md) - kxd - switch between Kubeconfigs and contexts. +* [kxd file current](kxd_file_current.md) - Shows currently set kubeconfig +* [kxd file switch](kxd_file_switch.md) - Switch kubeconfig + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_file_current.md b/docs/kxd_file_current.md new file mode 100644 index 0000000..074db21 --- /dev/null +++ b/docs/kxd_file_current.md @@ -0,0 +1,23 @@ +## kxd file current + +Shows currently set kubeconfig + +### Synopsis + +This shows the current set kubeconfig file. + +``` +kxd file current [flags] +``` + +### Options + +``` + -h, --help help for current +``` + +### SEE ALSO + +* [kxd file](kxd_file.md) - Kubeconfig file command + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_file_switch.md b/docs/kxd_file_switch.md new file mode 100644 index 0000000..8ab0644 --- /dev/null +++ b/docs/kxd_file_switch.md @@ -0,0 +1,23 @@ +## kxd file switch + +Switch kubeconfig + +### Synopsis + +This allows for switching of your kubeconfig. + +``` +kxd file switch [flags] +``` + +### Options + +``` + -h, --help help for switch +``` + +### SEE ALSO + +* [kxd file](kxd_file.md) - Kubeconfig file command + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/docs/kxd_version.md b/docs/kxd_version.md new file mode 100644 index 0000000..92fbd34 --- /dev/null +++ b/docs/kxd_version.md @@ -0,0 +1,23 @@ +## kxd version + +kxd version command + +### Synopsis + +Returns the current version of kxd + +``` +kxd version [flags] +``` + +### Options + +``` + -h, --help help for version +``` + +### SEE ALSO + +* [kxd](kxd.md) - kxd - switch between Kubeconfigs and contexts. + +###### Auto generated by spf13/cobra on 25-Sep-2023 diff --git a/go.mod b/go.mod index 96b1cdd..f08db42 100644 --- a/go.mod +++ b/go.mod @@ -9,32 +9,35 @@ require ( ) require ( - github.com/chzyer/readline v1.5.1 // indirect + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect + github.com/imdario/mergo v0.3.6 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.28.2 // indirect k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index e81691d..82a1306 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,10 @@ +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -20,20 +18,19 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -52,6 +49,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= @@ -62,66 +60,52 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -139,11 +123,11 @@ k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/main.go b/main.go index 6bd95d7..b0e269f 100644 --- a/main.go +++ b/main.go @@ -1,294 +1,9 @@ package main import ( - "fmt" - "log" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/manifoldco/promptui" - "github.com/manifoldco/promptui/list" - "github.com/spf13/cobra" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/tools/clientcmd/api" -) - -const ( - NoticeColor = "\033[0;38m%s\u001B[0m" - PromptColor = "\033[1;38m%s\u001B[0m" - CyanColor = "\033[0;36m%s\033[0m" - MagentaColor = "\033[0;35m%s\033[0m" + "github.com/radiusmethod/kxd/src/cmd" ) -var version string = "v0.0.4" - -func newPromptUISearcher(items []string) list.Searcher { - return func(searchInput string, itemIndex int) bool { - return strings.Contains(strings.ToLower(items[itemIndex]), strings.ToLower(searchInput)) - } -} - func main() { - homeDir, err := os.UserHomeDir() - if err != nil { - log.Fatalf("Error getting user home directory: %v\n", err) - } - - var configFlag, contextFlag, listFlag, listContextFlag, versionFlag bool - - rootCmd := &cobra.Command{ - Use: "kxd", - Short: "kxd - switch between Kubeconfigs and contexts.", - Run: func(cmd *cobra.Command, args []string) { - if versionFlag { - fmt.Println("kxd version:", version) - } else if configFlag { - err := runConfigSwitcher(homeDir) - if err != nil { - log.Fatal(err) - } - } else if contextFlag { - err := runContextSwitcher(homeDir) - if err != nil { - log.Fatal(err) - } - } else if listFlag { - err := runListConfig(homeDir) - if err != nil { - log.Fatal(err) - } - } else if listContextFlag { - err := runListContext(homeDir) - if err != nil { - log.Fatal(err) - } - } else { - err := runConfigSwitcher(homeDir) - if err != nil { - log.Fatal(err) - } - } - }, - } - - rootCmd.PersistentFlags().BoolVarP(&configFlag, "switch", "s", false, "Switch configs") - rootCmd.PersistentFlags().BoolVarP(&contextFlag, "context", "c", false, "Switch contexts") - rootCmd.PersistentFlags().BoolVarP(&listFlag, "list", "l", false, "List current config") - rootCmd.PersistentFlags().BoolVarP(&listContextFlag, "list-context", "x", false, "List current context") - rootCmd.PersistentFlags().BoolVarP(&versionFlag, "version", "v", false, "Displays version") - - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func runListConfig(homeDir string) error { - kubeconfigPath := getenv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) - if _, err := os.Stat(kubeconfigPath); err == nil { - fmt.Println(kubeconfigPath) - } else { - fmt.Println("No current kubeconfig found.") - os.Exit(1) - } - return nil -} - -func runListContext(homeDir string) error { - kubeconfigPath := getenv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) - config, err := initializeKubeconfig(kubeconfigPath) - if err != nil { - log.Fatalf("Error initializing kubeconfig: %v\n", err) - } - currentContext := config.CurrentContext - if currentContext == "" { - fmt.Println("No current context found in kubeconfig.") - os.Exit(1) - } - fmt.Printf(currentContext + "\n") - return nil -} - -func runConfigSwitcher(homeDir string) error { - configFileLocation := fmt.Sprintf("%s/.kube", homeDir) - configs := getConfigs(configFileLocation, homeDir) - - err := touchFile(fmt.Sprintf("%s/.kxd", homeDir)) - if err != nil { - log.Fatal(err) - } - - fmt.Printf(NoticeColor, "Kubeconfig Switcher\n") - prompt := promptui.Select{ - Label: fmt.Sprintf(PromptColor, "Choose a config"), - Items: configs, - HideHelp: true, - HideSelected: true, - Templates: &promptui.SelectTemplates{ - Label: "{{ . }}?", - Active: fmt.Sprintf("%s {{ . | cyan }}", promptui.IconSelect), - Inactive: " {{.}}", - Selected: " {{ . | cyan }}", - }, - Searcher: newPromptUISearcher(configs), - StartInSearchMode: true, - Stdout: &bellSkipper{}, - } - - _, result, err := prompt.Run() - if err != nil { - checkError(err) - } - - fmt.Printf(PromptColor, "Choose a config") - fmt.Printf(NoticeColor, "? ") - fmt.Printf(CyanColor, result) - fmt.Println("") - - if result == "default" { - result = "config" - } - writeFile(result, homeDir) - - return nil -} - -func runContextSwitcher(homeDir string) error { - kubeconfigPath := getenv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) - config, err := initializeKubeconfig(kubeconfigPath) - if err != nil { - log.Fatalf("Error initializing kubeconfig: %v\n", err) - } - - contexts := listContexts(kubeconfigPath) - - fmt.Printf(NoticeColor, "Kubeconfig Context Switcher\n") - prompt := promptui.Select{ - Label: fmt.Sprintf(PromptColor, "Choose a context"), - Items: contexts, - HideHelp: true, - HideSelected: true, - Templates: &promptui.SelectTemplates{ - Label: "{{ . }}?", - Active: fmt.Sprintf("%s {{ . | magenta }}", promptui.IconSelect), - Inactive: " {{.}}", - Selected: " {{ . | magenta }}", - }, - Searcher: newPromptUISearcher(contexts), - StartInSearchMode: true, - Stdout: &bellSkipper{}, - } - - _, result, err := prompt.Run() - if err != nil { - checkError(err) - } - - fmt.Printf(PromptColor, "Choose a context") - fmt.Printf(NoticeColor, "? ") - fmt.Printf(MagentaColor, result) - fmt.Println("") - - err = switchContext(config, result, kubeconfigPath) - if err != nil { - log.Fatalf("Error switching context: %v\n", err) - } - return nil -} - -func initializeKubeconfig(kubeconfigPath string) (*api.Config, error) { - return clientcmd.LoadFromFile(kubeconfigPath) -} - -func listContexts(kubeconfigPath string) []string { - config, err := initializeKubeconfig(kubeconfigPath) - if err != nil { - log.Fatalf("Error initializing kubeconfig: %v\n", err) - } - - var contexts []string - for contextName := range config.Contexts { - contexts = append(contexts, contextName) - } - return contexts -} - -func switchContext(config *api.Config, contextName string, kubeconfigPath string) error { - config.CurrentContext = contextName - return clientcmd.WriteToFile(*config, kubeconfigPath) -} - -func touchFile(name string) error { - file, err := os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0644) - if err != nil { - return err - } - return file.Close() -} - -func writeFile(config, loc string) { - s := []byte("") - if config != "unset" { - s = []byte(config) - } - err := os.WriteFile(fmt.Sprintf("%s/.kxd", loc), s, 0644) - if err != nil { - log.Fatal(err) - } -} - -func getConfigs(configFileLocation string, homeDir string) []string { - var files []string - fileExt := getenv("KXD_MATCHER", ".conf") - err := filepath.Walk(configFileLocation, func(path string, f os.FileInfo, _ error) error { - if !f.IsDir() && strings.Contains(f.Name(), fileExt) { - files = append(files, f.Name()) - } - return nil - }) - if err != nil { - log.Fatal(err) - } - - if _, err := os.Stat(fmt.Sprintf("%s/.kube/config", homeDir)); err == nil { - files = append(files, "default") - } - files = append(files, "unset") - sort.Strings(files) - return files -} - -func getenv(key, fallback string) string { - value := os.Getenv(key) - if len(value) == 0 { - return fallback - } - return value -} - -func checkError(err error) { - if err.Error() == "^D" { - // https://github.com/manifoldco/promptui/issues/179 - log.Fatalf(" not supported") - } else if err.Error() == "^C" { - os.Exit(1) - } else { - log.Fatal(err) - } -} - -type bellSkipper struct{} - -func (bs *bellSkipper) Write(b []byte) (int, error) { - const charBell = 7 // c.f. readline.CharBell - if len(b) == 1 && b[0] == charBell { - return 0, nil - } - return os.Stderr.Write(b) -} - -func (bs *bellSkipper) Close() error { - return os.Stderr.Close() + cmd.Execute() } diff --git a/scripts/_kxd b/scripts/_kxd index 53bc858..2305a57 100755 --- a/scripts/_kxd +++ b/scripts/_kxd @@ -1,32 +1,10 @@ #!/usr/bin/env bash -run_context() { - _kxd_prompt --context - return -} - -run_list_context() { - _kxd_prompt --list-context - return -} - -run_list_config() { - _kxd_prompt --list - return -} - -display_help() { - _kxd_prompt --help - return -} - -display_version() { - _kxd_prompt --version - return -} +arg1="$1" +arg2="$2" run_main() { - KUBECONFIG="$KUBECONFIG" _kxd_prompt + KUBECONFIG="$KUBECONFIG" _kxd_prompt file switch selected_config="$(cat ~/.kxd)" if [ -z "$selected_config" ] @@ -37,28 +15,24 @@ run_main() { fi } -arg=$(echo "$1" | tr '[:upper:]' '[:lower:]') +run_file() { + case "$arg2" in + s|switch) + run_main + ;; + *) + _kxd_prompt "$@" + return + ;; + esac +} -case "$arg" in - -c|--context) - run_context - ;; - -l|--list) - run_list_config - ;; - -x|--list-context) - run_list_context - ;; - -h|--help) - display_help - ;; - -s|--switch) - run_main - ;; - -v|--version) - display_version +case "$arg1" in + f|file) + run_file "$arg2" ;; *) - run_main + _kxd_prompt "$@" + return ;; esac diff --git a/src/cmd/context.go b/src/cmd/context.go new file mode 100644 index 0000000..8839281 --- /dev/null +++ b/src/cmd/context.go @@ -0,0 +1,110 @@ +package cmd + +import ( + "fmt" + "github.com/manifoldco/promptui" + "github.com/radiusmethod/kxd/src/utils" + "github.com/spf13/cobra" + "log" + "os" + "path/filepath" +) + +var contextCmd = &cobra.Command{ + Use: "context", + Short: "Kubeconfig context command", + Aliases: []string{"ctx"}, + Long: "This is the default context command.", +} + +var currentContextCmd = &cobra.Command{ + Use: "current", + Short: "Shows currently set kubeconfig context", + Aliases: []string{"c"}, + Long: "This shows the current set kubeconfig context.", + Run: func(cmd *cobra.Command, args []string) { + err := runListContext() + if err != nil { + log.Fatal(err) + } + }, +} + +var switchContextCmd = &cobra.Command{ + Use: "switch", + Short: "Switch kubeconfig contexts", + Aliases: []string{"s"}, + Long: "This allows for switching of your kubeconfig context.", + Run: func(cmd *cobra.Command, args []string) { + err := runContextSwitcher() + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + contextCmd.AddCommand(switchContextCmd) + contextCmd.AddCommand(currentContextCmd) + rootCmd.AddCommand(contextCmd) +} + +func runContextSwitcher() error { + homeDir := utils.GetHomeDir() + kubeconfigPath := utils.GetEnv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) + config, err := utils.InitializeKubeconfig(kubeconfigPath) + if err != nil { + log.Fatalf("Error initializing kubeconfig: %v\n", err) + } + + contexts := utils.ListContexts(kubeconfigPath) + + fmt.Printf(utils.NoticeColor, "Kubeconfig Context Switcher\n") + prompt := promptui.Select{ + Label: fmt.Sprintf(utils.PromptColor, "Choose a context"), + Items: contexts, + HideHelp: true, + HideSelected: true, + Templates: &promptui.SelectTemplates{ + Label: "{{ . }}?", + Active: fmt.Sprintf("%s {{ . | magenta }}", promptui.IconSelect), + Inactive: " {{.}}", + Selected: " {{ . | magenta }}", + }, + Searcher: utils.NewPromptUISearcher(contexts), + StartInSearchMode: true, + Stdout: &utils.BellSkipper{}, + } + + _, result, err := prompt.Run() + if err != nil { + utils.CheckError(err) + } + + fmt.Printf(utils.PromptColor, "Choose a context") + fmt.Printf(utils.NoticeColor, "? ") + fmt.Printf(utils.MagentaColor, result) + fmt.Println("") + + err = utils.SwitchContext(config, result, kubeconfigPath) + if err != nil { + log.Fatalf("Error switching context: %v\n", err) + } + return nil +} + +func runListContext() error { + homeDir := utils.GetHomeDir() + kubeconfigPath := utils.GetEnv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) + config, err := utils.InitializeKubeconfig(kubeconfigPath) + if err != nil { + log.Fatalf("Error initializing kubeconfig: %v\n", err) + } + currentContext := config.CurrentContext + if currentContext == "" { + fmt.Println("No current context found in kubeconfig.") + os.Exit(1) + } + fmt.Printf(currentContext + "\n") + return nil +} diff --git a/src/cmd/file.go b/src/cmd/file.go new file mode 100644 index 0000000..c67b671 --- /dev/null +++ b/src/cmd/file.go @@ -0,0 +1,130 @@ +package cmd + +import ( + "fmt" + "github.com/manifoldco/promptui" + "github.com/radiusmethod/kxd/src/utils" + "github.com/spf13/cobra" + "log" + "os" + "path/filepath" + "sort" + "strings" +) + +var fileCmd = &cobra.Command{ + Use: "file", + Short: "Kubeconfig file command", + Aliases: []string{"f"}, + Long: "This is the default file command.", +} + +var currentFileCmd = &cobra.Command{ + Use: "current", + Short: "Shows currently set kubeconfig", + Aliases: []string{"c"}, + Long: "This shows the current set kubeconfig file.", + Run: func(cmd *cobra.Command, args []string) { + err := runGetCurrentConfig() + if err != nil { + log.Fatal(err) + } + }, +} + +var switchFileCmd = &cobra.Command{ + Use: "switch", + Short: "Switch kubeconfig", + Aliases: []string{"s"}, + Long: "This allows for switching of your kubeconfig.", + Run: func(cmd *cobra.Command, args []string) { + err := runConfigSwitcher() + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + fileCmd.AddCommand(switchFileCmd) + fileCmd.AddCommand(currentFileCmd) + rootCmd.AddCommand(fileCmd) +} + +func runConfigSwitcher() error { + homeDir := utils.GetHomeDir() + configFileLocation := fmt.Sprintf("%s/.kube", homeDir) + configs := getConfigs(configFileLocation, homeDir) + + err := utils.TouchFile(fmt.Sprintf("%s/.kxd", homeDir)) + if err != nil { + log.Fatal(err) + } + + fmt.Printf(utils.NoticeColor, "Kubeconfig Switcher\n") + prompt := promptui.Select{ + Label: fmt.Sprintf(utils.PromptColor, "Choose a config"), + Items: configs, + HideHelp: true, + HideSelected: true, + Templates: &promptui.SelectTemplates{ + Label: "{{ . }}?", + Active: fmt.Sprintf("%s {{ . | cyan }}", promptui.IconSelect), + Inactive: " {{.}}", + Selected: " {{ . | cyan }}", + }, + Searcher: utils.NewPromptUISearcher(configs), + StartInSearchMode: true, + Stdout: &utils.BellSkipper{}, + } + + _, result, err := prompt.Run() + if err != nil { + utils.CheckError(err) + } + + fmt.Printf(utils.PromptColor, "Choose a config") + fmt.Printf(utils.NoticeColor, "? ") + fmt.Printf(utils.CyanColor, result) + fmt.Println("") + + if result == "default" { + result = "config" + } + utils.WriteFile(result, homeDir) + + return nil +} + +func runGetCurrentConfig() error { + homeDir := utils.GetHomeDir() + kubeconfigPath := utils.GetEnv("KUBECONFIG", filepath.Join(homeDir, ".kube/config")) + if _, err := os.Stat(kubeconfigPath); err == nil { + fmt.Println(kubeconfigPath) + } else { + fmt.Println("No current kubeconfig found.") + os.Exit(1) + } + return nil +} + +func getConfigs(configFileLocation string, homeDir string) []string { + var files []string + fileExt := utils.GetEnv("KXD_MATCHER", ".conf") + err := filepath.Walk(configFileLocation, func(path string, f os.FileInfo, _ error) error { + if !f.IsDir() && strings.Contains(f.Name(), fileExt) { + files = append(files, f.Name()) + } + return nil + }) + if err != nil { + log.Fatal(err) + } + + if _, err := os.Stat(fmt.Sprintf("%s/.kube/config", homeDir)); err == nil { + files = append(files, "default") + } + files = append(files, "unset") + sort.Strings(files) + return files +} diff --git a/src/cmd/root.go b/src/cmd/root.go new file mode 100644 index 0000000..134d46b --- /dev/null +++ b/src/cmd/root.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "os" +) + +var rootCmd = &cobra.Command{ + Use: "kxd", + Short: "kxd - switch between Kubeconfigs and contexts.", + Long: "Allows for switching kubeconfig files and contexts, as well as getting the current set ones.", +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/src/cmd/version.go b/src/cmd/version.go new file mode 100644 index 0000000..a082831 --- /dev/null +++ b/src/cmd/version.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" +) + +var version string = "v0.0.4" + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "kxd version command", + Aliases: []string{"v"}, + Long: "Returns the current version of kxd", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("kxd version:", version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/src/utils/common.go b/src/utils/common.go new file mode 100644 index 0000000..7eb2760 --- /dev/null +++ b/src/utils/common.go @@ -0,0 +1,53 @@ +package utils + +import ( + "fmt" + "log" + "os" +) + +func TouchFile(name string) error { + file, err := os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + return file.Close() +} + +func WriteFile(config, loc string) { + s := []byte("") + if config != "unset" { + s = []byte(config) + } + err := os.WriteFile(fmt.Sprintf("%s/.kxd", loc), s, 0644) + if err != nil { + log.Fatal(err) + } +} + +func GetEnv(key, fallback string) string { + value := os.Getenv(key) + if len(value) == 0 { + return fallback + } + return value +} + +func CheckError(err error) { + if err.Error() == "^D" { + // https://github.com/manifoldco/promptui/issues/179 + log.Fatalf(" not supported") + } else if err.Error() == "^C" { + os.Exit(1) + } else { + log.Fatal(err) + } +} + +func GetHomeDir() string { + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatalf("Error getting user home directory: %v\n", err) + } + return homeDir +} diff --git a/src/utils/kube.go b/src/utils/kube.go new file mode 100644 index 0000000..d1d876b --- /dev/null +++ b/src/utils/kube.go @@ -0,0 +1,29 @@ +package utils + +import ( + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + "log" +) + +func InitializeKubeconfig(kubeconfigPath string) (*api.Config, error) { + return clientcmd.LoadFromFile(kubeconfigPath) +} + +func SwitchContext(config *api.Config, contextName string, kubeconfigPath string) error { + config.CurrentContext = contextName + return clientcmd.WriteToFile(*config, kubeconfigPath) +} + +func ListContexts(kubeconfigPath string) []string { + config, err := InitializeKubeconfig(kubeconfigPath) + if err != nil { + log.Fatalf("Error initializing kubeconfig: %v\n", err) + } + + var contexts []string + for contextName := range config.Contexts { + contexts = append(contexts, contextName) + } + return contexts +} diff --git a/src/utils/ui.go b/src/utils/ui.go new file mode 100644 index 0000000..c82581f --- /dev/null +++ b/src/utils/ui.go @@ -0,0 +1,34 @@ +package utils + +import ( + "github.com/manifoldco/promptui/list" + "os" + "strings" +) + +const ( + NoticeColor = "\033[0;38m%s\u001B[0m" + PromptColor = "\033[1;38m%s\u001B[0m" + CyanColor = "\033[0;36m%s\033[0m" + MagentaColor = "\033[0;35m%s\033[0m" +) + +type BellSkipper struct{} + +func NewPromptUISearcher(items []string) list.Searcher { + return func(searchInput string, itemIndex int) bool { + return strings.Contains(strings.ToLower(items[itemIndex]), strings.ToLower(searchInput)) + } +} + +func (bs *BellSkipper) Write(b []byte) (int, error) { + const charBell = 7 // c.f. readline.CharBell + if len(b) == 1 && b[0] == charBell { + return 0, nil + } + return os.Stderr.Write(b) +} + +func (bs *BellSkipper) Close() error { + return os.Stderr.Close() +}