diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -132,6 +132,8 @@ 'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php', 'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php', 'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php', + 'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php', + 'ArcanistPhpLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpLinterTestCase.php', 'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php', 'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php', 'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php', @@ -313,6 +315,8 @@ 'ArcanistPEP8LinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPasteWorkflow' => 'ArcanistWorkflow', 'ArcanistPatchWorkflow' => 'ArcanistWorkflow', + 'ArcanistPhpLinter' => 'ArcanistExternalLinter', + 'ArcanistPhpLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPhpcsLinter' => 'ArcanistExternalLinter', 'ArcanistPhpcsLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow', diff --git a/src/lint/linter/ArcanistPhpLinter.php b/src/lint/linter/ArcanistPhpLinter.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/ArcanistPhpLinter.php @@ -0,0 +1,85 @@ +getExecutableCommand()); + + $matches = array(); + $regex = '/^PHP (?P\d+\.\d+\.\d+)\b/'; + if (preg_match($regex, $stdout, $matches)) { + return $matches['version']; + } else { + return false; + } + } + + public function shouldExpectCommandErrors() { + return true; + } + + public function supportsReadDataFromStdin() { + return false; + } + + protected function parseLinterOutput($path, $err, $stdout, $stderr) { + // Older versions of php had both on $stdout, newer ones split it + // Combine $stdout and $stderr for consistency + $stdout = $stderr."\n".$stdout; + $matches = array(); + $regex = '/PHP (?.+?) error:\s+(?.*?)\s+in\s+(?.*?)'. + '\s+on line\s+(?\d*)/'; + if (preg_match($regex, $stdout, $matches)) { + $type = strtolower($matches['type']); + $message = new ArcanistLintMessage(); + $message->setPath($matches['file']); + $message->setLine($matches['line']); + $message->setCode('php.'.$type); + $message->setDescription('This file contains a '.$type.' error: '. + $matches['error'].' on line '.$matches['line']); + $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR); + + // php -l only returns the first error + return array($message); + } + + return array(); + } + +} diff --git a/src/lint/linter/__tests__/ArcanistPhpLinterTestCase.php b/src/lint/linter/__tests__/ArcanistPhpLinterTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/ArcanistPhpLinterTestCase.php @@ -0,0 +1,11 @@ +executeTestsInDirectory( + dirname(__FILE__).'/php/', + new ArcanistPhpLinter()); + } + +} diff --git a/src/lint/linter/__tests__/php/fatal.lint-test b/src/lint/linter/__tests__/php/fatal.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/php/fatal.lint-test @@ -0,0 +1,7 @@ +