* Try Python commands to get sys.executable path.
(commands: string[])
| 107 | * Try Python commands to get sys.executable path. |
| 108 | */ |
| 109 | async function tryPythonCommands(commands: string[]): Promise<string | null> { |
| 110 | for (const cmd of commands) { |
| 111 | try { |
| 112 | const result = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)']); |
| 113 | const executablePath = result.stdout.trim(); |
| 114 | if (executablePath && executablePath !== 'None') { |
| 115 | // On Windows, ensure .exe suffix if missing (but only for Windows-style paths) |
| 116 | if (process.platform === 'win32' && !executablePath.toLowerCase().endsWith('.exe')) { |
| 117 | // Only add .exe for Windows-style paths (drive letter or UNC paths) |
| 118 | if (executablePath.includes('\\') || /^[A-Za-z]:/.test(executablePath)) { |
| 119 | return executablePath + '.exe'; |
| 120 | } |
| 121 | } |
| 122 | return executablePath; |
| 123 | } |
| 124 | } catch (error) { |
| 125 | const errorMsg = error instanceof Error ? error.message : String(error); |
| 126 | logger.debug(`Python command "${cmd}" failed: ${errorMsg}`); |
| 127 | |
| 128 | // Log permission/access errors differently |
| 129 | if ( |
| 130 | errorMsg.includes('Access is denied') || |
| 131 | errorMsg.includes('EACCES') || |
| 132 | errorMsg.includes('EPERM') |
| 133 | ) { |
| 134 | logger.warn(`Permission denied when trying Python command "${cmd}": ${errorMsg}`); |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | return null; |
| 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Try direct command validation as final fallback. |
no outgoing calls
no test coverage detected
searching dependent graphs…