diff --git a/envpath/envpath.go b/envpath/envpath.go index a077842..9ef9f79 100644 --- a/envpath/envpath.go +++ b/envpath/envpath.go @@ -3,12 +3,10 @@ package main import ( "fmt" "io/ioutil" - "math/rand" "os" "path/filepath" "strconv" "strings" - "time" ) // ppsep is used as the replacement for slashes in path @@ -25,7 +23,8 @@ import ( const ppsep = "-" func usage() { - fmt.Fprintf(os.Stderr, "Usage: envpath show|add|append|remove \n") + //fmt.Fprintf(os.Stderr, "Usage: envpath show|add|append|remove \n") + fmt.Fprintf(os.Stderr, "Usage: envpath show|add|remove \n") } func main() { @@ -38,11 +37,7 @@ func main() { } action := os.Args[1] - paths, err := Paths() - if nil != err { - fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(2) - } + paths := Paths() if "show" == action { if len(os.Args) > 2 { @@ -79,16 +74,18 @@ func main() { default: usage() os.Exit(1) - case "append": - newpath, _, err := addPath(pathentry, appendOrder) - if nil != err { - fmt.Fprintf(os.Stderr, "%s\n", err) - return - } - fmt.Println("New sessions will have " + pathentry + " in their PATH.") - fmt.Println("To update this session run\n") - //fmt.Println("\tsource", pathfile) - fmt.Printf(`%sexport PATH="$PATH:%s"%s`, "\t", newpath, "\n") + /* + case "append": + newpath, _, err := addPath(pathentry, appendOrder) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + return + } + fmt.Println("New sessions will have " + pathentry + " in their PATH.") + fmt.Println("To update this session run\n") + //fmt.Println("\tsource", pathfile) + fmt.Printf(`%sexport PATH="$PATH:%s"%s`, "\t", newpath, "\n") + */ case "add": _, pathfile, err := addPath(pathentry, prependOrder) if nil != err { @@ -99,27 +96,19 @@ func main() { fmt.Printf("\tsource %s\n\n", pathfile) //fmt.Printf(`%sexport PATH="%s:$PATH"%s`, "\t", newpath, "\n\n") case "remove": - _, err := removePath(pathentry) + msg, err := removePath(pathentry) if nil != err { fmt.Fprintf(os.Stderr, "%s\n", err) return } + fmt.Println(msg) } - - // TODO support both of these usages: - // 1. export PATH="$(envpath append /opt/whatever/bin)" - // 2. envpath append /opt/whatever/bin - // export PATH="$PATH:/opt/whatever/bin" } // Paths returns the slice of PATHs from the Environment -func Paths() ([]string, error) { +func Paths() []string { // ":" on *nix - return strings.Split(os.Getenv("PATH"), string(os.PathListSeparator)), nil -} - -func init() { - rand.Seed(time.Now().UnixNano()) + return strings.Split(os.Getenv("PATH"), string(os.PathListSeparator)) } type setOrder bool @@ -168,8 +157,12 @@ func addPath(oldpathentry string, order setOrder) (string, string, error) { return "", "", err } - if err := ensureNotInPath(home, pathentry); nil != err { - return "", "", err + if index, ok := isInPath(home, pathentry); ok { + return "", "", fmt.Errorf( + "%q is in your PATH at position %d and must be removed manually to re-order\n", + pathentry, + index, + ) } // ex: 100-opt»foo»bin.sh @@ -189,12 +182,76 @@ func addPath(oldpathentry string, order setOrder) (string, string, error) { return pathentry, fullname, nil } -// TODO don't check in parser before add/append functions actually run -func ensureNotInPath(home, pathentry string) error { - paths, err := Paths() +func removePath(oldpathentry string) (string, error) { + home, err := os.UserHomeDir() if nil != err { - return err + return "", err } + home = filepath.ToSlash(home) + + pathentry, fname, err := normalizeEntryAndFile(home, oldpathentry) + if nil != err { + return "", err + } + + envpathd := filepath.Join(home, ".config/envpath/path.d") + err = os.MkdirAll(envpathd, 0755) + if nil != err { + return "", err + } + + nodes, err := ioutil.ReadDir(envpathd) + if nil != err { + return "", err + } + + var fullname string + for i := range nodes { + node := nodes[i] + // 000-foo-bin.sh vs foo-bin.sh + if strings.HasSuffix(node.Name(), "-"+fname) { + if len(strings.Split(node.Name(), "-"))-1 == len(strings.Split(fname, "-")) { + fullname = node.Name() + } + } + } + + paths := Paths() + index, exists := isInPath(home, pathentry) + + if "" == fullname { + if exists { + return "", fmt.Errorf("%q is in your PATH, but is NOT managed by envpath", pathentry) + } + return "", fmt.Errorf("%q is NOT in your PATH, and NOT managed by envpath", pathentry) + } + + err = os.Remove(filepath.Join(envpathd, fullname)) + if nil != err { + return "", err + } + + if !exists { + return fmt.Sprintf("Removed %s", filepath.Join(envpathd, fullname)), nil + } + + newpaths := []string{} + for i := range paths { + if i == index { + continue + } + newpaths = append(newpaths, paths[i]) + } + return fmt.Sprintf( + "Removed %s. To update the current shell re-export the new PATH:\n\n"+ + "\texport PATH=%q\n", + fullname, + strings.Join(newpaths, ":"), + ), nil +} + +func isInPath(home, pathentry string) (int, bool) { + paths := Paths() index := -1 for i := range paths { @@ -205,15 +262,9 @@ func ensureNotInPath(home, pathentry string) error { } } if index >= 0 { - fmt.Fprintf( - os.Stderr, - "%q is in your PATH at position %d and must be removed manually to re-order\n", - pathentry, - index, - ) - os.Exit(3) + return index, true } - return nil + return -1, false } func normalizeEntryAndFile(home, pathentry string) (string, string, error) { @@ -321,59 +372,3 @@ func getOrder(nodes []os.FileInfo, pathentry, fname, envpathd string, fn sorter) return priority, nil } - -func removePath(oldpathentry string) (string, error) { - // TODO Show current PATH sans this item - /* - oldpaths := paths - paths = []string{} - for i := range oldpaths { - if i != index { - paths = append(paths, oldpaths[i]) - } - } - */ - - home, err := os.UserHomeDir() - if nil != err { - return "", err - } - home = filepath.ToSlash(home) - - pathentry, fname, err := normalizeEntryAndFile(home, oldpathentry) - if nil != err { - return "", err - } - - envpathd := filepath.Join(home, ".config/envpath/path.d") - err = os.MkdirAll(envpathd, 0755) - if nil != err { - return "", err - } - - /* - err = ensureNotInPath(home, pathentry) - if nil != err { - return "", err - } - */ - - nodes, err := ioutil.ReadDir(envpathd) - if nil != err { - return "", err - } - - // TODO rename getOrder to getNext - _, err = getOrder(nodes, pathentry, fname, envpathd, sortForward) - if nil == err { - fmt.Fprintf(os.Stderr, "%q is not managed by envpath.\n", pathentry) - } - - /* - if index < 0 { - fmt.Fprintf(os.Stderr, "%q is NOT in PATH.\n", pathentry) - os.Exit(3) - } - */ - return "", nil -}