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 @@ -156,6 +156,7 @@ 'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php', 'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php', 'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php', + 'ArcanistScalastyleLinter' => 'lint/linter/ArcanistScalastyleLinter.php', 'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php', 'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php', 'ArcanistSettings' => 'configuration/ArcanistSettings.php', @@ -337,6 +338,7 @@ 'ArcanistRevertWorkflow' => 'ArcanistWorkflow', 'ArcanistRubyLinter' => 'ArcanistExternalLinter', 'ArcanistRubyLinterTestCase' => 'ArcanistArcanistLinterTestCase', + 'ArcanistScalastyleLinter' => 'ArcanistExternalLinter', 'ArcanistScriptAndRegexLinter' => 'ArcanistLinter', 'ArcanistSetConfigWorkflow' => 'ArcanistWorkflow', 'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow', diff --git a/src/lint/linter/ArcanistScalastyleLinter.php b/src/lint/linter/ArcanistScalastyleLinter.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/ArcanistScalastyleLinter.php @@ -0,0 +1,178 @@ +jarPath === null) { + throw new ArcanistUsageException( + pht('Scalastyle JAR path must be configured.')); + } + if ($this->configPath === null) { + throw new ArcanistUsageException( + pht('Scalastyle config XML path must be configured.')); + } + + return array( + '-jar', $this->jarPath, + '--config', $this->configPath, + '--quiet', 'true'); + } + + protected function getDefaultFlags() { + return array(); + } + + protected function parseLinterOutput($path, $err, $stdout, $stderr) { + + $messages = array(); + + $output = trim($stdout); + if (strlen($output) === 0) { + return $messages; + } + + $lines = explode(PHP_EOL, $output); + + foreach ($lines as $line) { + $lintMessage = id(new ArcanistLintMessage()) + ->setPath($path) + ->setCode($this->getLinterName()); + + $matches = array(); + if (preg_match('/^([a-z]+)/', $line, $matches)) { + switch ($matches[1]) { + case 'warning': + $lintMessage->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING); + break; + case 'error': + $lintMessage->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR); + break; + } + } + + $matches = array(); + if (preg_match('/message=([^=]+ )/', $line, $matches)) { + $lintMessage->setDescription(trim($matches[1])); + } else if (preg_match('/message=([^=]+$)/', $line, $matches)) { + $lintMessage->setDescription(trim($matches[1])); + } + + $matches = array(); + if (preg_match('/line=([^=]+ )/', $line, $matches)) { + $lintMessage->setLine(trim($matches[1])); + } else if (preg_match('/line=([^=]+$)/', $line, $matches)) { + $lintMessage->setLine(trim($matches[1])); + } + + $matches = array(); + if (preg_match('/column=([^=]+ )/', $line, $matches)) { + $lintMessage->setChar(trim($matches[1])); + } else if (preg_match('/column=([^=]+$)/', $line, $matches)) { + $lintMessage->setChar(trim($matches[1])); + } + + $messages[] = $lintMessage; + } + + return $messages; + } + + public function getLinterConfigurationOptions() { + $options = array( + 'jar' => array( + 'type' => 'optional string | list', + 'help' => pht( + 'Specify a string (or list of strings) identifying the Scalastyle '. + 'JAR file.') + ), + 'config' => array( + 'type' => 'optional string | list', + 'help' => pht( + 'Specify a string (or list of strings) identifying the Scalastyle '. + 'config XML file.') + ), + ); + + return $options + parent::getLinterConfigurationOptions(); + } + + public function setLinterConfigurationValue($key, $value) { + switch ($key) { + case 'jar': + $working_copy = $this->getEngine()->getWorkingCopy(); + $root = $working_copy->getProjectRoot(); + + foreach ((array)$value as $path) { + if (Filesystem::pathExists($path)) { + $this->jarPath = $path; + return; + } + + $path = Filesystem::resolvePath($path, $root); + + if (Filesystem::pathExists($path)) { + $this->jarPath = $path; + return; + } + } + + throw new ArcanistUsageException( + pht('None of the configured Scalastyle JARs can be located.')); + + case 'config': + $working_copy = $this->getEngine()->getWorkingCopy(); + $root = $working_copy->getProjectRoot(); + + foreach ((array)$value as $path) { + if (Filesystem::pathExists($path)) { + $this->configPath = $path; + return; + } + + $path = Filesystem::resolvePath($path, $root); + + if (Filesystem::pathExists($path)) { + $this->configPath = $path; + return; + } + } + + throw new ArcanistUsageException( + pht('None of the configured Scalastyle configs can be located.')); + } + + return parent::setLinterConfigurationValue($key, $value); + } + +}