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 @@ -311,7 +311,7 @@ 'ArcanistRevertWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistRubyLinter' => 'ArcanistExternalLinter', 'ArcanistRubyLinterTestCase' => 'ArcanistArcanistLinterTestCase', - 'ArcanistScalaSBTLinter' => 'ArcanistLinter', + 'ArcanistScalaSBTLinter' => 'ArcanistExternalLinter', 'ArcanistScriptAndRegexLinter' => 'ArcanistLinter', 'ArcanistSetConfigWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistShellCompleteWorkflow' => 'ArcanistBaseWorkflow', diff --git a/src/lint/linter/ArcanistScalaSBTLinter.php b/src/lint/linter/ArcanistScalaSBTLinter.php --- a/src/lint/linter/ArcanistScalaSBTLinter.php +++ b/src/lint/linter/ArcanistScalaSBTLinter.php @@ -3,60 +3,78 @@ /** * Uses `sbt compile` to detect various warnings/errors in Scala code. */ -final class ArcanistScalaSBTLinter extends ArcanistLinter { +final class ArcanistScalaSBTLinter extends ArcanistExternalLinter { + + public function getInfoName() { + return 'sbt'; + } + + public function getInfoURI() { + return 'http://www.scala-sbt.org'; + } + + public function getInfoDescription() { + return pht('sbt is a build tool for Scala, Java, and more.'); + } public function getLinterName() { return 'ScalaSBT'; } - public function canRun() { - // Check if this looks like a SBT project. If it doesn't, throw, because - // we rely fairly heavily on `sbt compile` working, below. We don't want - // to call out to scalac ourselves, because then we'll end up in Class Path - // Hell. We let the build system handle this for us. - if (!Filesystem::pathExists('project/Build.scala') && - !Filesystem::pathExists('build.sbt')) { - return false; - } - return true; + public function getLinterConfigurationName() { + return 'scala-sbt'; } - private function getSBTPath() { - $sbt_bin = "sbt"; - + public function getDefaultBinary() { $prefix = $this->getDeprecatedConfiguration('lint.scala_sbt.prefix'); - if ($prefix !== null) { - $sbt_bin = $prefix . $sbt_bin; - } + $bin = 'sbt'; - return $sbt_bin; + if ($prefix) { + return $prefix.'/'.$bin; + } else { + return $bin; + } } - private function getMessageCodeSeverity($type_of_error) { - switch ($type_of_error) { - case 'warn': - return ArcanistLintSeverity::SEVERITY_WARNING; - case 'error': - return ArcanistLintSeverity::SEVERITY_ERROR; + public function getVersion() { + // NOTE: `sbt --version` returns a non-zero exit status. + list($err, $stdout) = exec_manual( + '%C --version', + $this->getExecutableCommand()); + + $matches = array(); + $regex = '/^sbt launcher version (?P\d+\.\d+\.\d+)$/'; + if (preg_match($regex, $stdout, $matches)) { + return $matches['version']; + } else { + return false; } } - public function lintPath($path) { - $sbt = $this->getSBTPath(); + public function getInstallInstructions() { + return pht( + 'Check for installation instructions.'); + } + + public function shouldExpectCommandErrors() { + return true; + } - // Tell SBT to not use color codes so our regex life is easy. - // TODO: Should this be "clean compile" instead of "compile"? - $f = new ExecFuture("%s -Dsbt.log.noformat=true compile", $sbt); - list($err, $stdout, $stderr) = $f->resolve(); + protected function getMandatoryFlags() { + return array( + '-Dsbt.log.noformat=true', + 'compile', + ); + } - $lines = explode("\n", $stdout); + protected function parseLinterOutput($path, $err, $stdout, $stderr) { + $lines = phutil_split_lines($stdout, false); $messages = array(); + foreach ($lines as $line) { $matches = null; - if (!preg_match( - "/\[(warn|error)\] (.*?):(\d+): (.*?)$/", - $line, - $matches)) { + $regex = '/\[(warn|error)\] (.*?):(\d+): (.*?)$/'; + if (!preg_match($regex, $line, $matches)) { continue; } foreach ($matches as $key => $match) { @@ -68,9 +86,23 @@ $message->setLine($matches[3]); $message->setCode($this->getLinterName()); $message->setDescription($matches[4]); - $message->setSeverity($this->getMessageCodeSeverity($matches[1])); - $this->addLintMessage($message); + + switch ($matches[1]) { + case 'error': + $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR); + break; + case 'warn': + $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING); + break; + default: + $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE); + break; + } + + $messages[] = $message; } + + return $messages; } }