75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package troubleshooter
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// IsExecutable checks if a given path points to an executable file or if a command exists in PATH
|
|
func IsExecutable(name string) (string, error) {
|
|
// If name contains any path separators, treat it as a path
|
|
if strings.Contains(name, string(os.PathSeparator)) {
|
|
path, err := filepath.Abs(name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return checkExecutable(path)
|
|
}
|
|
|
|
// Otherwise, search in PATH
|
|
return findInPath(name)
|
|
}
|
|
|
|
// findInPath searches for an executable in the system's PATH
|
|
func findInPath(name string) (string, error) {
|
|
// On Windows, also check for .exe extension if not provided
|
|
if runtime.GOOS == "windows" && !strings.HasSuffix(strings.ToLower(name), ".exe") {
|
|
name += ".exe"
|
|
}
|
|
|
|
// Get system PATH
|
|
pathEnv := os.Getenv("PATH")
|
|
paths := strings.Split(pathEnv, string(os.PathListSeparator))
|
|
|
|
// Search each directory in PATH
|
|
for _, dir := range paths {
|
|
if dir == "" {
|
|
continue
|
|
}
|
|
path := filepath.Join(dir, name)
|
|
fullPath, err := checkExecutable(path)
|
|
if err == nil {
|
|
return fullPath, nil
|
|
}
|
|
}
|
|
|
|
return "", errors.New("executable not found in PATH")
|
|
}
|
|
|
|
// checkExecutable verifies if a given path points to an executable file
|
|
func checkExecutable(path string) (string, error) {
|
|
fileInfo, err := os.Stat(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if fileInfo.IsDir() {
|
|
return "", errors.New("path points to a directory")
|
|
}
|
|
|
|
// On Windows, just check if the file exists (as Windows uses file extensions)
|
|
if runtime.GOOS == "windows" {
|
|
return path, nil
|
|
}
|
|
|
|
// On Unix-like systems, check if the file is executable
|
|
if fileInfo.Mode()&0111 != 0 {
|
|
return path, nil
|
|
}
|
|
|
|
return "", errors.New("file is not executable")
|
|
}
|