summaryrefslogtreecommitdiff
path: root/internal/install/install.go
diff options
context:
space:
mode:
authorEyal Posener <[email protected]>2019-11-14 06:51:44 +0200
committerEyal Posener <[email protected]>2019-11-18 01:05:47 +0200
commit8724aaf18312e54750540a9578e00d61b1c545d8 (patch)
treed3e736b4fb279975bbcc017ae1bad53e454c5773 /internal/install/install.go
parent05b68ffc813dd10c420993cb1cf927b346c057b8 (diff)
V2
Diffstat (limited to 'internal/install/install.go')
-rw-r--r--internal/install/install.go176
1 files changed, 176 insertions, 0 deletions
diff --git a/internal/install/install.go b/internal/install/install.go
new file mode 100644
index 0000000..e4c5c0e
--- /dev/null
+++ b/internal/install/install.go
@@ -0,0 +1,176 @@
+package install
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "os/user"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/hashicorp/go-multierror"
+)
+
+func Run(name string, uninstall, yes bool, out io.Writer, in io.Reader) {
+ action := "install"
+ if uninstall {
+ action = "uninstall"
+ }
+ if !yes {
+ fmt.Fprintf(out, "%s completion for %s? ", action, name)
+ var answer string
+ fmt.Fscanln(in, &answer)
+ switch strings.ToLower(answer) {
+ case "y", "yes":
+ default:
+ fmt.Fprintf(out, "Cancelling...")
+ return
+ }
+ }
+ fmt.Fprintf(out, action+"ing...")
+
+ if uninstall {
+ Uninstall(name)
+ } else {
+ Install(name)
+ }
+}
+
+type installer interface {
+ IsInstalled(cmd, bin string) bool
+ Install(cmd, bin string) error
+ Uninstall(cmd, bin string) error
+}
+
+// Install complete command given:
+// cmd: is the command name
+func Install(cmd string) error {
+ is := installers()
+ if len(is) == 0 {
+ return errors.New("Did not find any shells to install")
+ }
+ bin, err := getBinaryPath()
+ if err != nil {
+ return err
+ }
+
+ for _, i := range is {
+ errI := i.Install(cmd, bin)
+ if errI != nil {
+ err = multierror.Append(err, errI)
+ }
+ }
+
+ return err
+}
+
+// IsInstalled returns true if the completion
+// for the given cmd is installed.
+func IsInstalled(cmd string) bool {
+ bin, err := getBinaryPath()
+ if err != nil {
+ return false
+ }
+
+ for _, i := range installers() {
+ installed := i.IsInstalled(cmd, bin)
+ if installed {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Uninstall complete command given:
+// cmd: is the command name
+func Uninstall(cmd string) error {
+ is := installers()
+ if len(is) == 0 {
+ return errors.New("Did not find any shells to uninstall")
+ }
+ bin, err := getBinaryPath()
+ if err != nil {
+ return err
+ }
+
+ for _, i := range is {
+ errI := i.Uninstall(cmd, bin)
+ if errI != nil {
+ err = multierror.Append(err, errI)
+ }
+ }
+
+ return err
+}
+
+func installers() (i []installer) {
+ // The list of bash config files candidates where it is
+ // possible to install the completion command.
+ var bashConfFiles []string
+ switch runtime.GOOS {
+ case "darwin":
+ bashConfFiles = []string{".bash_profile"}
+ default:
+ bashConfFiles = []string{".bashrc", ".bash_profile", ".bash_login", ".profile"}
+ }
+ for _, rc := range bashConfFiles {
+ if f := rcFile(rc); f != "" {
+ i = append(i, bash{f})
+ break
+ }
+ }
+ if f := rcFile(".zshrc"); f != "" {
+ i = append(i, zsh{f})
+ }
+ if d := fishConfigDir(); d != "" {
+ i = append(i, fish{d})
+ }
+ return
+}
+
+func fishConfigDir() string {
+ configDir := filepath.Join(getConfigHomePath(), "fish")
+ if configDir == "" {
+ return ""
+ }
+ if info, err := os.Stat(configDir); err != nil || !info.IsDir() {
+ return ""
+ }
+ return configDir
+}
+
+func getConfigHomePath() string {
+ u, err := user.Current()
+ if err != nil {
+ return ""
+ }
+
+ configHome := os.Getenv("XDG_CONFIG_HOME")
+ if configHome == "" {
+ return filepath.Join(u.HomeDir, ".config")
+ }
+ return configHome
+}
+
+func getBinaryPath() (string, error) {
+ bin, err := os.Executable()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Abs(bin)
+}
+
+func rcFile(name string) string {
+ u, err := user.Current()
+ if err != nil {
+ return ""
+ }
+ path := filepath.Join(u.HomeDir, name)
+ if _, err := os.Stat(path); err != nil {
+ return ""
+ }
+ return path
+}