From d0134d301eba153dcda0c79a3a23babf75a14434 Mon Sep 17 00:00:00 2001 From: Zhenzhen Zhao Date: Mon, 17 Oct 2022 09:50:15 +0800 Subject: [PATCH] fix(zsh): ignore inserting zsh-completion if system don't have zsh shell (#1025) * fix(zsh): ignore inserting zsh-completion if system don't have zsh shell - Change envd's zsh-completion script name to `.envd.zsh` - Try to write the `.envd.zsh` by the following methods: 1. write `/usr/share/zsh/site-functions/.envd.zsh` directly. 2. write `/usr/local/share/zsh/site-functions/.envd.zsh` directly. 3. write `$HOME/.envd.zsh` directly and add loaded script into the `$HOME/.zshrc` Signed-off-by: Triple-Z * refact(zsh): use `~/.config/envd/` as a fallback directory Signed-off-by: Triple-Z * fix(zsh): uncomment the dirs Signed-off-by: Triple-Z * refact(zsh): use `fileutil.DefaultConfigDir` Signed-off-by: Triple-Z Signed-off-by: Triple-Z --- pkg/autocomplete/zsh.go | 85 ++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/pkg/autocomplete/zsh.go b/pkg/autocomplete/zsh.go index 31aa81214..ab6e858eb 100644 --- a/pkg/autocomplete/zsh.go +++ b/pkg/autocomplete/zsh.go @@ -17,6 +17,7 @@ package autocomplete import ( "fmt" "os" + "os/exec" "os/user" "path/filepath" "strings" @@ -52,33 +53,62 @@ _cli_zsh_autocomplete() { compdef _cli_zsh_autocomplete envd` +var zshConfig = ` +# envd zsh-completion +[ -f ~/.config/envd/envd.zsh ] && source ~/.config/envd/envd.zsh +` + // If debugging this, it might be required to run `rm ~/.zcompdump*` to remove the cache func InsertZSHCompleteEntry() error { - // should be the same on linux and macOS - path := "/usr/local/share/zsh/site-functions/_envd" - dirPath := filepath.Dir(path) - - dirPathExists, err := fileutil.DirExists(dirPath) + // check the system has zsh + _, err := exec.LookPath("zsh") if err != nil { - return errors.Wrapf(err, "failed to check if %s exists", dirPath) - } - if !dirPathExists { - log.L.Warnf("Warning: unable to enable zsh-completion: %s does not exist", dirPath) - return nil // zsh-completion isn't available, silently fail. + log.L.Debugf("can't find zsh in this system, stop setting the zsh-completion.") + return nil } - pathExists, err := fileutil.FileExists(path) - if err != nil { - return errors.Wrapf(err, "failed to check if %s exists", path) + // should be the same on linux and macOS + filename := "envd.zsh" + homeDir := os.Getenv("HOME") + dirs := []string{ + "/usr/share/zsh/site-functions", + "/usr/local/share/zsh/site-functions", + fileutil.DefaultConfigDir, } - if pathExists { - return nil // file already exists, don't update it. + + var f *os.File + var lastErr error + path := "" + for _, dir := range dirs { + dirPathExists, err := fileutil.DirExists(dir) + if err != nil { + return errors.Wrapf(err, "failed to check if %s exists", dir) + } + if dirPathExists { + path = fmt.Sprintf("%s/%s", dir, filename) + log.L.Debugf("use the zsh-completion path for envd: %s", path) + + pathExists, err := fileutil.FileExists(path) + if err != nil { + lastErr = errors.Wrapf(err, "failed to check if %s exists", path) + } + if pathExists { + return nil // file already exists, don't update it. + } + + // create the completion file + f, err = os.Create(path) + if err != nil { + lastErr = err + continue + } + + break + } } - // create the completion file - f, err := os.Create(path) - if err != nil { - return err + if f == nil { + return lastErr } defer f.Close() @@ -93,6 +123,23 @@ func InsertZSHCompleteEntry() error { return errors.Wrapf(err, "failed writing to %s", path) } + if strings.HasPrefix(path, homeDir) { + zshFile, err := os.OpenFile(fmt.Sprintf("%s/.zshrc", homeDir), os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660) + if err != nil { + log.L.Warnf("unable to open the `~/.zshrc`, please add the following lines into `~/.zshrc` to get the envd zsh completion:\n"+ + " %s\n", zshConfig) + return err + } + defer zshFile.Close() + + _, err = fmt.Fprintf(zshFile, "%s\n", zshConfig) + if err != nil { + log.L.Warnf("unable to write the `~/.zshrc`, please add the following lines into `~/.zshrc` to get the envd zsh completion:\n"+ + " %s\n", zshConfig) + return err + } + } + return deleteZcompdump() }