github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/osutils/osutils.go (about) 1 package osutils 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path" 8 "path/filepath" 9 "strings" 10 11 "github.com/ActiveState/cli/internal/errs" 12 "github.com/ActiveState/cli/internal/fileutils" 13 "github.com/ActiveState/cli/internal/multilog" 14 ) 15 16 // CmdString returns a human-readable description of c. 17 // This is a copy of the Go 1.13 (cmd.String) function 18 func CmdString(c *exec.Cmd) string { 19 20 // report the exact executable path (plus args) 21 b := new(strings.Builder) 22 b.WriteString(c.Path) 23 24 for _, a := range c.Args[1:] { 25 b.WriteByte(' ') 26 b.WriteString(a) 27 } 28 29 return b.String() 30 } 31 32 // BashifyPath takes a windows style path and turns it into a bash style path 33 // eg. C:\temp becomes /c/temp 34 func BashifyPath(absolutePath string) (string, error) { 35 if absolutePath[0:1] == "/" { 36 // Already the format we want 37 return absolutePath, nil 38 } 39 40 if absolutePath[1:2] != ":" { 41 // Check for windows style paths 42 return "", errs.New("Unrecognized absolute path format: %s", absolutePath) 43 } 44 45 winPath, err := winPathToLinPath(absolutePath) 46 if err == nil { 47 winPath = strings.Replace(winPath, ` `, `\ `, -1) // escape space 48 return winPath, nil 49 } 50 multilog.Error("Failed to bashify path using installed bash executable, falling back to slash replacement: %v", err) 51 52 vol := filepath.VolumeName(absolutePath) 53 absolutePath = absolutePath[len(vol):] 54 vol = strings.Replace(vol, ":", "", 1) 55 winPath = "/" + vol + filepath.ToSlash(absolutePath) 56 winPath = strings.Replace(winPath, ` `, `\ `, -1) // escape space 57 return winPath, nil 58 } 59 60 func winPathToLinPath(name string) (string, error) { 61 cmd := exec.Command("bash", "-c", "pwd") 62 cmd.Dir = filepath.Dir(name) 63 64 out, err := cmd.Output() 65 if err != nil { 66 return "", err 67 } 68 69 path := strings.TrimSpace(string(out)) + "/" + filepath.Base(name) 70 71 return path, nil 72 } 73 74 // Getwd is an alias of os.Getwd which wraps the error in our localized error message and FailGetWd, which is user facing (doesn't get logged) 75 func Getwd() (string, error) { 76 r, err := os.Getwd() 77 if err != nil { 78 return "", errs.Wrap(err, "GetWd failed") 79 } 80 return r, nil 81 } 82 83 func EnvSliceToMap(envSlice []string) map[string]string { 84 env := map[string]string{} 85 for _, v := range envSlice { 86 kv := strings.SplitN(v, "=", 2) 87 env[kv[0]] = "" 88 if len(kv) == 2 { // account for empty values, windows does some weird stuff, better safe than sorry 89 env[kv[0]] = kv[1] 90 } 91 } 92 return env 93 } 94 95 func EnvMapToSlice(envMap map[string]string) []string { 96 var env []string 97 for k, v := range envMap { 98 env = append(env, fmt.Sprintf("%s=%s", k, v)) 99 } 100 101 return env 102 } 103 104 // Executable returns the resolved path to the currently running executable. 105 func Executable() string { 106 exec, err := os.Executable() 107 if err != nil { 108 exec = os.Args[0] 109 } 110 111 resolved, err := fileutils.ResolvePath(exec) 112 if err != nil { 113 return exec 114 } 115 116 return resolved 117 } 118 119 // ExecutableName returns the name of the executable called with the extension 120 // removed and falls back to the command used to call the executable. 121 func ExecutableName() string { 122 name := filepath.Base(Executable()) 123 name = strings.TrimSuffix(name, path.Ext(name)) 124 return name 125 }