55@preconcurrency import class Foundation. FileManager
66@preconcurrency import struct Foundation. URL
77@preconcurrency import struct Foundation. Data
8+ @preconcurrency import struct Foundation. ObjCBool
89@preconcurrency import func Foundation. kill
910@preconcurrency import var Foundation. SIGINT
1011@preconcurrency import var Foundation. SIGTERM
1112import protocol Dispatch. DispatchSourceSignal
1213import class Dispatch. DispatchSource
1314
1415internal func which( _ executable: String ) throws -> URL {
16+ func checkCandidate( _ candidate: URL ) -> Bool {
17+ var isDirectory : ObjCBool = false
18+ let fileExists = FileManager . default. fileExists ( atPath: candidate. path, isDirectory: & isDirectory)
19+ return fileExists && !isDirectory. boolValue && FileManager . default. isExecutableFile ( atPath: candidate. path)
20+ }
1521 do {
1622 // Check overriding environment variable
1723 let envVariable = executable. uppercased ( ) . replacingOccurrences ( of: " - " , with: " _ " ) + " _PATH "
1824 if let path = ProcessInfo . processInfo. environment [ envVariable] {
1925 let url = URL ( fileURLWithPath: path) . appendingPathComponent ( executable)
20- if FileManager . default . isExecutableFile ( atPath : url. path ) {
26+ if checkCandidate ( url) {
2127 return url
2228 }
2329 }
@@ -31,7 +37,7 @@ internal func which(_ executable: String) throws -> URL {
3137 let paths = ProcessInfo . processInfo. environment [ " PATH " ] !. split ( separator: pathSeparator)
3238 for path in paths {
3339 let url = URL ( fileURLWithPath: String ( path) ) . appendingPathComponent ( executable)
34- if FileManager . default . isExecutableFile ( atPath : url. path ) {
40+ if checkCandidate ( url) {
3541 return url
3642 }
3743 }
0 commit comments