mirror of
				https://github.com/therootcompany/pathman.git
				synced 2024-11-16 17:09:01 +00:00 
			
		
		
		
	v0.5.0: initial publishable version
This commit is contained in:
		
							parent
							
								
									9254e307e3
								
							
						
					
					
						commit
						8a699044be
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,6 @@ | |||||||
|  | /pathman | ||||||
|  | dist | ||||||
|  | 
 | ||||||
| # ---> Go | # ---> Go | ||||||
| # Binaries for programs and plugins | # Binaries for programs and plugins | ||||||
| *.exe | *.exe | ||||||
|  | |||||||
							
								
								
									
										81
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								README.md
									
									
									
									
									
								
							| @ -1,3 +1,82 @@ | |||||||
| # go-envpath | # [pathman](https://git.rootprojects.org/root/pathman) | ||||||
| 
 | 
 | ||||||
| Manage PATH on Windows, Mac, and Linux with various Shells | Manage PATH on Windows, Mac, and Linux with various Shells | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pathman list | ||||||
|  | pathman add ~/.local/bin | ||||||
|  | pathman remove ~/.local/bin | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Windows: stores PATH in the registry. | ||||||
|  | 
 | ||||||
|  | Mac & Linux: stores PATH in `~/.config/envman/PATH.sh` | ||||||
|  | 
 | ||||||
|  | # add | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pathman add ~/.local/bin | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```txt | ||||||
|  | Saved PATH changes. To set the PATH immediately, update the current session: | ||||||
|  | 
 | ||||||
|  | 	export PATH="/Users/me/.local/bin:$PATH" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # remove | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pathman remove ~/.local/bin | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```txt | ||||||
|  | Saved PATH changes. To set the PATH immediately, update the current session: | ||||||
|  | 
 | ||||||
|  | 	export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # list | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pathman list | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```txt | ||||||
|  | pathman-managed PATH entries: | ||||||
|  | 
 | ||||||
|  | 	$HOME/.local/bin | ||||||
|  | 
 | ||||||
|  | other PATH entries: | ||||||
|  | 
 | ||||||
|  | 	/usr/local/bin | ||||||
|  | 	/usr/bin | ||||||
|  | 	/bin | ||||||
|  | 	/usr/sbin | ||||||
|  | 	/sbin | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Windows | ||||||
|  | 
 | ||||||
|  | You can use `~` as a shortcut for `%USERPROFILE%`. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pathman add ~\.local\bin | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The registry will be used, even when your using Node Bash, Git Bash, or MINGW. | ||||||
|  | 
 | ||||||
