Summary: Added FBCODE like linting support to our codebase. Test Plan: arc lint lint's the code. Reviewers: dhruba Reviewed By: dhruba CC: emayanke, leveldb Differential Revision: https://reviews.facebook.net/D7041main
parent
3366eda839
commit
34487af458
@ -0,0 +1 @@ |
||||
{"__symbol_cache_version__":8,"b937ad5f80a8bd1156038b730ff56ec5":{"have":{"class":{"FacebookFbcodeLintEngine":71}},"need":{"class":{"ArcanistLintEngine":104,"ArcanistGeneratedLinter":488,"ArcanistNoLintLinter":577,"ArcanistTextLinter":658,"ArcanistPEP8Linter":1227,"FbcodeCppLinter":1715,"PfffCppLinter":1759,"ArcanistSpellingLinter":1875,"ArcanistFilenameLinter":4207,"Filesystem":357,"ArcanistLintSeverity":778}},"xmap":{"FacebookFbcodeLintEngine":["ArcanistLintEngine"]}},"4443484928afb005f585843d07b04190":{"have":{"class":{"FbcodeCppLinter":13}},"need":{"function":{"Futures":1265},"class":{"ArcanistLinter":37,"ExecFuture":934,"ArcanistLintSeverity":1729}},"xmap":{"FbcodeCppLinter":["ArcanistLinter"]}},"02e2a613e371424b2108d2d6cb849d39":{"have":{"class":{"PfffCppLinter":71}},"need":{"function":{"Futures":875},"class":{"ArcanistLinter":93,"ExecFuture":756,"ArcanistLintMessage":1270,"ArcanistLintSeverity":1607}},"xmap":{"PfffCppLinter":["ArcanistLinter"]}}} |
@ -0,0 +1,3 @@ |
||||
<?php |
||||
|
||||
phutil_register_library('linters', __FILE__); |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* This file is automatically generated. Use 'arc liberate' to rebuild it. |
||||
* @generated |
||||
* @phutil-library-version 2 |
||||
*/ |
||||
|
||||
phutil_register_library_map(array( |
||||
'__library_version__' => 2, |
||||
'class' => |
||||
array( |
||||
'FacebookFbcodeLintEngine' => 'lint_engine/FacebookFbcodeLintEngine.php', |
||||
'FbcodeCppLinter' => 'cpp_linter/FbcodeCppLinter.php', |
||||
'PfffCppLinter' => 'cpp_linter/PfffCppLinter.php', |
||||
), |
||||
'function' => |
||||
array( |
||||
), |
||||
'xmap' => |
||||
array( |
||||
'FacebookFbcodeLintEngine' => 'ArcanistLintEngine', |
||||
'FbcodeCppLinter' => 'ArcanistLinter', |
||||
'PfffCppLinter' => 'ArcanistLinter', |
||||
), |
||||
)); |
@ -0,0 +1,99 @@ |
||||
<?php |
||||
|
||||
class FbcodeCppLinter extends ArcanistLinter { |
||||
const CPPLINT = "/home/engshare/tools/cpplint"; |
||||
const LINT_ERROR = 1; |
||||
const LINT_WARNING = 2; |
||||
const C_FLAG = "--c_mode=true"; |
||||
private $rawLintOutput = array(); |
||||
|
||||
public function willLintPaths(array $paths) { |
||||
$futures = array(); |
||||
$ret_value = 0; |
||||
$last_line = system("which cpplint", $ret_value); |
||||
$CPP_LINT = false; |
||||
if ($ret_value == 0) { |
||||
$CPP_LINT = $last_line; |
||||
} else if (file_exists(self::CPPLINT)) { |
||||
$CPP_LINT = self::CPPLINT; |
||||
} |
||||
|
||||
if ($CPP_LINT) { |
||||
foreach ($paths as $p) { |
||||
$lpath = $this->getEngine()->getFilePathOnDisk($p); |
||||
$lpath_file = file($lpath); |
||||
if (preg_match('/\.(c)$/', $lpath) || |
||||
preg_match('/-\*-.*Mode: C[; ].*-\*-/', $lpath_file[0]) || |
||||
preg_match('/vim(:.*)*:\s*(set\s+)?filetype=c\s*:/', $lpath_file[0]) |
||||
) { |
||||
$futures[$p] = new ExecFuture("%s %s %s 2>&1", |
||||
$CPP_LINT, self::C_FLAG, |
||||
$this->getEngine()->getFilePathOnDisk($p)); |
||||
} else { |
||||
$futures[$p] = new ExecFuture("%s %s 2>&1", |
||||
self::CPPLINT, $this->getEngine()->getFilePathOnDisk($p)); |
||||
} |
||||
} |
||||
|
||||
foreach (Futures($futures)->limit(8) as $p => $f) { |
||||
$this->rawLintOutput[$p] = $f->resolvex(); |
||||
} |
||||
} |
||||
return; |
||||
} |
||||
|
||||
public function getLinterName() { |
||||
return "FBCPP"; |
||||
} |
||||
|
||||
public function lintPath($path) { |
||||
$msgs = $this->getCppLintOutput($path); |
||||
foreach ($msgs as $m) { |
||||
$this->raiseLintAtLine($m['line'], 0, $m['severity'], $m['msg']); |
||||
} |
||||
} |
||||
|
||||
public function getLintSeverityMap() { |
||||
return array( |
||||
self::LINT_WARNING => ArcanistLintSeverity::SEVERITY_WARNING, |
||||
self::LINT_ERROR => ArcanistLintSeverity::SEVERITY_ERROR |
||||
); |
||||
} |
||||
|
||||
public function getLintNameMap() { |
||||
return array( |
||||
self::LINT_WARNING => "CppLint Warning", |
||||
self::LINT_ERROR => "CppLint Error" |
||||
); |
||||
} |
||||
|
||||
private function getCppLintOutput($path) { |
||||
list($output) = $this->rawLintOutput[$path]; |
||||
|
||||
$msgs = array(); |
||||
$current = null; |
||||
foreach (explode("\n", $output) as $line) { |
||||
if (preg_match('/[^:]*\((\d+)\):(.*)$/', $line, $matches)) { |
||||
if ($current) { |
||||
$msgs[] = $current; |
||||
} |
||||
$line = $matches[1]; |
||||
$text = $matches[2]; |
||||
$sev = preg_match('/.*Warning.*/', $text) |
||||
? self::LINT_WARNING |
||||
: self::LINT_ERROR; |
||||
$current = array('line' => $line, |
||||
'msg' => $text, |
||||
'severity' => $sev); |
||||
} else if ($current) { |
||||
$current['msg'] .= ' ' . $line; |
||||
} |
||||
} |
||||
if ($current) { |
||||
$msgs[] = $current; |
||||
} |
||||
|
||||
return $msgs; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,68 @@ |
||||
<?php |
||||
// Copyright 2004-present Facebook. All rights reserved. |
||||
|
||||
class PfffCppLinter extends ArcanistLinter { |
||||
const PROGRAM = "/home/engshare/tools/checkCpp"; |
||||
|
||||
public function getLinterName() { |
||||
return "checkCpp"; |
||||
} |
||||
public function getLintNameMap() { |
||||
return array( |
||||
); |
||||
} |
||||
|
||||
public function getLintSeverityMap() { |
||||
return array( |
||||
); |
||||
} |
||||
|
||||
public function willLintPaths(array $paths) { |
||||
$program = false; |
||||
$ret_value = 0; |
||||
$last_line = system("which checkCpp", $ret_value); |
||||
if ($ret_value == 0) { |
||||
$program = $last_line; |
||||
} else if (file_exists(self::PROGRAM)) { |
||||
$program = self::PROGRAM; |
||||
} |
||||
if ($program) { |
||||
$futures = array(); |
||||
foreach ($paths as $p) { |
||||
$futures[$p] = new ExecFuture("%s --lint %s 2>&1", |
||||
$program, $this->getEngine()->getFilePathOnDisk($p)); |
||||
} |
||||
foreach (Futures($futures)->limit(8) as $p => $f) { |
||||
|
||||
list($stdout, $stderr) = $f->resolvex(); |
||||
$raw = json_decode($stdout, true); |
||||
if (!is_array($raw)) { |
||||
throw new Exception( |
||||
"checkCpp returned invalid JSON!". |
||||
"Stdout: {$stdout} Stderr: {$stderr}" |
||||
); |
||||
} |
||||
foreach($raw as $err) { |
||||
$this->addLintMessage( |
||||
ArcanistLintMessage::newFromDictionary( |
||||
array( |
||||
'path' => $err['file'], |
||||
'line' => $err['line'], |
||||
'char' => 0, |
||||
'name' => $err['name'], |
||||
'description' => $err['info'], |
||||
'code' => $this->getLinterName(), |
||||
'severity' => ArcanistLintSeverity::SEVERITY_WARNING, |
||||
) |
||||
) |
||||
); |
||||
} |
||||
} |
||||
} |
||||
return; |
||||
} |
||||
|
||||
public function lintPath($path) { |
||||
return; |
||||
} |
||||
} |
@ -0,0 +1,147 @@ |
||||
<?php |
||||
// Copyright 2004-present Facebook. All rights reserved. |
||||
|
||||
class FacebookFbcodeLintEngine extends ArcanistLintEngine { |
||||
|
||||
public function buildLinters() { |
||||
$linters = array(); |
||||
$paths = $this->getPaths(); |
||||
|
||||
// Remove all deleted files, which are not checked by the |
||||
// following linters. |
||||
foreach ($paths as $key => $path) { |
||||
if (!Filesystem::pathExists($this->getFilePathOnDisk($path))) { |
||||
unset($paths[$key]); |
||||
} |
||||
} |
||||
|
||||
$generated_linter = new ArcanistGeneratedLinter(); |
||||
$linters[] = $generated_linter; |
||||
|
||||
$nolint_linter = new ArcanistNoLintLinter(); |
||||
$linters[] = $nolint_linter; |
||||
|
||||
$text_linter = new ArcanistTextLinter(); |
||||
$text_linter->setCustomSeverityMap(array( |
||||
ArcanistTextLinter::LINT_LINE_WRAP |
||||
=> ArcanistLintSeverity::SEVERITY_ADVICE, |
||||
)); |
||||
$linters[] = $text_linter; |
||||
|
||||
$java_text_linter = new ArcanistTextLinter(); |
||||
$java_text_linter->setMaxLineLength(100); |
||||
$java_text_linter->setCustomSeverityMap(array( |
||||
ArcanistTextLinter::LINT_LINE_WRAP |
||||
=> ArcanistLintSeverity::SEVERITY_ADVICE, |
||||
)); |
||||
$linters[] = $java_text_linter; |
||||
|
||||
$pep8_options = $this->getPEP8WithTextOptions().',E302'; |
||||
|
||||
$python_linter = new ArcanistPEP8Linter(); |
||||
$python_linter->setConfig(array('options' => $pep8_options)); |
||||
$linters[] = $python_linter; |
||||
|
||||
$python_2space_linter = new ArcanistPEP8Linter(); |
||||
$python_2space_linter->setConfig(array('options' => $pep8_options.',E111')); |
||||
$linters[] = $python_2space_linter; |
||||
|
||||
// Currently we can't run cpplint in commit hook mode, because it |
||||
// depends on having access to the working directory. |
||||
if (!$this->getCommitHookMode()) { |
||||
$cpp_linter = new FbcodeCppLinter(); |
||||
$cpp_linter2 = new PfffCppLinter(); |
||||
$linters[] = $cpp_linter; |
||||
$linters[] = $cpp_linter2; |
||||
} |
||||
|
||||
$spelling_linter = new ArcanistSpellingLinter(); |
||||
$linters[] = $spelling_linter; |
||||
|
||||
foreach ($paths as $path) { |
||||
$is_text = false; |
||||
|
||||
$text_extensions = ( |
||||
'/\.('. |
||||
'cpp|cxx|c|cc|h|hpp|hxx|tcc|'. |
||||
'py|rb|hs|pl|pm|tw|'. |
||||
'php|phpt|css|js|'. |
||||
'java|'. |
||||
'thrift|'. |
||||
'lua|'. |
||||
'siv|'. |
||||
'txt'. |
||||
')$/' |
||||
); |
||||
if (preg_match($text_extensions, $path)) { |
||||
$is_text = true; |
||||
} |
||||
if ($is_text) { |
||||
$nolint_linter->addPath($path); |
||||
|
||||
$generated_linter->addPath($path); |
||||
$generated_linter->addData($path, $this->loadData($path)); |
||||
|
||||
if (preg_match('/\.java$/', $path)) { |
||||
$java_text_linter->addPath($path); |
||||
$java_text_linter->addData($path, $this->loadData($path)); |
||||
} else { |
||||
$text_linter->addPath($path); |
||||
$text_linter->addData($path, $this->loadData($path)); |
||||
} |
||||
|
||||
$spelling_linter->addPath($path); |
||||
$spelling_linter->addData($path, $this->loadData($path)); |
||||
} |
||||
if (isset($cpp_linter) && isset($cpp_linter2) && |
||||
preg_match('/\.(cpp|c|cc|cxx|h|hh|hpp|hxx|tcc)$/', $path)) { |
||||
$cpp_linter->addPath($path); |
||||
$cpp_linter->addData($path, $this->loadData($path)); |
||||
$cpp_linter2->addPath($path); |
||||
$cpp_linter2->addData($path, $this->loadData($path)); |
||||
|
||||
} |
||||
|
||||
// Match *.py and contbuild config files |
||||
if (preg_match('/(\.(py|tw|smcprops)|^contbuild\/configs\/[^\/]*)$/', |
||||
$path)) { |
||||
$space_count = 4; |
||||
$real_path = $this->getFilePathOnDisk($path); |
||||
$dir = dirname($real_path); |
||||
do { |
||||
if (file_exists($dir.'/.python2space')) { |
||||
$space_count = 2; |
||||
break; |
||||
} |
||||
$dir = dirname($dir); |
||||
} while ($dir != '/' && $dir != '.'); |
||||
|
||||
if ($space_count == 4) { |
||||
$cur_path_linter = $python_linter; |
||||
} else { |
||||
$cur_path_linter = $python_2space_linter; |
||||
} |
||||
$cur_path_linter->addPath($path); |
||||
$cur_path_linter->addData($path, $this->loadData($path)); |
||||
|
||||
if (preg_match('/\.tw$/', $path)) { |
||||
$cur_path_linter->setCustomSeverityMap(array( |
||||
'E251' => ArcanistLintSeverity::SEVERITY_DISABLED, |
||||
)); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
$name_linter = new ArcanistFilenameLinter(); |
||||
$linters[] = $name_linter; |
||||
foreach ($paths as $path) { |
||||
$name_linter->addPath($path); |
||||
} |
||||
|
||||
return $linters; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue