github.com/direnv/go-lpenv@v0.0.0-20201224120758-54c33c5ae6e4/lp_windows.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package lpenv 6 7 import ( 8 "errors" 9 "os" 10 "path/filepath" 11 "strings" 12 ) 13 14 // ErrNotFound is the error resulting if a path search failed to find an executable file. 15 var ErrNotFound = errors.New("executable file not found in %PATH%") 16 17 func chkStat(file string) error { 18 d, err := os.Stat(file) 19 if err != nil { 20 return err 21 } 22 if d.IsDir() { 23 return os.ErrPermission 24 } 25 return nil 26 } 27 28 func hasExt(file string) bool { 29 i := strings.LastIndex(file, ".") 30 if i < 0 { 31 return false 32 } 33 return strings.LastIndexAny(file, `:\/`) < i 34 } 35 36 func findExecutable(cwd string, file string, exts []string) (string, error) { 37 file = JoinRel(cwd, file) 38 if len(exts) == 0 { 39 return file, chkStat(file) 40 } 41 if hasExt(file) { 42 if chkStat(file) == nil { 43 return file, nil 44 } 45 } 46 for _, e := range exts { 47 if f := file + e; chkStat(f) == nil { 48 return f, nil 49 } 50 } 51 return "", os.ErrNotExist 52 } 53 54 // LookPathEnv searches for an executable named file in the 55 // directories named by the PATH environment variable. 56 // If file contains a slash, it is tried directly and the PATH is not consulted. 57 // LookPathEnv also uses PATHEXT environment variable to match 58 // a suitable candidate. 59 // The result may be an absolute path or a path relative to the current directory. 60 func LookPathEnv(file string, cwd string, env []string) (string, error) { 61 var exts []string 62 x := Getenv(env, `PATHEXT`) 63 if x != "" { 64 for _, e := range strings.Split(strings.ToLower(x), `;`) { 65 if e == "" { 66 continue 67 } 68 if e[0] != '.' { 69 e = "." + e 70 } 71 exts = append(exts, e) 72 } 73 } else { 74 exts = []string{".com", ".exe", ".bat", ".cmd"} 75 } 76 77 if strings.ContainsAny(file, `:\/`) { 78 if f, err := findExecutable(cwd, file, exts); err == nil { 79 return f, nil 80 } else { 81 return "", &Error{file, err} 82 } 83 } 84 if f, err := findExecutable(cwd, file, exts); err == nil { 85 return f, nil 86 } 87 path := Getenv(env, "path") 88 for _, dir := range filepath.SplitList(path) { 89 if f, err := findExecutable(cwd, filepath.Join(dir, file), exts); err == nil { 90 return f, nil 91 } 92 } 93 return "", &Error{file, ErrNotFound} 94 }