mirror of
				https://github.com/therootcompany/pathman.git
				synced 2024-11-16 17:09:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			237 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package envpath
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Paths parses the PATH.env file and returns a slice of valid paths
 | |
| func Paths() ([]string, error) {
 | |
| 	home, err := os.UserHomeDir()
 | |
| 	if nil != err {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	home = filepath.ToSlash(home)
 | |
| 
 | |
| 	_, paths, err := getEnv(home, "PATH")
 | |
| 	if nil != err {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// ":" on *nix
 | |
| 	return paths, nil
 | |
| }
 | |
| 
 | |
| // Add adds a path entry to the PATH env file
 | |
| func Add(entry string) (bool, error) {
 | |
| 	home, err := os.UserHomeDir()
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	home = filepath.ToSlash(home)
 | |
| 
 | |
| 	pathentry, err := normalizePathEntry(home, entry)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	err = initializeShells(home)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	fullpath, paths, err := getEnv(home, "PATH")
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	index := IndexOf(paths, pathentry)
 | |
| 	if index >= 0 {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	paths = append(paths, pathentry)
 | |
| 	err = writeEnv(fullpath, paths)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("Wrote " + fullpath)
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| // Remove adds a path entry to the PATH env file
 | |
| func Remove(entry string) (bool, error) {
 | |
| 	home, err := os.UserHomeDir()
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	home = filepath.ToSlash(home)
 | |
| 
 | |
| 	pathentry, err := normalizePathEntry(home, entry)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	err = initializeShells(home)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	fullpath, oldpaths, err := getEnv(home, "PATH")
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	index := IndexOf(oldpaths, pathentry)
 | |
| 	if index < 0 {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	paths := []string{}
 | |
| 	for i := range oldpaths {
 | |
| 		if index != i {
 | |
| 			paths = append(paths, oldpaths[i])
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	err = writeEnv(fullpath, paths)
 | |
| 	if nil != err {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("Wrote " + fullpath)
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| func getEnv(home string, env string) (string, []string, error) {
 | |
| 	envmand := filepath.Join(home, ".config/envman")
 | |
| 	err := os.MkdirAll(envmand, 0755)
 | |
| 	if nil != err {
 | |
| 		return "", nil, err
 | |
| 	}
 | |
| 
 | |
| 	nodes, err := ioutil.ReadDir(envmand)
 | |
| 	if nil != err {
 | |
| 		return "", nil, err
 | |
| 	}
 | |
| 
 | |
| 	//filename := fmt.Sprintf("00-%s.env", env)
 | |
| 	filename := fmt.Sprintf("%s.env", env)
 | |
| 	for i := range nodes {
 | |
| 		name := nodes[i].Name()
 | |
| 		if fmt.Sprintf("%s.env", env) == name || strings.HasSuffix(name, fmt.Sprintf("-%s.env", env)) {
 | |
| 			filename = name
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	fullpath := filepath.Join(envmand, filename)
 | |
| 	f, err := os.OpenFile(fullpath, os.O_CREATE|os.O_RDONLY, 0644)
 | |
| 	if nil != err {
 | |
| 		return "", nil, err
 | |
| 	}
 | |
| 
 | |
| 	b, err := ioutil.ReadAll(f)
 | |
| 	f.Close()
 | |
| 	if nil != err {
 | |
| 		return "", nil, err
 | |
| 	}
 | |
| 
 | |
| 	paths, warnings := Parse(b, env)
 | |
| 	for i := range warnings {
 | |
| 		w := warnings[i]
 | |
| 		fmt.Printf("warning: dropped %q from %s:%d: %s\n", w.Line, filename, w.LineNumber, w.Message)
 | |
| 	}
 | |
| 
 | |
| 	pathlines := []string{}
 | |
| 	for i := range paths {
 | |
| 		pathname := strings.TrimSuffix(paths[i], ":$PATH")
 | |
| 		if strings.HasPrefix(pathname, "$PATH:") {
 | |
| 			fixed := strings.TrimPrefix(pathname, "$PATH:")
 | |
| 			fmt.Fprintf(os.Stderr, "warning: re-arranging $PATH:%s to %s:$PATH\n", fixed, fixed)
 | |
| 			pathname = fixed
 | |
| 		}
 | |
| 		pathlines = append(pathlines, pathname)
 | |
| 	}
 | |
| 
 | |
| 	if len(warnings) > 0 {
 | |
| 		err := writeEnv(fullpath, pathlines)
 | |
| 		if nil != err {
 | |
| 			return "", nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return fullpath, pathlines, nil
 | |
| }
 | |
| 
 | |
| func writeEnv(fullpath string, paths []string) error {
 | |
| 	f, err := os.OpenFile(fullpath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
 | |
| 	if nil != err {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	_, err = f.Write([]byte("# Generated for envman. Do not edit.\n"))
 | |
| 	if nil != err {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	for i := range paths {
 | |
| 		_, err := f.Write([]byte(fmt.Sprintf("export PATH=\"%s:$PATH\"\n", paths[i])))
 | |
| 		if nil != err {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return f.Close()
 | |
| }
 | |
| 
 | |
| // IndexOf searches the given path list for first occurence
 | |
| // of the given path entry and returns the index, or -1
 | |
| func IndexOf(paths []string, p string) int {
 | |
| 	home, err := os.UserHomeDir()
 | |
| 	if nil != err {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 
 | |
| 	p, _ = normalizePathEntry(home, p)
 | |
| 	index := -1
 | |
| 	for i := range paths {
 | |
| 		entry, _ := normalizePathEntry(home, paths[i])
 | |
| 		if p == entry {
 | |
| 			index = i
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	return index
 | |
| }
 | |
| 
 | |
| func normalizePathEntry(home, pathentry string) (string, error) {
 | |
| 	var err error
 | |
| 
 | |
| 	// We add the slashes so that we don't get false matches
 | |
| 	// ex: foo should match foo/bar, but should NOT match foobar
 | |
| 	home, err = filepath.Abs(home)
 | |
| 	if nil != err {
 | |
| 		// I'm not sure how it's possible to get an error with Abs...
 | |
| 		return "", err
 | |
| 	}
 | |
| 	home += "/"
 | |
| 	pathentry, err = filepath.Abs(pathentry)
 | |
| 	if nil != err {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	pathentry += "/"
 | |
| 
 | |
| 	// Next we make the path relative to / or ~/
 | |
| 	// ex: /Users/me/.local/bin/ => .local/bin/
 | |
| 	if strings.HasPrefix(pathentry, home) {
 | |
| 		pathentry = "$HOME/" + strings.TrimPrefix(pathentry, home)
 | |
| 	}
 | |
| 
 | |
| 	return strings.TrimSuffix(pathentry, "/"), nil
 | |
| }
 |