@@ -319,28 +319,46 @@ public final class Process: ObjectIdentifierProtocol {
319
319
_ program: String ,
320
320
workingDirectory: AbsolutePath ? = nil
321
321
) -> AbsolutePath ? {
322
- return Process . executablesQueue. sync {
323
- // Check if we already have a value for the program.
324
- if let value = Process . validatedExecutablesMap [ program] {
325
- return value
322
+ if let abs = try ? AbsolutePath ( validating: program) {
323
+ return abs
324
+ }
325
+ let cwdOpt = workingDirectory ?? localFileSystem. currentWorkingDirectory
326
+ // The program might be a multi-component relative path.
327
+ if let rel = try ? RelativePath ( validating: program) , rel. components. count > 1 {
328
+ if let cwd = cwdOpt {
329
+ let abs = cwd. appending ( rel)
330
+ if localFileSystem. isExecutableFile ( abs) {
331
+ return abs
332
+ }
326
333
}
327
-
328
- let cwd = workingDirectory ?? localFileSystem . currentWorkingDirectory
329
-
330
- // FIXME: This can be cached.
334
+ return nil
335
+ }
336
+ // From here on out, the program is an executable name, i.e. it doesn't contain a "/"
337
+ let lookup : ( ) -> AbsolutePath ? = {
331
338
let envSearchPaths = getEnvSearchPaths (
332
339
pathString: ProcessEnv . path,
333
- currentWorkingDirectory: cwd
340
+ currentWorkingDirectory: cwdOpt
334
341
)
335
- // Lookup and cache the executable path.
336
342
let value = lookupExecutablePath (
337
343
filename: program,
338
- currentWorkingDirectory: cwd ,
344
+ currentWorkingDirectory: cwdOpt ,
339
345
searchPaths: envSearchPaths
340
346
)
341
- Process . validatedExecutablesMap [ program] = value
342
347
return value
343
348
}
349
+ // This should cover the most common cases, i.e. when the cache is most helpful.
350
+ if workingDirectory == localFileSystem. currentWorkingDirectory {
351
+ return Process . executablesQueue. sync {
352
+ if let value = Process . validatedExecutablesMap [ program] {
353
+ return value
354
+ }
355
+ let value = lookup ( )
356
+ Process . validatedExecutablesMap [ program] = value
357
+ return value
358
+ }
359
+ } else {
360
+ return lookup ( )
361
+ }
344
362
}
345
363
346
364
/// Launch the subprocess.
0 commit comments