0
# Executable Discovery
1
2
Cross-platform utility for finding executables on the system PATH with automatic handling of platform-specific file extensions and search paths.
3
4
## Capabilities
5
6
### ExecutableFinder Class
7
8
Locates executables by scanning the file system and PATH environment variable, with intelligent handling of platform-specific executable extensions and search locations.
9
10
```java { .api }
11
public class ExecutableFinder {
12
/**
13
* Find executable by scanning file system and PATH
14
* @param named the name of the executable to find
15
* @return absolute path to executable, or null if not found
16
*/
17
public String find(String named);
18
}
19
```
20
21
**Usage Examples:**
22
23
```java
24
import org.openqa.selenium.os.ExecutableFinder;
25
26
ExecutableFinder finder = new ExecutableFinder();
27
28
// Find browser drivers
29
String chromeDriver = finder.find("chromedriver");
30
String geckoDriver = finder.find("geckodriver");
31
String edgeDriver = finder.find("msedgedriver");
32
33
// Find system utilities
34
String gitPath = finder.find("git");
35
String pythonPath = finder.find("python");
36
String javacPath = finder.find("javac");
37
38
if (chromeDriver != null) {
39
System.out.println("ChromeDriver found at: " + chromeDriver);
40
} else {
41
System.err.println("ChromeDriver not found on PATH");
42
}
43
44
// Use with ExternalProcess
45
if (gitPath != null) {
46
ExternalProcess process = ExternalProcess.builder()
47
.command(gitPath, Arrays.asList("--version"))
48
.start();
49
50
if (process.waitFor(Duration.ofSeconds(5))) {
51
System.out.println("Git version: " + process.getOutput().trim());
52
}
53
}
54
```
55
56
### Search Algorithm
57
58
The ExecutableFinder implements a comprehensive search strategy that handles platform differences automatically:
59
60
**Search Order:**
61
1. **Direct Path Check**: If the provided name is already an absolute or relative path to an executable file
62
2. **Windows Extension Check**: On Windows, automatically try adding `.exe` extension
63
3. **PATH Environment Scanning**: Search each directory in the PATH environment variable
64
4. **Platform-Specific Extensions**: Try all appropriate extensions for the current platform
65
5. **macOS Specific Paths**: On macOS, additionally search paths defined in `/etc/paths`
66
67
**Platform-Specific Extensions:**
68
- **Windows**: `""`, `.cmd`, `.exe`, `.com`, `.bat`
69
- **Unix/Linux/macOS**: `""` (no extension)
70
71
**Environment Variable Handling:**
72
- Searches `PATH` environment variable (case-insensitive lookup)
73
- Uses `File.pathSeparator` for splitting PATH entries (`;` on Windows, `:` on Unix)
74
- Handles missing or empty PATH gracefully
75
76
**macOS Enhancement:**
77
- Reads `/etc/paths` file for additional system paths
78
- Gracefully handles missing `/etc/paths` file
79
- Each line in `/etc/paths` is treated as an additional search directory
80
81
### File System Checks
82
83
The finder performs comprehensive checks to ensure discovered files are actually executable:
84
85
**Validation Criteria:**
86
- File must exist on the file system
87
- Must not be a directory
88
- Must have executable permissions (`File.canExecute()`)
89
90
**Error Handling:**
91
- Returns `null` if no executable found (never throws exceptions)
92
- Handles I/O errors gracefully during file system access
93
- Manages permissions errors when checking executability
94
95
**Cross-Platform Considerations:**
96
- Respects platform-specific permission models
97
- Handles symbolic links appropriately
98
- Works with both absolute and relative paths in PATH entries
99
100
### Integration with Process Management
101
102
ExecutableFinder is commonly used with process management classes to locate executables before launching:
103
104
```java
105
import org.openqa.selenium.os.ExecutableFinder;
106
import org.openqa.selenium.os.ExternalProcess;
107
108
// Pattern: Locate then execute
109
ExecutableFinder finder = new ExecutableFinder();
110
String executable = finder.find("my-tool");
111
112
if (executable != null) {
113
ExternalProcess process = ExternalProcess.builder()
114
.command(executable, Arrays.asList("arg1", "arg2"))
115
.start();
116
// ... manage process
117
} else {
118
throw new IllegalStateException("Required executable 'my-tool' not found on PATH");
119
}
120
121
// Legacy API integration (deprecated)
122
String driverPath = finder.find("chromedriver");
123
if (driverPath != null) {
124
CommandLine cmd = new CommandLine(driverPath, "--port=9515");
125
cmd.execute();
126
}
127
```
128
129
This pattern ensures robust executable discovery before attempting to launch processes, providing clear error messages when required tools are not available in the environment.