diff --git a/src/filesystem/Filesystem.php b/src/filesystem/Filesystem.php --- a/src/filesystem/Filesystem.php +++ b/src/filesystem/Filesystem.php @@ -1103,12 +1103,24 @@ } return null; } - $stdout = head($stdout); + + // These are the only file extensions that can be executed directly + // when using proc_open() with 'bypass_shell'. + $executable_extensions = ['.exe', '.bat', '.cmd', '.com']; + + foreach ($stdout as $line) { + $path = trim($line); + foreach ($executable_extensions as $ext) { + if (substr($path, -strlen($ext)) === $ext) { + return $path; + } + } + } + return null; } else { list($err, $stdout) = exec_manual('which %s', $binary); + return $err === 0 ? trim($stdout) : null; } - - return $err === 0 ? trim($stdout) : null; } diff --git a/src/lint/linter/ArcanistExternalLinter.php b/src/lint/linter/ArcanistExternalLinter.php --- a/src/lint/linter/ArcanistExternalLinter.php +++ b/src/lint/linter/ArcanistExternalLinter.php @@ -133,7 +133,19 @@ * @task bin */ final public function getBinary() { - return coalesce($this->bin, $this->getDefaultBinary()); + $bin = coalesce($this->bin, $this->getDefaultBinary()); + if (phutil_is_windows()) { + // On Windows, we use proc_open with 'bypass_shell' option, which will + // resolve %PATH%, but not %PATHEXT% (unless the extension is .exe). + // Therefore find the right binary ourselves. + $resolved = Filesystem::resolveBinary($bin); + if ($resolved) { + // If we can't find it, leave it unresolved, as this string will be + // used in some error messages elsewhere. + $bin = $resolved; + } + } + return $bin; } /**