cli/completion_installer.go (143 lines of code) (raw):

// Copyright (c) 2009-present, Alibaba Cloud All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cli import ( "fmt" "os" "os/user" "github.com/aliyun/aliyun-cli/v3/i18n" ) var hookGetBinaryPath = func(fn func() (string, error)) func() (string, error) { return fn } func getHomeDir() string { homeDirFromEnv := os.Getenv("MOCK_USER_HOME_DIR") if homeDirFromEnv != "" { os.Mkdir(homeDirFromEnv, os.ModePerm) return homeDirFromEnv } u, err := user.Current() if err != nil { return "" } return u.HomeDir } var uninstallFlag = &Flag{ Name: "uninstall", Short: i18n.T("uninstall auto completion", "卸载自动完成"), } func NewAutoCompleteCommand() *Command { cmd := &Command{ Name: "auto-completion", Short: i18n.T( "enable auto completion", "启用自动完成"), Usage: "auto-completion [--uninstall]", Run: func(ctx *Context, args []string) error { //s, _ := os.Executable() //fmt.Printf("%s \n", s) // //if f := rcFile(".zshrc"); f != "" { // // i = append(i, zshInstaller{f}) // fmt.Printf("zshInstaller: %s\n", f) //} if uninstallFlag.IsAssigned() { uninstallCompletion(ctx, "aliyun") } else { installCompletion(ctx, "aliyun") } return nil }, } cmd.Flags().Add(uninstallFlag) return cmd } func installCompletion(ctx *Context, cmd string) { bin, err := getBinaryPath() if err != nil { Errorf(ctx.Stderr(), "can't get binary path %s", err) return } for _, i := range completionInstallers() { err := i.Install(cmd, bin) if err != nil { Errorf(ctx.Stderr(), "install completion failed for %s %s\n", bin, err) } } } func uninstallCompletion(ctx *Context, cmd string) { bin, err := hookGetBinaryPath(getBinaryPath)() if err != nil { Errorf(ctx.Stderr(), "can't get binary path %s", err) return } for _, i := range completionInstallers() { err := i.Uninstall(cmd, bin) if err != nil { Errorf(ctx.Stderr(), "uninstall %s failed\n", err) } } } func completionInstallers() (i []completionInstaller) { for _, rc := range [...]string{".bashrc", ".bash_profile", ".bash_login", ".profile"} { if f := rcFile(rc); f != "" { i = append(i, bashInstaller{f}) break } } if f := rcFile(".zshrc"); f != "" { i = append(i, zshInstaller{f}) } return } type completionInstaller interface { GetName() string Install(cmd string, bin string) error Uninstall(cmd string, bin string) error } // (un)install in zshInstaller // basically adds/remove from .zshrc: // // autoload -U +X bashcompinit && bashcompinit" // complete -C </path/to/completion/command> <command> type zshInstaller struct { rc string } func (z zshInstaller) GetName() string { return "zsh" } func (z zshInstaller) Install(cmd, bin string) error { completeCmd := z.cmd(cmd, bin) if lineInFile(z.rc, completeCmd) { return fmt.Errorf("already installed in %s", z.rc) } compInit := "autoload -U +X compinit && compinit -i" bashCompInit := "autoload -U +X bashcompinit && bashcompinit -i" if !lineInFile(z.rc, compInit) { if !lineInFile(z.rc, bashCompInit) { completeCmd = compInit + "\n" + bashCompInit + "\n" + completeCmd } else { completeCmd = compInit + "\n" + completeCmd } } return appendToFile(z.rc, completeCmd) } func (z zshInstaller) Uninstall(cmd, bin string) error { completeCmd := z.cmd(cmd, bin) if !lineInFile(z.rc, completeCmd) { return fmt.Errorf("does not installed in %s", z.rc) } return removeFromFile(z.rc, completeCmd) } func (zshInstaller) cmd(cmd, bin string) string { return fmt.Sprintf("complete -o nospace -F %s %s", bin, cmd) } // (un)install in bashInstaller // basically adds/remove from .bashrc: // // complete -C </path/to/completion/command> <command> type bashInstaller struct { rc string } func (b bashInstaller) GetName() string { return "bash" } func (b bashInstaller) Install(cmd, bin string) error { completeCmd := b.cmd(cmd, bin) if lineInFile(b.rc, completeCmd) { return fmt.Errorf("already installed in %s", b.rc) } return appendToFile(b.rc, completeCmd) } func (b bashInstaller) Uninstall(cmd, bin string) error { completeCmd := b.cmd(cmd, bin) if !lineInFile(b.rc, completeCmd) { return fmt.Errorf("does not installed in %s", b.rc) } return removeFromFile(b.rc, completeCmd) } func (bashInstaller) cmd(cmd, bin string) string { return fmt.Sprintf("complete -C %s %s", bin, cmd) }