which.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package utils
  3. import (
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "sync"
  9. "golang.org/x/sys/unix"
  10. )
  11. var _ = fmt.Print
  12. var DefaultExeSearchPaths = sync.OnceValue(func() []string {
  13. candidates := [...]string{"/usr/local/bin", "/opt/bin", "/opt/homebrew/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"}
  14. ans := make([]string, 0, len(candidates))
  15. for _, x := range candidates {
  16. if s, err := os.Stat(x); err == nil && s.IsDir() {
  17. ans = append(ans, x)
  18. }
  19. }
  20. return ans
  21. })
  22. func Which(cmd string, paths ...string) string {
  23. if strings.Contains(cmd, string(os.PathSeparator)) {
  24. return ""
  25. }
  26. if len(paths) == 0 {
  27. path := os.Getenv("PATH")
  28. if path == "" {
  29. return ""
  30. }
  31. paths = strings.Split(path, string(os.PathListSeparator))
  32. }
  33. for _, dir := range paths {
  34. q := filepath.Join(dir, cmd)
  35. if unix.Access(q, unix.X_OK) == nil {
  36. s, err := os.Stat(q)
  37. if err == nil && !s.IsDir() {
  38. return q
  39. }
  40. }
  41. }
  42. return ""
  43. }
  44. func FindExe(name string) string {
  45. ans := Which(name)
  46. if ans != "" {
  47. return ans
  48. }
  49. ans = Which(name, DefaultExeSearchPaths()...)
  50. if ans == "" {
  51. ans = name
  52. }
  53. return ans
  54. }