Skip to content

Commit

Permalink
Merge pull request #9 from spideyz0r/zsh
Browse files Browse the repository at this point in the history
Add support to zsh, alpha version
  • Loading branch information
spideyz0r authored Jul 19, 2023
2 parents 1db3918 + 7e9fcf0 commit 58a79ce
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 37 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ kubesw ls ns
kubesw switch ns "somenamespace"
```

## Auto-completion
## Autocompletion
The autocompletion script can be generated with the following:
```
kubesw completion bash
Expand All @@ -93,9 +93,32 @@ You can add the following line to your ~/.bashrc:
source <(`which kubesw` completion bash)
```

For zshell, pick a path under $fpath and put the contents of `kubesw completion zsh`:
```
kubesw completion zsh >$(echo $fpath | cut -d " " -f1)/_kubesw
```

## Fix shell history
In order to have the shell's history, some extra configuration needs to be appended to the rc files.
This will make each command run to be persisted to the history file right-away.


### Bash
~/.bashrc
```
shopt -s histappend
PROMPT_COMMAND="history -a"
```

### Zsh
~/.zshrc
```
setopt inc_append_history
```


## TODO
- Read extra/optional configurations like rc files and PS1 from the configuration file (maybe use viper)
- Add support to zsh
- Improve error checks and messages
- Add --global flag for updating the namespace or context globally
- Investigate the use of eval instead of spawning shells
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func init() {
rootCmd.AddCommand(getCmd)
rootCmd.AddCommand(setCmd)
rootCmd.AddCommand(listCmd)
rootCmd.AddCommand(getVersion)
}

func Execute() error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var (
Use: "version",
Short: "Get version of kubesw",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("v0.0.8")
fmt.Println("v0.0.9")
},
}
)
Expand Down
123 changes: 95 additions & 28 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,33 @@ func InitialSetup() (string, string) {
return strings.Join(existing_files, ":"), kubeconfig_kubesw_dir
}

func read_bashrc() string {
func read_rc(shell string) string {
if debug {
fmt.Printf("Reading bashrc files\n")
fmt.Printf("Reading %s rc files\n", shell)
}
zdotdir := os.Getenv("ZDOTDIR")
homedir := os.Getenv("HOME")
var all_rc_files string
rc_files := []string{
if zdotdir == "" && shell == "zsh" {
zdotdir = homedir
}

rc_shell := make(map[string][]string)
rc_shell["zsh"] = []string{
zdotdir + "/.zshrc",
zdotdir + "/.zprofile",
zdotdir + "/.zlogin",
zdotdir + "/.zlogout",
}
rc_shell["bash"] = []string{
homedir + "/.bashrc",
homedir + "/.bash_profile",
homedir + "/.profile",
homedir + "/.bash_login",
homedir + "/.bash_logout",
}

for _, rc_file := range rc_files {
var all_rc_files string
for _, rc_file := range rc_shell[shell] {
_, err := os.Stat(rc_file)
if os.IsNotExist(err) {
if debug {
Expand Down Expand Up @@ -183,7 +195,9 @@ func SpawnShell(kube_config, history string) {
}
switch shell {
case "/bin/bash":
spawn_bash(kube_config, history)
spawn_generic_shell(kube_config, history, "bash")
case "/bin/zsh":
spawn_generic_shell(kube_config, history, "zsh")
default:
log.Fatal("Unsupported shell")
}
Expand All @@ -193,37 +207,86 @@ func InjectShellHistory(option, value string) string {
return fmt.Sprintf("kubesw set %s %s", option, value)
}

func spawn_bash(kube_config, history string) {
current_rc := read_bashrc()
tmp_rc, err := ioutil.TempFile("", "kubesw_rc")
if err != nil {
log.Fatal(err)
}
tmp_rc_path := tmp_rc.Name()
defer os.Remove(tmp_rc_path)
func spawn_generic_shell(kube_config, history, shell string) {
// to keep history in bash the user needs to put the following to their bashrc
// shopt -s histappend
// PROMPT_COMMAND="history -a"

// to keep history in zsh the user needs to enable setopt inc_append_history
// https://zsh.sourceforge.io/Doc/Release/Options.html#index-SHARE_005fHISTORY

extra_rc_configuration := `
[[ -f "$HOME/.bash_profile" ]] && source "$HOME/.bash_profile"
[[ -f "$HOME/.bash_login" ]] && source "$HOME/.bash_login"
[[ -f "$HOME/.profile" ]] && source "$HOME/.profile"
export KUBECONFIG=` + kube_config + `:$KUBECONFIG
shopt -s histappend
PROMPT_COMMAND="history -a; history -n"
history -s ` + history + `
# export PS1="[\u@\h \W: $(go run main.go get context) @ $(go run main.go get namespace)]\\$ "
`
current_rc := read_rc(shell)

var extra_rc_configuration string
var file *os.File
var tmp_rc_path string
var err error
if shell == "bash" {
file, err = ioutil.TempFile("", "kubesw_rc")
if err != nil {
log.Fatal(err)
}
if debug {
fmt.Printf("Created temporary rc file: %s\n", file.Name())
}
tmp_rc_path = file.Name()
defer os.Remove(tmp_rc_path)
extra_rc_configuration = `
[[ -f "$HOME/.bash_profile" ]] && source "$HOME/.bash_profile"
[[ -f "$HOME/.bash_login" ]] && source "$HOME/.bash_login"
[[ -f "$HOME/.profile" ]] && source "$HOME/.profile"
export KUBECONFIG=` + kube_config + `:$KUBECONFIG
# shopt -s histappend
# PROMPT_COMMAND="history -a; history -n"
history -n
history -s ` + history + `
# export PS1="[\u@\h \W: $(go run main.go get context) @ $(go run main.go get namespace)]\\$ "
`
} else {
extra_rc_configuration = `
[[ -f /etc/zshenv ]] && source "/etc/zshenv"
[[ -f /etc/zsh/zshenv ]] && source "/etc/zsh/zshenv"
[[ -f "$HOME/.zshenv" ]] && source "$HOME/.zshenv"
export KUBECONFIG=` + kube_config + `:$KUBECONFIG
# export PS1="[\u@\h \W: $(go run main.go get context) @ $(go run main.go get namespace)]\\$ "
`
tmp_rc_path, err = ioutil.TempDir("", "zdir")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(tmp_rc_path)
file, err = os.OpenFile(tmp_rc_path + "/.zshrc", os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatal(err)
}
defer file.Close()
}

rc := fmt.Sprintf("%s\n%s", current_rc, extra_rc_configuration)
_, err = tmp_rc.WriteString(rc)
if debug {
fmt.Printf("Writing to rc file: %s:\n", tmp_rc_path)
fmt.Printf("%s\n", rc)
}
_, err = file.WriteString(rc)
if err != nil {
log.Fatal(err)
}

if debug {
fmt.Printf("Spawning bash shell with rcfile: %s\n", tmp_rc_path)
fmt.Printf("Spawning %s shell with rcfile: %s\n", shell, tmp_rc_path)
}

var cmd *exec.Cmd
var env []string
if shell == "bash" {
cmd = exec.Command("/bin/bash")
cmd.Args = []string{"/bin/bash", "--rcfile", tmp_rc_path}
} else {
cmd = exec.Command("/bin/zsh")
env = os.Environ()
env = append(env, "ZDOTDIR=" + tmp_rc_path)
cmd.Env = env
}
cmd := exec.Command("/bin/bash")
cmd.Args = []string{"/bin/bash", "--rcfile", tmp_rc_path}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand All @@ -237,6 +300,10 @@ func spawn_bash(kube_config, history string) {
fmt.Printf("Failed to wait for bash shell: %v", err)
log.Fatal(err)
}
if debug {
fmt.Printf("Shell session closed.")
fmt.Printf("%s", rc)
}
}

func ListContexts() {
Expand Down
14 changes: 12 additions & 2 deletions pkg/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,35 @@ func TestDetectShell(t *testing.T) {
}
}

func TestReadBashrc(t *testing.T) {
func TestReadRc(t *testing.T) {
testCases := []struct {
name string
input string
shell string
expected string
}{
{
name: "/.bashrc",
input: "Test content",
shell: "bash",
expected: "\nTest content",
},
{
name: "/.zshrc",
input: "Test content",
shell: "zsh",
expected: "\nTest content",
},
{
name: "/.bash_logout",
input: "Test content",
shell: "bash",
expected: "\nTest content",
},
{
name: "/.nonexistent",
input: "Anything",
shell: "bash",
expected: "",
},
}
Expand All @@ -70,7 +80,7 @@ func TestReadBashrc(t *testing.T) {
file.WriteString(tc.input)
file.Close()

actual_rc := read_bashrc()
actual_rc := read_rc(tc.shell)
if actual_rc != tc.expected {
t.Errorf("Expected shell to be >>%s<<, but got >>%s<<", tc.expected, actual_rc)
}
Expand Down
11 changes: 7 additions & 4 deletions rpm/kubesw.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
%global go_release go1.18.10

Name: kubesw
Version: 0.0.8
Version: 0.0.9
Release: 1%{?dist}
Summary: kubesw, a tool to switch context and namespaces per terminal
License: GPLv3
Expand Down Expand Up @@ -35,13 +35,16 @@ install -Dpm 0755 %{name} %{buildroot}%{_bindir}/%{name}
%license LICENSE

%changelog
* Mon Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.8-1
* Wed Jul 19 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.9-1
- Add support to zsh

* Tue Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.8-1
- Add keep history feature -- errata: removed 0.0.7

* Mon Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.6-1
* Tue Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.6-1
- Add new features

* Mon Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.5-1
* Tue Jul 18 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.5-1
- Errata: fix modules and readme

* Mon Jul 17 2023 spideyz0r <47341410+spideyz0r@users.noreply.github.com> 0.0.4-1
Expand Down

0 comments on commit 58a79ce

Please sign in to comment.