Created
September 26, 2018 19:36
-
-
Save ambv/af475051961126765e35d31bd054e61c to your computer and use it in GitHub Desktop.
How to integrate Black with Arcanist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
final class PythonFormatLinter extends ArcanistFutureLinter { | |
public function getLinterName() { | |
return 'BLACK'; | |
} | |
protected function getFuturesLimit() { | |
return 8; | |
} | |
protected function buildFutures(array $paths) { | |
$vcs_root = $this->getVCSRoot(); | |
$futures = array(); | |
foreach ($paths as $path) { | |
$fullPath = $this->getEngine()->getFilePathOnDisk($path); | |
$dirPath = dirname($fullPath); | |
$futures[$path] = new ExecFuture( | |
'/usr/local/bin/black --diff %s', | |
$this->getEngine()->getFilePathOnDisk($path)); | |
$futures[$path]->setCWD($this->getProjectRoot()); | |
} | |
return $futures; | |
} | |
protected function resolveFuture($path, Future $future) { | |
list($err, $stdout, $stderr) = $future->resolve(); | |
if ($err) { | |
$this->addLintMessage( | |
$this->parseLinterError($path, $stdout, $stderr, $err)); | |
} else { | |
$messages = $this->parseLinterOutput($path, $stdout, $stderr); | |
if ($messages !== false) { | |
foreach ($messages as $message) { | |
$this->addLintMessage($message); | |
} | |
} | |
} | |
} | |
protected function parseLinterOutput($path, $stdout, $stderr) { | |
if (empty($stdout) || substr($stdout, 0, 3) != '---') { | |
return array(); | |
} | |
$messages = array(); | |
$parser = new ArcanistDiffParser(); | |
$changes = $parser->parseDiff($stdout); | |
foreach ($changes as $change) { | |
foreach ($change->getHunks() as $hunk) { | |
$repl = array(); | |
$orig = array(); | |
$lines = phutil_split_lines($hunk->getCorpus(), false); | |
foreach ($lines as $line) { | |
if (empty($line)) { | |
continue; | |
} | |
$char = $line[0]; | |
$rest = substr($line, 1); | |
switch ($char) { | |
case '-': | |
$orig[] = $rest; | |
break; | |
case '+': | |
$repl[] = $rest; | |
break; | |
case '~': | |
break; | |
case ' ': | |
$orig[] = $rest; | |
$repl[] = $rest; | |
break; | |
} | |
} | |
$messages[] = id(new ArcanistLintMessage()) | |
->setPath($path) | |
->setLine($hunk->getOldOffset()) | |
->setChar(1) | |
->setCode($this->getLinterName()) | |
->setSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX) | |
->setName('format') | |
->setOriginalText(implode("\n", $orig)) | |
->setReplacementText(implode("\n", $repl)) | |
->setBypassChangedLineFiltering(true); | |
} | |
} | |
return $messages; | |
} | |
protected function parseLinterError($path, $stdout, $stderr, $err) { | |
$matches = null; | |
preg_match( | |
'/error: cannot format -: Cannot parse: (?P<line>\d+):(?P<column>\d+): (?P<message>.*)/', | |
$stderr, | |
$matches); | |
if ($matches) { | |
$line = $matches['line']; | |
$col = $matches['column'] + 1; | |
$message = $matches['message']; | |
$name = 'Cannot parse'; | |
$severity = ArcanistLintSeverity::SEVERITY_ERROR; | |
} else { | |
$line = 1; | |
$col = 1; | |
$message = $stderr; | |
$name = sprintf('Command execution failed (%d)', $err); | |
$severity = ArcanistLintSeverity::SEVERITY_ADVICE; | |
} | |
return id(new ArcanistLintMessage()) | |
->setPath($path) | |
->setLine($line) | |
->setChar($col) | |
->setCode($this->getLinterName()) | |
->setSeverity($severity) | |
->setName($name) | |
->setDescription($message) | |
->setBypassChangedLineFiltering(true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment