From 2c4eb00a128cf900ddc964387545f773645448c7 Mon Sep 17 00:00:00 2001 From: adonohue Date: Thu, 19 Jan 2012 17:09:27 -0800 Subject: [PATCH] Add ArcanistConduitLinter, a linter that delegates through Conduit Summary: Julien built a really cool static analysis database of our codebase. One capability is that it can suggest typehints that are not in the code. The analysis to do this is very expensive, so it can't reasonably be run locally. But it can remain indexed on a server. The idea here is to provide a familiar interface to it through arc lint, via a generic Conduit service call. In our lint engine, this will probably be gated on --advice for performance. This will introduce a slight awkwardness in that running with --advice can add new non-advice lint if the server chooses, but this isn't likely to cause a practical problem. Test Plan: Construct a fake Conduit lint endpoint, attach this linter to it, and see bogus lint appear with --advice. Reviewers: epriestley Reviewed By: epriestley CC: aran Differential Revision: https://secure.phabricator.com/D1462 --- src/__phutil_library_map__.php | 2 + .../linter/conduit/ArcanistConduitLinter.php | 110 ++++++++++++++++++ src/lint/linter/conduit/__init__.php | 17 +++ 3 files changed, 129 insertions(+) create mode 100644 src/lint/linter/conduit/ArcanistConduitLinter.php create mode 100644 src/lint/linter/conduit/__init__.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2279b6cf..72890ccd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -21,6 +21,7 @@ phutil_register_library_map(array( 'ArcanistChooseInvalidRevisionException' => 'exception', 'ArcanistChooseNoRevisionsException' => 'exception', 'ArcanistCommitWorkflow' => 'workflow/commit', + 'ArcanistConduitLinter' => 'lint/linter/conduit', 'ArcanistConfiguration' => 'configuration', 'ArcanistCoverWorkflow' => 'workflow/cover', 'ArcanistDiffChange' => 'parser/diff/change', @@ -119,6 +120,7 @@ phutil_register_library_map(array( 'ArcanistBundleTestCase' => 'ArcanistPhutilTestCase', 'ArcanistCallConduitWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistCommitWorkflow' => 'ArcanistBaseWorkflow', + 'ArcanistConduitLinter' => 'ArcanistLinter', 'ArcanistCoverWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistDiffParserTestCase' => 'ArcanistPhutilTestCase', 'ArcanistDiffUtilsTestCase' => 'ArcanistPhutilTestCase', diff --git a/src/lint/linter/conduit/ArcanistConduitLinter.php b/src/lint/linter/conduit/ArcanistConduitLinter.php new file mode 100644 index 00000000..97d1eaf2 --- /dev/null +++ b/src/lint/linter/conduit/ArcanistConduitLinter.php @@ -0,0 +1,110 @@ + must match passed in path. + * 'line' + * 'char' + * 'code' + * 'severity' => Must match a constant in ArcanistLintSeverity. + * 'name' + * 'description' + * 'original' & 'replacement' => optional patch information + * + * This class is intended for customization via instantiation, not via + * subclassing. + */ +class ArcanistConduitLinter extends ArcanistLinter { + const CONDUIT_METHOD = 'lint.getalllint'; + + private $conduitURI; + private $linterName; + private $lintByPath; // array(/pa/th/ => ), valid after willLintPaths(). + + public function __construct($conduit_uri, $linter_name) { + $this->conduitURI = $conduit_uri; + $this->linterName = $linter_name; + } + + public function willLintPaths(array $paths) { + // Load all file path data into $this->data. + array_map(array($this, 'getData'), $paths); + + $conduit = new ConduitClient($this->conduitURI); + + $this->lintByPath = $conduit->callMethodSynchronous( + self::CONDUIT_METHOD, + array( + 'file_contents' => $this->data, + ) + ); + } + + public function lintPath($path) { + $lint_for_path = idx($this->lintByPath, $path); + if (!$lint_for_path) { + return; + } + + foreach ($lint_for_path as $lint) { + $this->addLintMessage(ArcanistLintMessage::newFromDictionary($lint)); + } + } + + public function getLinterName() { + return $this->linterName; + } + + public function getLintSeverityMap() { + // The rationale here is that this class will only be used for custom + // linting in installations. No two server endpoints will be the same across + // different instantiations. Therefore, the server can handle all severity + // customization directly. + throw new ArcanistUsageException( + 'ArcanistConduitLinter does not support client-side severity '. + 'customization.' + ); + } + + public function getLintNameMap() { + // See getLintSeverityMap for rationale. + throw new ArcanistUsageException( + 'ArcanistConduitLinter does not support a name map.' + ); + } +} diff --git a/src/lint/linter/conduit/__init__.php b/src/lint/linter/conduit/__init__.php new file mode 100644 index 00000000..6c491881 --- /dev/null +++ b/src/lint/linter/conduit/__init__.php @@ -0,0 +1,17 @@ +