|  | # build | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git clone https://git.rootprojects.org/root/pathman.git | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | go mod tidy | ||||||
|  | go mod vendor | ||||||
|  | go generate -mod=vendor ./... | ||||||
|  | go build -mod=vendor | ||||||
|  | ./pathman list | ||||||
|  | ``` | ||||||
|  | |||||||
							
								
								
									
										43
									
								
								build-all.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								build-all.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #GOOS=windows GOARCH=amd64 go install | ||||||
|  | #go tool dist list | ||||||
|  | 
 | ||||||
|  | # TODO move this into tools/build.go | ||||||
|  | 
 | ||||||
|  | export CGO_ENABLED=0 | ||||||
|  | exe=pathman | ||||||
|  | gocmd=. | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | go generate -mod=vendor ./... | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Windows amd64" | ||||||
|  | GOOS=windows GOARCH=amd64 go build -mod=vendor -o dist/windows/amd64/${exe}.exe -ldflags "-s -w -H=windowsgui" $gocmd | ||||||
|  | GOOS=windows GOARCH=amd64 go build -mod=vendor -o dist/windows/amd64/${exe}.debug.exe | ||||||
|  | echo "Windows 386" | ||||||
|  | GOOS=windows GOARCH=386 go build -mod=vendor -o dist/windows/386/${exe}.exe -ldflags "-s -w -H=windowsgui" $gocmd | ||||||
|  | GOOS=windows GOARCH=386 go build -mod=vendor -o dist/windows/386/${exe}.debug.exe | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Darwin (macOS) amd64" | ||||||
|  | GOOS=darwin GOARCH=amd64 go build -mod=vendor -o dist/darwin/amd64/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Linux amd64" | ||||||
|  | GOOS=linux GOARCH=amd64 go build -mod=vendor -o dist/linux/amd64/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | echo "Linux 386" | ||||||
|  | GOOS=linux GOARCH=386 go build -mod=vendor -o dist/linux/386/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "RPi 4 (64-bit) ARMv8" | ||||||
|  | GOOS=linux GOARCH=arm64 go build -mod=vendor -o dist/linux/armv8/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | echo "RPi 3 B+ ARMv7" | ||||||
|  | GOOS=linux GOARCH=arm GOARM=7 go build -mod=vendor -o dist/linux/armv7/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | echo "ARMv6" | ||||||
|  | GOOS=linux GOARCH=arm GOARM=6 go build -mod=vendor -o dist/linux/armv6/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | echo "RPi Zero ARMv5" | ||||||
|  | GOOS=linux GOARCH=arm GOARM=5 go build -mod=vendor -o dist/linux/armv5/${exe} -ldflags "-s -w" $gocmd | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | #rsync -av ./dist/ ubuntu@rootprojects.org:/srv/www/rootprojects.org/pathman/dist/ | ||||||
|  | # https://rootprojects.org/pathman/dist/windows/amd64/pathman.exe | ||||||
| @ -48,12 +48,12 @@ func Add(entry string) (bool, error) { | |||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, ok := isInPath(home, paths, pathentry) | 	index := IndexOf(paths, pathentry) | ||||||
| 	if ok { | 	if index >= 0 { | ||||||
| 		return false, nil | 		return false, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	paths = append([]string{pathentry}, paths...) | 	paths = append(paths, pathentry) | ||||||
| 	err = writeEnv(fullpath, paths) | 	err = writeEnv(fullpath, paths) | ||||||
| 	if nil != err { | 	if nil != err { | ||||||
| 		return false, err | 		return false, err | ||||||
| @ -86,8 +86,8 @@ func Remove(entry string) (bool, error) { | |||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	index, exists := isInPath(home, oldpaths, pathentry) | 	index := IndexOf(oldpaths, pathentry) | ||||||
| 	if !exists { | 	if index < 0 { | ||||||
| 		return false, nil | 		return false, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -119,7 +119,8 @@ func getEnv(home string, env string) (string, []string, error) { | |||||||
| 		return "", nil, err | 		return "", nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	filename := fmt.Sprintf("00-%s.env", env) | 	//filename := fmt.Sprintf("00-%s.env", env) | ||||||
|  | 	filename := fmt.Sprintf("%s.env", env) | ||||||
| 	for i := range nodes { | 	for i := range nodes { | ||||||
| 		name := nodes[i].Name() | 		name := nodes[i].Name() | ||||||
| 		if fmt.Sprintf("%s.env", env) == name || strings.HasSuffix(name, fmt.Sprintf("-%s.env", env)) { | 		if fmt.Sprintf("%s.env", env) == name || strings.HasSuffix(name, fmt.Sprintf("-%s.env", env)) { | ||||||
| @ -188,19 +189,24 @@ func writeEnv(fullpath string, paths []string) error { | |||||||
| 	return f.Close() | 	return f.Close() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isInPath(home string, paths []string, pathentry string) (int, bool) { | // 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 | 	index := -1 | ||||||
| 	for i := range paths { | 	for i := range paths { | ||||||
| 		entry, _ := normalizePathEntry(home, paths[i]) | 		entry, _ := normalizePathEntry(home, paths[i]) | ||||||
| 		if pathentry == entry { | 		if p == entry { | ||||||
| 			index = i | 			index = i | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if index >= 0 { | 	return index | ||||||
| 		return index, true |  | ||||||
| 	} |  | ||||||
| 	return -1, false |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func normalizePathEntry(home, pathentry string) (string, error) { | func normalizePathEntry(home, pathentry string) (string, error) { | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ package envpath | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -11,9 +13,6 @@ func TestAddRemove(t *testing.T) { | |||||||
| 		t.Error(err) | 		t.Error(err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	for i := range paths { |  | ||||||
| 		fmt.Println(paths[i]) |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	modified, err := Remove("/tmp/doesnt/exist") | 	modified, err := Remove("/tmp/doesnt/exist") | ||||||
| 	if nil != err { | 	if nil != err { | ||||||
| @ -35,10 +34,16 @@ func TestAddRemove(t *testing.T) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	var exists bool | ||||||
| 	paths, err = Paths() | 	paths, err = Paths() | ||||||
| 	if 1 != len(paths) || "/tmp/delete/me" != paths[0] { | 	for i := range paths { | ||||||
|  | 		if "/tmp/delete/me" == paths[i] { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if !exists { | ||||||
| 		fmt.Println("len(paths):", len(paths)) | 		fmt.Println("len(paths):", len(paths)) | ||||||
| 		t.Error(fmt.Errorf("Paths: should have had exactly one entry: /tmp/delete/me")) | 		t.Error(fmt.Errorf("Paths: should have had the entry: /tmp/delete/me")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -52,9 +57,16 @@ func TestAddRemove(t *testing.T) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	exists = false | ||||||
| 	paths, err = Paths() | 	paths, err = Paths() | ||||||
| 	if 1 != len(paths) || "/tmp/delete/me" != paths[0] { | 	for i := range paths { | ||||||
| 		t.Error(fmt.Errorf("Paths: should have had exactly one entry: /tmp/delete/me")) | 		if "/tmp/delete/me" == paths[i] { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if !exists { | ||||||
|  | 		fmt.Println("len(paths):", len(paths)) | ||||||
|  | 		t.Error(fmt.Errorf("Paths: should have had the entry: /tmp/delete/me")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -78,9 +90,16 @@ func TestAddRemove(t *testing.T) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	exists = false | ||||||
| 	paths, err = Paths() | 	paths, err = Paths() | ||||||
| 	if 0 != len(paths) { | 	for i := range paths { | ||||||
| 		t.Error(fmt.Errorf("Paths: should have had no entries")) | 		if "/tmp/delete/me" == paths[i] { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if exists { | ||||||
|  | 		fmt.Println("len(paths):", len(paths)) | ||||||
|  | 		t.Error(fmt.Errorf("Paths: should not have had the entry: /tmp/delete/me")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -94,3 +113,73 @@ func TestAddRemove(t *testing.T) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestHome(t *testing.T) { | ||||||
|  | 	home, _ := os.UserHomeDir() | ||||||
|  | 
 | ||||||
|  | 	modified, err := Add(filepath.Join(home, "deleteme")) | ||||||
|  | 	if nil != err { | ||||||
|  | 		t.Error(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !modified { | ||||||
|  | 		t.Error(fmt.Errorf("Add $HOME/deleteme: should have modified")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	modified, err = Add(filepath.Join(home, "deleteme")) | ||||||
|  | 	if nil != err { | ||||||
|  | 		t.Error(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if modified { | ||||||
|  | 		t.Error(fmt.Errorf("Add $HOME/deleteme: should not have modified")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	exists := false | ||||||
|  | 	paths, err := Paths() | ||||||
|  | 	for i := range paths { | ||||||
|  | 		if "$HOME/deleteme" == paths[i] { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if !exists { | ||||||
|  | 		fmt.Println("len(paths):", len(paths)) | ||||||
|  | 		t.Error(fmt.Errorf("Paths: should have had the entry: $HOME/deleteme")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	modified, err = Remove(filepath.Join(home, "deleteme")) | ||||||
|  | 	if nil != err { | ||||||
|  | 		t.Error(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !modified { | ||||||
|  | 		t.Error(fmt.Errorf("Remove $HOME/deleteme: should have modified")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	exists = false | ||||||
|  | 	paths, err = Paths() | ||||||
|  | 	for i := range paths { | ||||||
|  | 		if "$HOME/deleteme" == paths[i] { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if exists { | ||||||
|  | 		fmt.Println("len(paths):", len(paths)) | ||||||
|  | 		t.Error(fmt.Errorf("Paths: should not have had the entry: $HOME/deleteme")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	modified, err = Remove(filepath.Join(home, "deleteme")) | ||||||
|  | 	if nil != err { | ||||||
|  | 		t.Error(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if modified { | ||||||
|  | 		t.Error(fmt.Errorf("Remove $HOME/deleteme: should not have modified")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ func initializeShells(home string) error { | |||||||
| 	for i := range confs { | 	for i := range confs { | ||||||
| 		c := confs[i] | 		c := confs[i] | ||||||
| 
 | 
 | ||||||
| 		if os.Getenv("SHELL") == c.shell { | 		if filepath.Base(os.Getenv("SHELL")) == c.shell { | ||||||
| 			nativeMatch = c | 			nativeMatch = c | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| @ -181,7 +181,7 @@ func (c *envConfig) initializeShell() (bool, error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Generate our script | 	// Generate our script | ||||||
| 	script := fmt.Sprintf("# Generated for envpath. Do not edit.\n%s\n", c.rcScript) | 	script := fmt.Sprintf("# Generated for envman. Do not edit.\n%s\n", c.rcScript) | ||||||
| 
 | 
 | ||||||
| 	// If there's not a newline before our template, | 	// If there's not a newline before our template, | ||||||
| 	// include it in the template. We want nice things. | 	// include it in the template. We want nice things. | ||||||
| @ -212,7 +212,7 @@ func (c *envConfig) ensurePathsLoader() error { | |||||||
| 		// TODO maybe don't write every time | 		// TODO maybe don't write every time | ||||||
| 		if err := ioutil.WriteFile( | 		if err := ioutil.WriteFile( | ||||||
| 			loadFile, | 			loadFile, | ||||||
| 			[]byte(fmt.Sprintf("# Generated for envpath. Do not edit.\n%s\n", c.loadScript)), | 			[]byte(fmt.Sprintf("# Generated for envman. Do not edit.\n%s\n", c.loadScript)), | ||||||
| 			os.FileMode(0755), | 			os.FileMode(0755), | ||||||
| 		); nil != err { | 		); nil != err { | ||||||
| 			return err | 			return err | ||||||
|  | |||||||
| @ -35,17 +35,16 @@ PATH="" | |||||||
| 
 | 
 | ||||||
| ` | ` | ||||||
| 
 | 
 | ||||||
| var paths = []string{ |  | ||||||
| 	`PATH="/foo"`, |  | ||||||
| 	`PATH="/foo:$PATH"`, |  | ||||||
| 	`PATH=""`, |  | ||||||
| 	`PATH="/boo:$PATH"`, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestParse(t *testing.T) { | func TestParse(t *testing.T) { | ||||||
|  | 	exppaths := []string{ | ||||||
|  | 		`PATH="/foo"`, | ||||||
|  | 		`PATH="/foo:$PATH"`, | ||||||
|  | 		`PATH=""`, | ||||||
|  | 		`PATH="/boo:$PATH"`, | ||||||
|  | 	} | ||||||
| 	newlines, warnings := Parse([]byte(file), "PATH") | 	newlines, warnings := Parse([]byte(file), "PATH") | ||||||
| 	newfile := `PATH="` + strings.Join(newlines, "\"\n\tPATH=\"") + `"` | 	newfile := `PATH="` + strings.Join(newlines, "\"\n\tPATH=\"") + `"` | ||||||
| 	expfile := strings.Join(paths, "\n\t") | 	expfile := strings.Join(exppaths, "\n\t") | ||||||
| 	if newfile != expfile { | 	if newfile != expfile { | ||||||
| 		t.Errorf("\nExpected:\n\t%s\nGot:\n\t%s", expfile, newfile) | 		t.Errorf("\nExpected:\n\t%s\nGot:\n\t%s", expfile, newfile) | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @ -2,4 +2,7 @@ module git.rootprojects.org/root/pathman | |||||||
| 
 | 
 | ||||||
| go 1.12 | go 1.12 | ||||||
| 
 | 
 | ||||||
| require golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 | require ( | ||||||
|  | 	git.rootprojects.org/root/go-gitver v1.1.3 | ||||||
|  | 	golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 | ||||||
|  | ) | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | git.rootprojects.org/root/go-gitver v1.1.3 h1:/qR9z53vY+IFhWRxLkF9cjaiWh8xRJIm6gyuW+MG81A= | ||||||
|  | git.rootprojects.org/root/go-gitver v1.1.3/go.mod h1:Rj1v3TBhvdaSphFEqMynUYwAz/4f+wY/+syBTvRrmlI= | ||||||
|  | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI= | ||||||
|  | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
							
								
								
									
										58
									
								
								pathman.go
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								pathman.go
									
									
									
									
									
								
							| @ -5,13 +5,24 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // GitRev is the git commit hash of the build | ||||||
|  | var GitRev = "000000000" | ||||||
|  | 
 | ||||||
|  | // GitVersion is the git description converted to semver | ||||||
|  | var GitVersion = "v0.5.2-pre+dirty" | ||||||
|  | 
 | ||||||
|  | // GitTimestamp is the timestamp of the latest commit | ||||||
|  | var GitTimestamp = time.Now().Format(time.RFC3339) | ||||||
|  | 
 | ||||||
| func usage() { | func usage() { | ||||||
| 	fmt.Fprintf(os.Stdout, "Usage: envpath <action> [path]\n") | 	fmt.Fprintf(os.Stdout, "Usage: pathman <action> [path]\n") | ||||||
| 	fmt.Fprintf(os.Stdout, "\tex: envpath list\n") | 	fmt.Fprintf(os.Stdout, "\tex: pathman list\n") | ||||||
| 	fmt.Fprintf(os.Stdout, "\tex: envpath add ~/.local/bin\n") | 	fmt.Fprintf(os.Stdout, "\tex: pathman add ~/.local/bin\n") | ||||||
| 	fmt.Fprintf(os.Stdout, "\tex: envpath remove ~/.local/bin\n") | 	fmt.Fprintf(os.Stdout, "\tex: pathman remove ~/.local/bin\n") | ||||||
|  | 	fmt.Fprintf(os.Stdout, "\tex: pathman version\n") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| @ -29,7 +40,7 @@ func main() { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	action = os.Args[1] | 	action = os.Args[1] | ||||||
| 	if 2 == len(os.Args) { | 	if 3 == len(os.Args) { | ||||||
| 		entry = os.Args[2] | 		entry = os.Args[2] | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -37,6 +48,7 @@ func main() { | |||||||
| 	// https://github.com/rust-lang-nursery/rustup.rs/issues/686#issuecomment-253982841 | 	// https://github.com/rust-lang-nursery/rustup.rs/issues/686#issuecomment-253982841 | ||||||
| 	// exec source $HOME/.profile | 	// exec source $HOME/.profile | ||||||
| 	shell := os.Getenv("SHELL") | 	shell := os.Getenv("SHELL") | ||||||
|  | 	shell = filepath.Base(shell) | ||||||
| 	switch shell { | 	switch shell { | ||||||
| 	case "": | 	case "": | ||||||
| 		if strings.HasSuffix(os.Getenv("COMSPEC"), "/cmd.exe") { | 		if strings.HasSuffix(os.Getenv("COMSPEC"), "/cmd.exe") { | ||||||
| @ -52,15 +64,27 @@ func main() { | |||||||
| 		// warn and try anyway | 		// warn and try anyway | ||||||
| 		fmt.Fprintf( | 		fmt.Fprintf( | ||||||
| 			os.Stderr, | 			os.Stderr, | ||||||
| 			"%q isn't a recognized shell. Please open an issue at https://git.rootprojects.org/envpath/issues?q=%s", | 			"%q isn't a recognized shell. Please open an issue at https://git.rootprojects.org/root/pathman/issues?q=%s", | ||||||
| 			shell, | 			shell, | ||||||
| 			shell, | 			shell, | ||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	home, _ := os.UserHomeDir() | ||||||
|  | 	if "" != entry && '~' == entry[0] { | ||||||
|  | 		// Let windows users not to have to type %USERPROFILE% or \Users\me every time | ||||||
|  | 		entry = strings.Replace(entry, "~", home, 0) | ||||||
|  | 	} | ||||||
| 	switch action { | 	switch action { | ||||||
|  | 	default: | ||||||
|  | 		usage() | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	case "version": | ||||||
|  | 		fmt.Printf("pathman %s (%s) %s\n", GitVersion, GitRev, GitTimestamp) | ||||||
|  | 		os.Exit(0) | ||||||
|  | 		return | ||||||
| 	case "list": | 	case "list": | ||||||
| 		if 2 == len(os.Args) { | 		if 2 != len(os.Args) { | ||||||
| 			usage() | 			usage() | ||||||
| 			os.Exit(1) | 			os.Exit(1) | ||||||
| 		} | 		} | ||||||
| @ -91,18 +115,24 @@ func list() { | |||||||
| 	fmt.Println("other PATH entries:\n") | 	fmt.Println("other PATH entries:\n") | ||||||
| 	// All managed paths | 	// All managed paths | ||||||
| 	pathsmap := map[string]bool{} | 	pathsmap := map[string]bool{} | ||||||
|  | 	home, _ := os.UserHomeDir() | ||||||
| 	for i := range managedpaths { | 	for i := range managedpaths { | ||||||
| 		// TODO normalize |  | ||||||
| 		pathsmap[managedpaths[i]] = true | 		pathsmap[managedpaths[i]] = true | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Paths in the environment which are not managed | 	// Paths in the environment which are not managed | ||||||
| 	var hasExtras bool | 	var hasExtras bool | ||||||
| 	envpaths := Paths() | 	paths := Paths() | ||||||
| 	for i := range envpaths { | 	for i := range paths { | ||||||
| 		// TODO normalize | 		// TODO normalize | ||||||
| 		path := envpaths[i] | 		path := paths[i] | ||||||
| 		if !pathsmap[path] { | 		path1 := "" | ||||||
|  | 		path2 := "" | ||||||
|  | 		if strings.HasPrefix(path, home) { | ||||||
|  | 			path1 = "$HOME" + strings.TrimPrefix(path, home) | ||||||
|  | 			path2 = "%USERPROFILE%" + strings.TrimPrefix(path, home) | ||||||
|  | 		} | ||||||
|  | 		if !pathsmap[path] && !pathsmap[path1] && !pathsmap[path2] { | ||||||
| 			hasExtras = true | 			hasExtras = true | ||||||
| 			fmt.Println("\t" + path) | 			fmt.Println("\t" + path) | ||||||
| 		} | 		} | ||||||
| @ -185,7 +215,7 @@ func remove(entry string) { | |||||||
| 			fmt.Fprintf(os.Stderr, "%s", err) | 			fmt.Fprintf(os.Stderr, "%s", err) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		msg += " To set the PATH immediately, update the current session:\n\n\t" + Remove(entry) + "\n" | 		msg += " To set the PATH immediately, update the current session:\n\n\t" + Remove(newpaths) + "\n" | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fmt.Println(msg + "\n") | 	fmt.Println(msg + "\n") | ||||||
| @ -224,6 +254,6 @@ func Remove(entries []string) string { | |||||||
| 	return fmt.Sprintf(`export PATH="%s"`, strings.Join(entries, ":")) | 	return fmt.Sprintf(`export PATH="%s"`, strings.Join(entries, ":")) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isCmdExe() { | func isCmdExe() bool { | ||||||
| 	return "" == os.Getenv("SHELL") && strings.Contains(strings.ToLower(os.Getenv("COMSPEC")), "/cmd.exe") | 	return "" == os.Getenv("SHELL") && strings.Contains(strings.ToLower(os.Getenv("COMSPEC")), "/cmd.exe") | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| // +build windows | // +build !windows | ||||||
| 
 | 
 | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| @ -15,7 +15,7 @@ func removePath(p string) (bool, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func listPaths() ([]string, error) { | func listPaths() ([]string, error) { | ||||||
| 	return envpath.List() | 	return envpath.Paths() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func indexOfPath(cur []string, p string) int { | func indexOfPath(cur []string, p string) int { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ func removePath(p string) (bool, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func listPaths() ([]string, error) { | func listPaths() ([]string, error) { | ||||||
| 	return winpath.List() | 	return winpath.Paths() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func indexOfPath(cur []string, p string) int { | func indexOfPath(cur []string, p string) int { | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								tools/tools.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tools/tools.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | // +build tools | ||||||
|  | 
 | ||||||
|  | package tools | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	_ "git.rootprojects.org/root/go-gitver" | ||||||
|  | ) | ||||||
| @ -50,7 +50,7 @@ func remove(p string) (bool, error) { | |||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	index := findMatch(cur, p) | 	index := IndexOf(cur, p) | ||||||
| 	// skip silently, successfully | 	// skip silently, successfully | ||||||
| 	if index < 0 { | 	if index < 0 { | ||||||
| 		return false, nil | 		return false, nil | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user