1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-01 19:22:41 +01:00

Add a very basic Scala (SBT) linter.

Summary:
SBT is the most common Scala buildsystem. This adds an extremely basic and
slightly horrible linter to check SBT's output for warnings and errors.

Test Plan:
Tested this with a Scala project I've been working on for some time.
It seemed relatively sane.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D4064
This commit is contained in:
Ricky Elrod 2012-12-03 08:13:45 -08:00 committed by epriestley
parent 6cb8d483b2
commit b549f565c9
3 changed files with 111 additions and 0 deletions

View file

@ -104,6 +104,7 @@ phutil_register_library_map(array(
'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php', 'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php', 'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php', 'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
'ArcanistScalaSBTLinter' => 'lint/linter/ArcanistScalaSBTLinter.php',
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php', 'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php', 'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php',
'ArcanistSettings' => 'configuration/ArcanistSettings.php', 'ArcanistSettings' => 'configuration/ArcanistSettings.php',
@ -215,6 +216,7 @@ phutil_register_library_map(array(
'ArcanistPyLintLinter' => 'ArcanistLinter', 'ArcanistPyLintLinter' => 'ArcanistLinter',
'ArcanistRubyLinter' => 'ArcanistLinter', 'ArcanistRubyLinter' => 'ArcanistLinter',
'ArcanistRubyLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistRubyLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistScalaSBTLinter' => 'ArcanistLinter',
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter', 'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
'ArcanistSetConfigWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistSetConfigWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistShellCompleteWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistShellCompleteWorkflow' => 'ArcanistBaseWorkflow',

View file

@ -45,6 +45,9 @@ final class ComprehensiveLintEngine extends ArcanistLintEngine {
$linters[] = id(new ArcanistRubyLinter()) $linters[] = id(new ArcanistRubyLinter())
->setPaths(preg_grep('/\.rb$/', $paths)); ->setPaths(preg_grep('/\.rb$/', $paths));
$linters[] = id(new ArcanistScalaSBTLinter())
->setPaths(preg_grep('/\.scala$/', $paths));
$linters[] = id(new ArcanistJSHintLinter()) $linters[] = id(new ArcanistJSHintLinter())
->setPaths(preg_grep('/\.js$/', $paths)); ->setPaths(preg_grep('/\.js$/', $paths));

View file

@ -0,0 +1,106 @@
<?php
/**
* Uses `sbt compile` to detect various warnings/errors in Scala code.
*
* @group linter
*/
final class ArcanistScalaSBTLinter extends ArcanistLinter {
public function willLintPaths(array $paths) {
return;
}
public function getLinterName() {
return 'ScalaSBT';
}
public function getLintSeverityMap() {
return array();
}
public function getLintNameMap() {
return array();
}
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')) {
throw new ArcanistUsageException(
"This directory does not appear to be maintained by SBT, as we can't ".
"seem to find a working build file (project/Build.scala or ".
"build.sbt).");
}
return true;
}
private function getSBTPath() {
$sbt_bin = "sbt";
// Use the SBT prefix specified in the config file
$working_copy = $this->getEngine()->getWorkingCopy();
$prefix = $working_copy->getConfig('lint.scala_sbt.prefix');
if ($prefix !== null) {
$sbt_bin = $prefix . $sbt_bin;
}
if (!Filesystem::pathExists($sbt_bin)) {
list($err) = exec_manual('which %s', $sbt_bin);
if ($err) {
throw new ArcanistUsageException(
"SBT does not appear to be installed on this system. Install it or ".
"add 'lint.scala_sbt.prefix' in your .arcconfig to point to ".
"the directory where it resides.");
}
}
return $sbt_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 lintPath($path) {
$sbt = $this->getSBTPath();
// 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();
$lines = explode("\n", $stdout);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match(
"/\[(warn|error)\] (.*?):(\d+): (.*?)$/",
$line,
$matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($matches[2]);
$message->setLine($matches[3]);
$message->setCode($this->getLinterName());
$message->setDescription($matches[4]);
$message->setSeverity($this->getMessageCodeSeverity($matches[1]));
$this->addLintMessage($message);
}
}
}