From 5db452a63f1b8ff0319f08986a4a04324647738f Mon Sep 17 00:00:00 2001 From: Eyal Posener Date: Mon, 8 May 2017 07:32:13 +0300 Subject: Install fixups - remove root installation - install according to shell type Closes #7 --- cmd/cmd.go | 15 ++--- cmd/install/bash.go | 153 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd/install/home.go | 152 ------------------------------------------------ cmd/install/install.go | 45 +++++++++++---- cmd/install/root.go | 29 ---------- 5 files changed, 191 insertions(+), 203 deletions(-) create mode 100644 cmd/install/bash.go delete mode 100644 cmd/install/home.go delete mode 100644 cmd/install/root.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 8149aac..d0b341c 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -27,9 +27,9 @@ func Run(cmd string) { } fmt.Println(c.action() + "ing...") if c.install { - err = install.Install(cmd, c.root) + err = install.Install(cmd) } else { - err = install.Uninstall(cmd, c.root) + err = install.Uninstall(cmd) } if err != nil { fmt.Printf("%s failed! %s\n", c.action(), err) @@ -40,7 +40,7 @@ func Run(cmd string) { // prompt use for approval func prompt(action, cmd string) bool { - fmt.Printf("%s bash completion for %s? ", action, cmd) + fmt.Printf("%s completion for %s? ", action, cmd) var answer string fmt.Scanln(&answer) @@ -56,7 +56,6 @@ func prompt(action, cmd string) bool { type config struct { install bool uninstall bool - root bool yes bool } @@ -64,13 +63,9 @@ type config struct { func parseFlags(cmd string) config { var c config flag.BoolVar(&c.install, "install", false, - fmt.Sprintf("Install bash completion for %s command", cmd)) + fmt.Sprintf("Install completion for %s command", cmd)) flag.BoolVar(&c.uninstall, "uninstall", false, - fmt.Sprintf("Uninstall bash completion for %s command", cmd)) - flag.BoolVar(&c.root, "root", false, - "(Un)Install as root:\n"+ - " (Un)Install at /etc/bash_completion.d/ (user should have write permissions to that directory).\n"+ - " If not set, a complete command will be added(removed) to ~/.bashrc") + fmt.Sprintf("Uninstall completion for %s command", cmd)) flag.BoolVar(&c.yes, "y", false, "Don't prompt user for typing 'yes'") flag.Parse() return c diff --git a/cmd/install/bash.go b/cmd/install/bash.go new file mode 100644 index 0000000..c8bff49 --- /dev/null +++ b/cmd/install/bash.go @@ -0,0 +1,153 @@ +package install + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/user" + "path/filepath" +) + +type bash struct{} + +func (bash) Install(cmd, bin string) error { + bashRCFileName, err := bashRCFileName() + if err != nil { + return err + } + completeCmd := completeCmd(cmd, bin) + if isInFile(bashRCFileName, completeCmd) { + return errors.New("Already installed in ~/.bashrc") + } + + bashRC, err := os.OpenFile(bashRCFileName, os.O_RDWR|os.O_APPEND, 0) + if err != nil { + return err + } + defer bashRC.Close() + _, err = bashRC.WriteString(fmt.Sprintf("\n%s\n", completeCmd)) + return err +} + +func (bash) Uninstall(cmd, bin string) error { + bashRC, err := bashRCFileName() + if err != nil { + return err + } + backup := bashRC + ".bck" + err = copyFile(bashRC, backup) + if err != nil { + return err + } + completeCmd := completeCmd(cmd, bin) + if !isInFile(bashRC, completeCmd) { + return errors.New("Does not installed in ~/.bashrc") + } + temp, err := uninstallToTemp(bashRC, completeCmd) + if err != nil { + return err + } + + err = copyFile(temp, bashRC) + if err != nil { + return err + } + + return os.Remove(backup) + +} + +func completeCmd(cmd, bin string) string { + return fmt.Sprintf("complete -C %s %s", bin, cmd) +} + +func bashRCFileName() (string, error) { + u, err := user.Current() + if err != nil { + return "", err + } + return filepath.Join(u.HomeDir, ".bashrc"), nil +} + +func isInFile(name string, lookFor string) bool { + f, err := os.Open(name) + if err != nil { + return false + } + defer f.Close() + r := bufio.NewReader(f) + prefix := []byte{} + for { + line, isPrefix, err := r.ReadLine() + if err == io.EOF { + return false + } + if err != nil { + return false + } + if isPrefix { + prefix = append(prefix, line...) + continue + } + line = append(prefix, line...) + if string(line) == lookFor { + return true + } + prefix = prefix[:0] + } +} + +func uninstallToTemp(bashRCFileName, completeCmd string) (string, error) { + rf, err := os.Open(bashRCFileName) + if err != nil { + return "", err + } + defer rf.Close() + wf, err := ioutil.TempFile("/tmp", "bashrc-") + if err != nil { + return "", err + } + defer wf.Close() + + r := bufio.NewReader(rf) + prefix := []byte{} + for { + line, isPrefix, err := r.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return "", err + } + if isPrefix { + prefix = append(prefix, line...) + continue + } + line = append(prefix, line...) + str := string(line) + if str == completeCmd { + continue + } + wf.WriteString(str + "\n") + prefix = prefix[:0] + } + return wf.Name(), nil +} + +func copyFile(src string, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() + _, err = io.Copy(out, in) + return err +} diff --git a/cmd/install/home.go b/cmd/install/home.go deleted file mode 100644 index 2694e96..0000000 --- a/cmd/install/home.go +++ /dev/null @@ -1,152 +0,0 @@ -package install - -import ( - "bufio" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/user" - "path/filepath" -) - -type home struct{} - -func (home) Install(cmd, bin string) error { - bashRCFileName, err := bashRCFileName() - if err != nil { - return err - } - completeCmd := completeCmd(cmd, bin) - if isInFile(bashRCFileName, completeCmd) { - return errors.New("Already installed in ~/.bashrc") - } - - bashRC, err := os.OpenFile(bashRCFileName, os.O_RDWR|os.O_APPEND, 0) - if err != nil { - return err - } - defer bashRC.Close() - _, err = bashRC.WriteString(fmt.Sprintf("\n%s\n", completeCmd)) - return err -} - -func (home) Uninstall(cmd, bin string) error { - bashRC, err := bashRCFileName() - if err != nil { - return err - } - backup := bashRC + ".bck" - err = copyFile(bashRC, backup) - if err != nil { - return err - } - completeCmd := completeCmd(cmd, bin) - if !isInFile(bashRC, completeCmd) { - return errors.New("Does not installed in ~/.bashrc") - } - temp, err := uninstallToTemp(bashRC, completeCmd) - if err != nil { - return err - } - - err = copyFile(temp, bashRC) - if err != nil { - return err - } - - return os.Remove(backup) -} - -func completeCmd(cmd, bin string) string { - return fmt.Sprintf("complete -C %s %s", bin, cmd) -} - -func bashRCFileName() (string, error) { - u, err := user.Current() - if err != nil { - return "", err - } - return filepath.Join(u.HomeDir, ".bashrc"), nil -} - -func isInFile(name string, lookFor string) bool { - f, err := os.Open(name) - if err != nil { - return false - } - defer f.Close() - r := bufio.NewReader(f) - prefix := []byte{} - for { - line, isPrefix, err := r.ReadLine() - if err == io.EOF { - return false - } - if err != nil { - return false - } - if isPrefix { - prefix = append(prefix, line...) - continue - } - line = append(prefix, line...) - if string(line) == lookFor { - return true - } - prefix = prefix[:0] - } -} - -func uninstallToTemp(bashRCFileName, completeCmd string) (string, error) { - rf, err := os.Open(bashRCFileName) - if err != nil { - return "", err - } - defer rf.Close() - wf, err := ioutil.TempFile("/tmp", "bashrc-") - if err != nil { - return "", err - } - defer wf.Close() - - r := bufio.NewReader(rf) - prefix := []byte{} - for { - line, isPrefix, err := r.ReadLine() - if err == io.EOF { - break - } - if err != nil { - return "", err - } - if isPrefix { - prefix = append(prefix, line...) - continue - } - line = append(prefix, line...) - str := string(line) - if str == completeCmd { - continue - } - wf.WriteString(str + "\n") - prefix = prefix[:0] - } - return wf.Name(), nil -} - -func copyFile(src string, dst string) error { - in, err := os.Open(src) - if err != nil { - return err - } - defer in.Close() - out, err := os.Create(dst) - if err != nil { - return err - } - defer out.Close() - _, err = io.Copy(out, in) - return err -} diff --git a/cmd/install/install.go b/cmd/install/install.go index c20e11a..bb44ad8 100644 --- a/cmd/install/install.go +++ b/cmd/install/install.go @@ -1,6 +1,8 @@ package install import ( + "errors" + "fmt" "os" "path/filepath" ) @@ -12,33 +14,47 @@ type installer interface { // Install complete command given: // cmd: is the command name -// asRoot: if true the completion will be installed in /etc/bash_complete.d -// otherwise the complete command will be added to the ~/.bashrc file. -func Install(cmd string, asRoot bool) error { +func Install(cmd string) error { + shell := shellType() + if shell == "" { + return errors.New("must install through a terminatl") + } + i := getInstaller(shell) + if i == nil { + return fmt.Errorf("shell %s not supported", shell) + } bin, err := getBinaryPath() if err != nil { return err } - return getInstaller(asRoot).Install(cmd, bin) + return i.Install(cmd, bin) } // Uninstall complete command given: // cmd: is the command name -// asRoot: if true the completion will be removed from /etc/bash_complete.d -// otherwise the complete command will be removed from the ~/.bashrc file. -func Uninstall(cmd string, asRoot bool) error { +func Uninstall(cmd string) error { + shell := shellType() + if shell == "" { + return errors.New("must uninstall through a terminatl") + } + i := getInstaller(shell) + if i == nil { + return fmt.Errorf("shell %s not supported", shell) + } bin, err := getBinaryPath() if err != nil { return err } - return getInstaller(asRoot).Uninstall(cmd, bin) + return i.Uninstall(cmd, bin) } -func getInstaller(asRoot bool) installer { - if asRoot { - return root{} +func getInstaller(shell string) installer { + switch shell { + case "bash": + return bash{} + default: + return nil } - return home{} } func getBinaryPath() (string, error) { @@ -48,3 +64,8 @@ func getBinaryPath() (string, error) { } return filepath.Abs(bin) } + +func shellType() string { + shell := os.Getenv("SHELL") + return filepath.Base(shell) +} diff --git a/cmd/install/root.go b/cmd/install/root.go deleted file mode 100644 index 66e23b3..0000000 --- a/cmd/install/root.go +++ /dev/null @@ -1,29 +0,0 @@ -package install - -import "os" - -type root struct{} - -func (r root) Install(cmd string, bin string) error { - completeLink := getBashCompletionDLink(cmd) - err := r.Uninstall(cmd, bin) - if err != nil { - return err - } - return os.Symlink(bin, completeLink) -} - -func (root) Uninstall(cmd string, bin string) error { - completeLink := getBashCompletionDLink(cmd) - if _, err := os.Stat(completeLink); err == nil { - err := os.Remove(completeLink) - if err != nil { - return err - } - } - return nil -} - -func getBashCompletionDLink(cmd string) string { - return "/etc/bash_completion.d/" + cmd -} -- cgit v1.2.3